#include "ltypes.h"
//ltype value(name, lociList, all_effects);
ltypes::ltypes(string myId, vector< vector<double> > myAllEff, vector<unsigned int> myLoci, vector<int> ploidy, int myPow)
{
    // 1 - Affectations
    id = myId;
    allEff = myAllEff;
    locList = myLoci;
    powE = myPow;

    //cout << "LOCL CREATION:" << id << ",allEff00:" << allEff[0][0] << ", size:" << myLoci.size() << ", [0]:" << myLoci[0] << endl;

    // 2 - Order locList, mostly for clarity
    sort(locList.begin(), locList.end());


    //3 - Creation of locus index (allow going from locus number/id to genome position)
    // == starting position of each locus on the genome
    //Already exists in species but we recreate it here for simplicity
    // Discarded at the end of the function
    vector<int> locIndex;
    int sum = 0;
    for(unsigned int i = 0; i < ploidy.size(); i++)
    {
        locIndex.push_back(sum);
        sum += ploidy[i];
    }


    // 4 - Make a index to get the position on genome of each copy of a locus
    locus_position.clear();
    //Iteration on different locus of the ltype
    for(unsigned int loc : locList)
    {
        locus_position.push_back(vector<unsigned int>());
        //Iteration from 0 to ploidy of the given locus
        for(unsigned int j = 0; j < ploidy[loc]; j++)
        {
            locus_position.back().push_back(locIndex[loc] + j);
        }
    }
}


ltypes::~ltypes()
{
    //dtor
}




//Add the environmental effect on the raw sum to get additive value of a type
//Same potential problem with dominance and epistasy?
//Inline function?
double ltypes::calc_add_value(individual& myInd, double E)
{
    //cout << "myInd" << *myInd << endl;
    /* DEBUG */ if (std::isnan(raw_loc_sum(myInd) * pow(E, powE)))
    /* DEBUG */ {
    /* DEBUG */      cout << "calc_additive_value (ltype): nan" << endl;
    /* DEBUG */      cout << raw_loc_sum(myInd) << " " << pow(E, powE) << endl;
    /* DEBUG */      exit(0);
    /* DEBUG */ }
    return raw_loc_sum(myInd) * pow(E, powE);
}


double ltypes::raw_loc_sum_one_locus(individual& myInd, unsigned int rel_pos_locus)//unsigned int abs_pos_locus,
{
    double sum = 0.0;
    //cout << "diving into rlsol with the brave locus " << locus << endl;
    if (rel_pos_locus >= locus_position.size())
    {
        cout << "Discrepency in ltype computation: position " << rel_pos_locus << " vs total size " << locus_position.size() << endl;
        cout << "raw_loc_sum_one_locus will not have a valid value" << endl;
        exit(0);
    }
    else
    {
        for(unsigned int locPos : locus_position[rel_pos_locus]) //locPos is a position on the genome
        {
            //The locus is : locList[i], The allele is : myInd.gen_val(locPos)
            //cout << "RAWLOCSUM:locPos:" << locPos << ",myInd.gen_val(locPos):" << myInd.gen_val(locPos) << endl;
            //cout << "lp" << locPos << endl;
            //cout << "gv" << myInd.gen_val(locPos) << endl;
            sum += allEff[rel_pos_locus][myInd.gen_val(locPos)];
        }
    }
    return sum;
}

bool ltypes::has_locus(unsigned int locus)
{
    bool has_loc = false;
    for (auto l:locList)
    {
        if (l == locus)
        {
            has_loc = true;
        }
    }
    //cout << "has locus ? " << has_loc << endl;
    return has_loc;
}

double ltypes::calc_add_value_one_locus(individual& myInd, double E, unsigned int rel_pos_locus)
{
    //cout << myInd. << endl;
    /*cout << rel_pos_locus << " ";
     cout << E << " ";
     cout << powE << " || ";*/
    return raw_loc_sum_one_locus(myInd, rel_pos_locus) * pow(E, powE);
}


//Sum allelic effects of each position of interest in the genome
//Probably the fastest way to do it
//Needs another funcion of dominance and epistasy
double ltypes::raw_loc_sum(individual& myInd)
{
    double sum = 0.0;
    //Iterate on the number of locus
    for(unsigned int i = 0; i < locList.size(); i++)
    {
        //cout << "raw loc sum " << i << endl;
        sum += raw_loc_sum_one_locus(myInd, i);
    } 
    
    return sum;
}

unsigned int ltypes::get_rel_locus_pos(unsigned int abs_locus_pos)
{
    unsigned int current_rel_pos = 0;
    for (unsigned int current_l : locList)
    {
        if (current_l == abs_locus_pos)
        {
            return current_rel_pos;
        }
        else
        {
            current_rel_pos++;
        }
    }
    cout << "BUG:Rel locus pos not found" << endl;
    return 0;
}
