#include "../include/outputs.h"

//TODO :
// Add possibility to fully configure what to print :
// Which species, which cells, which timestep => all cobinaisons

bool printYoung = true;

void output_time(vector<int> times, string oDir)
{
    string filename = oDir + "ticks.csv";

    //Open file
    ofstream myfile (filename);
    if (!myfile.is_open())
    {
        cout << "Unable to open file";
        return;
    }
    //Writes a line per tick
    for(int i=0;i<times.size();i++) myfile << i << " " << times[i] << endl;
    myfile << endl;
    return;
}

void output_ploidy(vector<species>& vSpe, string oDir)
{
    //Make file name
    string filename = oDir + "genotypes/ploidy.csv";

    //Open file
    ofstream myfile (filename);
    if (!myfile.is_open())
    {
        cout << "Unable to open file";
        return;
    }
    //Writes a line per specie
    for(auto pSpe : vSpe)
    {
        myfile << pSpe.get_name();
        vector<int>& ploidy = pSpe.get_ploidy();
        for(auto i : ploidy) myfile << " " << i;
        myfile << endl;
    }
    return;
}



void out_gen_multi(vector<species*>& vSpe, landscape &land, mClock& cl, string oDir)
{
    for(auto pSpe : vSpe)
    {
        output_genetic(land, pSpe, cl, oDir);
    }
}

//File name : genes_spename_time.csv
//Format : pop ind loc1 loc2 loc3....
void output_genetic(landscape &land, species* pSpe, mClock& cl, string oDir)
{
    //Make file name
    ostringstream oss;
    oss << oDir + "genotypes/genes_" << pSpe->get_name() << "_" << cl.get_step() << ".csv";
    string filename = oss.str();

    //Open file
    ofstream myfile (filename);
    if (!myfile.is_open())
    {
        cout << "Unable to open file";
        return;
    }

    cell* pCell;
    population* pPop;
    individual* pInd;
    vector<indId> ids;


    //Main loop on cells
    //cout << "loop on cells" << endl;
    for(unsigned int iCell = 0; iCell < land.nCells(); iCell++)
    {
        pCell = land.pCell(iCell);
        pPop = pCell->get_pop(pSpe);
        if (pPop->get_age() > pSpe->getAgeEnds()[0]-1 || printYoung)
        {
            ids = pPop->get_ids();
            //cout << "DEBUG: Output genet N° " << iCell << endl;
            //for(unsigned int iInd = 0; iInd < pPop->get_nInd(); iInd++) MUTED
            //cout << "loop on id from cell " << iCell << endl;
            for(auto id: ids)
            {

        	    //cout << "id " << id << endl;
                //cout << "DEBUG: Output genet N° " << iCell << " " << iInd << endl;
                pInd = pPop->get_pInd(id);
                myfile << iCell << " " << pInd->id;

                for(unsigned int iGen = 0; iGen < pInd->gen_size(); iGen++)
                {
                    //cout << "DEBUG: Output genet N° " << iCell << " " << iInd << " " << iGen << endl;
                    myfile << " " << pInd->gen_val(iGen);
                }
                myfile << endl;
            }
        }
    }

    myfile.close();
    return;
}


