#include "fluxMat.h"


fluxMat::fluxMat()
{
}

fluxMat::fluxMat(vector<vector<double>> m_matrix, int m_time)
{
    matrix = m_matrix;
    time = m_time;
}

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

/* Returns a copy of line [receiver]
 * Simple boudaries check
 */
vector<double> fluxMat::get_donnors(int receiver)
{
    if(receiver < 0 || receiver >= matrix.size())
    {
        cout << "get_donnors: out of bounaries : "
             << receiver  << " / " << matrix.size() << endl;
        exit(0);
    }

    return vector<double>(matrix[receiver]);
}



/* Draws a pop id from the flux matrix ponderated by a weight vector
 * Cost: This function creates a copy of one line of flux matrix
 * Drawing consists of:  weighting, cumSum, norm and bin search vs random unif
 * Failure: returns -1 if sum(flux_matrix x weights) == 0
 * TODO : Potential optimization to avoid copy of the vector:
 *        As weights are often calculated for each individual (in assortMating)
 *        Weights should be written over, and flux matrix only read by reference
 *        Thus reallocation of a new vector is spared
 * Note: Weights are already disposable when using from select_pop_assortMating
 */

int fluxMat::get_time()
{
   return time;
}

int fluxMat::draw(int receiver, vector<double> &weights, vector<int> ageClasses)
{
    // Copy of one ine of flux matrix
    vector<double> tempVect = get_donnors(receiver);
    if(tempVect.size() != weights.size())
    {
        fail("fluxMat::draw: Wrong size.");
    }
    //cout << "FLUXMAT for " << receiver << " : ";
    // Weighting of flux matrix & cumuative sum
    //tempVect[0] = tempVect[0] * weights[0]; //Fist step out of loop, can't add previous value in vect
    for(unsigned int i  = 0; i < tempVect.size(); i++) //Thus loop starts at 1
    {
        int consideredInRepro = 0;
        if (ageClasses[i] > 1) // if class is A or MA
        {
            consideredInRepro = 1;
        }

        // VERIF: CHECK IF LOCAL POP IS MUTED
        if (i == receiver && consideredInRepro == 0)
        {
            cout << "RECEIVER won't receive from self... BUG" << endl;
        }

        tempVect[i] = tempVect[i] * weights[i] * consideredInRepro;
        if (i > 0)
        {
            tempVect[i] += tempVect[i-1];
        }
    }

    // Failure condition
    if(tempVect.back() == 0.0) return -1;

    // Divide by maximum (= last value)
    for(unsigned int i  = 0; i < tempVect.size(); i++)
    {
        tempVect[i] /= tempVect.back();
        //cout << tempVect[i] << " ";
    }
    //cout << endl;


    int lb = lower_bound(tempVect.begin(), tempVect.end(), Random()) - tempVect.begin();

    return(lb);
}
