#ifndef INDIVIDUAL_INDEX_H
#define INDIVIDUAL_INDEX_H

#include <iostream>
#include <exception>
#include <vector>
#include <valarray>
#include <string>
#include <algorithm>    // std::sort

#include "individual.h"

//class individual;
// TODO: add cum sum option?

using indId = unsigned int;
using indref = vector<pair<double, indId>>;
using revindref = vector<pair<indId, unsigned int>>;


using namespace std;

class individual_index
{
    public:
        individual_index(const string& m_id, 
                         const vector<double>& values, const vector<indId>& indexInd,
                         bool sort_values, bool rev_acess = false); // OK
        ~individual_index();

        // Get id of individuals in the specified range
        bool get_ind_range(double start, double end, vector<indId> &retValues); //OK
        // Get value of a specific individual from its id
        double get_val(indId pInd); //Ok
        // Retrive all values from the index
        vector<double> get_values(); //Ok
        vector<indId> get_inds();
        // fist element of storage that does not compares inferior to value
        indref::iterator get_lower_bound(double value); //OK
        // first element in storage which compares greater than value.
        indref::iterator get_upper_bound(double value); //OK

        // Header implemented functions:
        inline unsigned int get_size();
        inline pair<double, indId> get_pair(int index);
        inline indId get_indId(int index);
        inline double get_value(int index);
        inline double get_min();
        inline double get_max();
        inline indref::iterator get_begin(){ return storage.begin(); }
        inline indref::iterator get_end(){ return storage.end(); }



    protected:
    private:
        string id; // Id of the typeof value stored
        indref storage; //Storage of values to indId, vector<pair<double, indId>>
        revindref revIndex; // indId to values

};

/*
 * Simple accessors functions:
 */

inline unsigned int individual_index::get_size()
{
    return storage.size();
}

inline pair<double, indId> individual_index::get_pair(int index)
{
    return storage[index];
}

inline indId individual_index::get_indId(int index)
{
    return storage[index].second;
}

inline double individual_index::get_value(int index)
{
    return storage[index].first;
}

// TODO: add check if sorted (and a boolean "sorted" field)
inline double individual_index::get_min()
{
    double minInd;
    try
    {
         minInd = storage.front().first;
    }
    catch (exception& e)
    {
        cout << "Storage check failed." << e.what() << endl;
        minInd = 0;
    }
    return minInd;
}

// TODO: add check if sorted (and a boolean "sorted" field)
inline double individual_index::get_max()
{
    return storage.back().first;
}


#endif // INDIVIDUAL_INDEX_H
