#ifndef __POPULATION_H_
#define __POPULATION_H_

#include "Definitions.h"
#include "IprocessConvergedAllele.h"
#include "Random.h"
#include <functional>
#include <boost/dynamic_bitset.hpp>
#include <boost/multi_array.hpp>
#include <boost/noncopyable.hpp>

class Population : boost::noncopyable, public IprocessConvergedAllele {
    struct ConvergedAllele {
      struct Comparator : std::binary_function<const ConvergedAllele &, const ConvergedAllele &, bool> {
        bool operator()( const ConvergedAllele & lhs, const ConvergedAllele & rhs );
      };

      unsigned int locus;
      AlleleType allele;
      FloatType probability;
      ConvergedAllele( unsigned int locus, AlleleType allele, FloatType probability );
    private:
      ConvergedAllele();
    };

  private:
    typedef boost::multi_array<FloatType, 2> MatrixType;

    MatrixType *data;
    boost::dynamic_bitset<> convergedAlleles;

    AlleleType getRandomAllele( unsigned int locus, Random *random ) const;
    AlleleType getProportionateAllele( unsigned int locus, Random *random ) const ;
    const ConvergedAllele getConvergedAllele( unsigned int locus ) const;
    void adjustProbabilities( const AlleleType *chromosome, FloatType epsilon );

  public:
    Population();
    ~Population();
    void print() const;
    void selectIndividual( AlleleType *destination ) const;
    void rewardGenes( const AlleleType *chromosome );
    void penalizeGenes( const AlleleType *chromosome );
    void updateConvergedAlleles();
    void processConvergedAllele( unsigned int locus, AlleleType allele );
    unsigned int prepareAllelesMessage( MessagePayloadType *buffer );
};

#endif /* __POPULATION_H_ */
