#ifndef INDIVIDUAL_H
#define INDIVIDUAL_H

#include <iostream>
#include <string>
#include <vector>

#include "specie.h"
#include "genome.h"

class mClock;
class species;

using indId = unsigned int;

/*#include "../include/individual.h"
#include "../include/population.h"
#include "../include/cell.h"


SEX SPECIE AGE AGE_CLASS FITNESS TRAITS
*/


// TODO: smart pointers uniq_ptr everywhere (umap)
// Individual must be refered to from it id



class individual
{
    public:
        individual(individual& mother, individual& father, mClock &m_clock, species* spe);
        individual(int p_age, int clock, vector<int> p_genome);

        ~individual();


        void print_all();
        unsigned int gen_val(int location);
        unsigned int gen_size();
        //individual(int * g_seq, species * h_species, int m_age);
        //individual(individual pere, individual mere);
        //void gprint();
        //species * get_species();
        //genome * get_genome();
        //double calc_trait(int trait_number);
        int get_birth();
        valarray<int> get_subGenome(valarray<bool> * mask);
        vector<int> get_genome();
        valarray<int> get_genome_va();
        vector<int>& get_genome_ref() { return genome; }


        int age_update(mClock &m_clock, species * pSpe);
        void mutate(species * pSpecie);
        void mutate_pos(int nAll, int pos);

        indId get_id();

        //TEST FUNCTION
        int check_integrity(species * pSpe);


        static indId counter_created;
        static indId counter_alive;
        const indId id;

        int get_age();
        double get_height();
        double get_handicap();
        void set_height(double h);
        void set_handicap(double h);

    protected:

    private:
        double age; //DEPRECATED?
        double height;
        double handicap;
        unsigned int birth_date;
        vector<int> genome;
};


inline unsigned int individual::gen_val(int location)
{
    return genome.at(location);
}

inline unsigned int individual::gen_size()
{
    return genome.size();
}


inline int individual::get_age()
{
    return age;
}

inline double individual::get_height()
{
    return height;
}

inline double individual::get_handicap()
{
    return handicap;
}

inline void individual::set_height(double h)
{
    height = h;
}

inline void individual::set_handicap(double h)
{
    handicap = h;
}

inline int individual::get_birth()
{
    return birth_date;
}

inline indId individual::get_id()
{
    return id;
}


#endif // INDIVIDUAL_H
