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

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

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);
        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);
        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);
            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();

    ostringstream ossT;
    ossT << oDir + "quantitative/" << pSpe->get_name() << "_" << cl.get_step() << "_geneflow_traits.csv";
    string filenameT = ossT.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;
    }

    ofstream myfileT (filenameT);
    if (!myfileT.is_open())
    {
        cout << "Unable to open fileT";
        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];
    }

    vector<string> allMigrations = pSpe->get_origins(false, nCellRef, land.max_longi());

    for (int i=0;i<allMigrations.size();i++)
    {
        myfileT << allMigrations[i] << endl;
    }

    myfileM.close();
    myfileF.close();
    myfileT.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);
        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
*/