void output_addByLocus(landscape &land, species* pSpe, mClock& cl, trait* oTrait, string oDir)
{
    //Make file name
    ostringstream oss;
    oss << oDir + "quantitative/" << pSpe->get_name() << "_" << cl.get_step() << "_" << oTrait->get_name() + "-add-bylocus.csv";
    string filename = oss.str();

    //Open file
    ofstream myfile (filename);
    if (!myfile.is_open())
    {
        cout << "Unable to open file";
        return;
    }

    cell* pCell;
    population* pPop;
    individual* pInd;
    vector<indId> ids;

    //Iterate on the LOCI UNDER SELECTION FOR THE GIVEN TRAIT
    vector<unsigned int> loci_in_trait = oTrait->get_loci();
    vector<vector<unsigned int>> loci_by_lt = oTrait->get_loci_by_lt();
    unsigned int n_loc_in_trait = loci_in_trait.size();

    myfile << "# loci considered (the first locus on the genome is the locus 1): ";
    for (auto l:loci_by_lt)
    {
      for (auto m:l)
      {
         myfile << m+1 << " ";
      }
      myfile << ";";

    }
    myfile << endl;

    //Main loop on cells
    //cout << "loop on cells" << endl;
    for(unsigned int iCell = 0; iCell < land.nCells(); iCell++)
    {
        pCell = land.pCell(iCell);
        pPop = pCell->get_pop(pSpe);
        if (pPop->get_age() > pSpe->getAgeEnds()[0]-1 || printYoung)
        {
            ids = pPop->get_ids();
            for(auto id: ids)
            {
                pInd = pPop->get_pInd(id);
                myfile << iCell << " " << pInd->id;

                //for(unsigned int i = 0; i < pSpe->get_nLoci(); i++)
                for(unsigned int pos_loc = 0; pos_loc < n_loc_in_trait;pos_loc++)
                {
                    unsigned int loc = loci_in_trait[pos_loc];
                    //cout << "OUT:" << pos_loc << "/" << n_loc_in_trait << "(" << loc << ")" << endl;
                    double sumPloidy = 0.0;
                    //for(ltypes& t : oTrait->)
                    for (int nLtype = 0; nLtype < oTrait->get_nLtype(); nLtype++)
                    {
                        ltypes* t = oTrait->get_ltype(nLtype);
                        if (t->has_locus(loc))
                        {
                            //cout << "got ltypes" << endl;
                            //cout << "pind" << pInd << endl;
                            //cout << "oTrait->get_E(pos_loc)" << oTrait->get_E(pos_loc) << endl;
                            //cout << "pos_loc" << pos_loc << endl;
                            unsigned int rel_pos_locus = t->get_rel_locus_pos(loc);
                            sumPloidy += t->calc_add_value_one_locus(*pInd, oTrait->get_E(pos_loc), rel_pos_locus);
                        }// else { cout << "not has loc" << endl;}
                    }
                    //cout << "SUM LOC " << loc  << "/" << loci_in_trait.size() << ":" << sumPloidy << endl;
                    myfile << " " << sumPloidy;
                }
                myfile << endl;
            }
        }
    }

    myfile.close();
    return;
}

void output_addByLtype(landscape &land, species* pSpe, mClock& cl, trait* oTrait, string oDir)
{
    for (int nLtype = 0; nLtype < oTrait->get_nLtype(); nLtype++)
    {
        ltypes* t = oTrait->get_ltype(nLtype);
        //Make file name
        ostringstream oss;
        oss << oDir + "quantitative/" << pSpe->get_name() << "_" << cl.get_step() << "_" << oTrait->get_name() + "-add-"+t->get_id()+".csv";
        string filename = oss.str();

        //Open file
        ofstream myfile (filename);
        if (!myfile.is_open())
        {
            cout << "Unable to open file";
            return;
        }

        cell* pCell;
        population* pPop;
        individual* pInd;
        vector<indId> ids;

        //Iterate on the LOCI UNDER SELECTION FOR THE GIVEN TRAIT
        vector<unsigned int> loci_in_trait = oTrait->get_loci();
        unsigned int n_loc_in_trait = loci_in_trait.size();

        /*myfile << "# loci considered (the first locus on the genome is the locus 1): ";
        for (auto l:loci_in_trait)
        {
            myfile << l+1 << " ";
        }*/
        myfile << endl;

        //Main loop on cells
        //cout << "loop on cells" << endl;
        for(unsigned int iCell = 0; iCell < land.nCells(); iCell++)
        {
            pCell = land.pCell(iCell);
            pPop = pCell->get_pop(pSpe);
            if (pPop->get_age() > pSpe->getAgeEnds()[0]-1 || printYoung)
            {
                ids = pPop->get_ids();
                for(auto id: ids)
                {
                    pInd = pPop->get_pInd(id);
                    myfile << iCell << " " << pInd->id;

                    double sumPloidy = 0.0;
                    //for(unsigned int i = 0; i < pSpe->get_nLoci(); i++)
                    for(unsigned int pos_loc = 0; pos_loc < n_loc_in_trait;pos_loc++)
                    {
                        unsigned int loc = loci_in_trait[pos_loc];

                        if (t->has_locus(loc))
                        {
                            //cout << "OUT:" << pos_loc << "/" << n_loc_in_trait << "(" << loc << ")" << endl;
                            unsigned int rel_pos_locus = t->get_rel_locus_pos(loc);
                            //sumPloidy += t->calc_add_value_one_locus(*pInd, oTrait->get_E(pos_loc), rel_pos_locus);
                            sumPloidy += t->raw_loc_sum_one_locus(*pInd, rel_pos_locus);
                        }
                    }
                    myfile << " " << sumPloidy << endl; //have all ltypes on same file ? not necessary
                }
            }
        }
        myfile.close();// else { cout << "not has loc" << endl;}
    }
    return;
}

