#include "individual_index.h"





/* Regular way to creat an individual index
 * Input: values type, vector of values, vector of indId + options
 * sort_values: do we sort values? (if not disallows certains order based methods (TODO !))
 * (also check if relly needed)
 * rev_access: creates an index that allows finding value fro indId in constant time
 */
individual_index::individual_index(const string& m_id, const vector<double>& values,
                                   const vector<indId>& indexInd, bool sort_values,
                                   bool rev_access)
{
    //Basic size check
    if(values.size() != indexInd.size())
        fail("individual_index constructor: n individuals != n values");

    //Declares the right size (better for speed)
    storage.reserve(values.size());

    id = m_id;

    // Insert values
    for(unsigned int i = 0; i < values.size(); i++)
    {
        storage.push_back(pair<double, indId>(values[i], indexInd[i]));
    }

    //Sort pairs using first elenent (lambda function)
    if(sort_values)
    {
        sort(storage.begin(), storage.end(),
            [](const std::pair<double, indId> &left, const std::pair<double, indId> &right)
                { return left.first < right.first;} );
    }

    // Creation of the reversed index,
    if(rev_access)
    {
        revIndex.reserve(storage.size());
        for(unsigned int i = 0; i < storage.size(); i++)
        {
            revIndex.push_back(pair<indId, unsigned int>(storage[i].second, i));
        }
        // To find id in log, ids are sorted
        sort(revIndex.begin(), revIndex.end(),
            [](const std::pair<indId, int> &left, const std::pair<indId, int> &right)
            { return left.first < right.first; } );
    }
}





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





/* Gets all individuals in a given range of values
 * id of the individuals are returned via retValues vector.
 */
bool individual_index::get_ind_range(double start, double end,
                                     vector<indId> &retValues)
{
    retValues.clear();
    // First we get the range
    auto iterStart = get_lower_bound(start);
    auto iterEnd = get_upper_bound(end);

    // Get Number of individuals, to reserve or abort
    int nInd = iterEnd - iterStart;
    if (nInd <= 0) return false;
    else retValues.reserve(nInd);

    // Fill vector
    for(auto it = iterStart; it != iterEnd; ++it)
    {
       retValues.push_back((*it).second);
    }
    return true;
}





/* Gets the value of the individual from its id
 * Performs a binary search on revIndex sorted indId list
 * Cost log(nIndividuals)
 */
double individual_index::get_val(indId id)
{
    // Safety check 1
    if(revIndex.size() == 0)
        cout << "Error, reversed index not implemeted for this type of value";

    // Get the interator from a binary search on sorted indIds
    revindref::iterator temp = lower_bound(revIndex.begin(), revIndex.end(), id,
        [](const pair<indId, unsigned int> &left, indId right)
            { return left.first < right; } ); //the fist element that does not compares inferior to value

    // Safety check 2
    if(temp == revIndex.end() || temp->first != id)
        fail("Individual_index::get_val: individual does not exist.");

    return storage[temp->second].first;
}





/* Returns a vector containing all th values of the index
 * Keeps the order
 */
vector<double> individual_index::get_values()
{
    vector<double> rv;
    rv.reserve(storage.size());
    for(unsigned int i = 0; i < storage.size(); i++)
    {
        rv.push_back(storage[i].first);
    }
    return rv;
}

vector<indId> individual_index::get_inds()
{
    vector<indId> rv;
    rv.reserve(storage.size());
    for(unsigned int i = 0; i < storage.size(); i++)
    {
        rv.push_back(storage[i].second);
    }
    return rv;
}


/* Returns iterator to the fist element of storage which does not compares
 * inferior to value.
 */
indref::iterator individual_index::get_lower_bound(double value)
{
    return lower_bound (storage.begin(), storage.end(), value,
        [](const pair<double, indId> &left, const double right)
        { return left.first < right; } ); //the fist element that does not compares inferior to value
}





/* WARNING ! The return value might be container::end()
 * Calling function MUST check for this.
 * Returns an iterator pointing to the first element in storage
 * which compares greater than value.
 */
indref::iterator individual_index::get_upper_bound(double value)
{
    return upper_bound (storage.begin(), storage.end(), value,
        [](const double left, const pair<double, indId> &right)
        { return left < right.first; } );
}