void output_geneflow(landscape &land, species* pSpe, mClock& cl, string oDir, int nCellRef)
{
    if (nCellRef >= land.max_size())
    {
        nCellRef = land.max_size() - 1;
    }

    cell* pCellRef = land.pCell(nCellRef);
    population* pPop = pCellRef->get_pop(pSpe);

    //Make file name
    ostringstream ossM;
    ossM << oDir + "quantitative/" << pSpe->get_name() << "_" << cl.get_step() << "_geneflowP.csv";
    string filenameM = ossM.str();

    ostringstream ossF;
    ossF << oDir + "quantitative/" << pSpe->get_name() << "_" << cl.get_step() << "_geneflowS.csv";
    string filenameF = ossF.str();

    //Open file
    ofstream myfileM (filenameM);
    if (!myfileM.is_open())
    {
        cout << "Unable to open fileM";
        return;
    }

    ofstream myfileF (filenameF);
    if (!myfileF.is_open())
    {
        cout << "Unable to open fileF";
        return;
    }

    // take one pop an analyse the gene flux (here pop number 23)
    for(unsigned int iCell = 0; iCell < pPop->get_nb_father_by_pop().size(); iCell++)//should  use ->size() ?
    {
      	if (iCell % land.max_longi() == 0)
      	{
                  myfileM << endl;
                  myfileF << endl;
      	}
        myfileM << " " << pPop->get_nb_father_by_pop()[iCell];
        myfileF << " " << pPop->get_nb_mother_by_pop()[iCell];
    }

    myfileM.close();
    myfileF.close();
    return;
}


void output_value(landscape &land, species* pSpe, mClock& cl, string valueName, string oDir)
{
    //Make file name
    ostringstream oss;
    oss << oDir + "quantitative/" << pSpe->get_name() << "_" << cl.get_step() << "_" << valueName << ".csv";
    string filename = oss.str();

    //Open file
    ofstream myfile (filename);
    if (!myfile.is_open())
    {
        cout << "Unable to open file";
        return;
    }

    cell* pCell;
    population* pPop;
    individual_index * pII;

    //Main loop on cells
    vector<int> pops = land.getPopulatedPops(pSpe);
    for(unsigned int i = 0; i < pops.size(); i++)
    {
        unsigned int iCell = pops[i];
        pCell = land.pCell(iCell);
        pPop = pCell->get_pop(pSpe);
        if (pPop->get_age() > pSpe->getAgeEnds()[0]-1 || printYoung)
        {
            pII = pPop->get_index(valueName);

            for(unsigned int i = 0; i < pII->get_size(); i++)
            {
                myfile << iCell << " "
                       << pII->get_indId(i) << " "
                       << pII->get_value(i) << endl;
            }
        }
    }

    myfile.close();
    return;
}

/*
alternate way
take individuals in arbitrary order:
then use reverse index of each individual_index to get the right value
*/
