// Copyright (C) 2021 EDF
// All Rights Reserved
// This code is published under the GNU Lesser General Public License (GNU LGPL)
#include <memory>
#include <vector>
#include <Eigen/Dense>
#include <StOpt/core/utils/constant.h>
#include <StOpt/core/grids/RegularSpaceGrid.h>
#include "Tunnel.h"

using namespace std;
using namespace Eigen;
using namespace StOpt;

Tunnel::Tunnel(const vector< std::array<double, 2> > &p_tunnel,  const double   &p_disVolume): m_tunnel(p_tunnel), m_disVolume(p_disVolume), m_fromDateToData(p_tunnel.size())
{
    for (size_t i = 0; i < m_fromDateToData.size(); ++i)
        m_fromDateToData[i] = i;
}
Tunnel::  Tunnel(const vector<int>    &p_dateToPos, const vector< std::array<double, 2> > &p_tunnel,  const double   &p_disVolume):
    m_tunnel(p_tunnel), m_disVolume(p_disVolume), m_fromDateToData(p_dateToPos[p_dateToPos.size() - 1])
{
    int ipos = 0;
    for (size_t i = 0; i < m_fromDateToData.size(); ++i)
    {
        if (i == static_cast<size_t>(p_dateToPos[ipos]))
            ipos += 1;
        m_fromDateToData[i] =  ipos;
    }
}

shared_ptr<FullGrid> Tunnel::getGrid(const int &p_idate) const
{
    // position in tunnel :
    int iposTunnel  = m_fromDateToData[p_idate];
    // correct grid if necessary to rely get a grid
    double minVolume =  m_tunnel[iposTunnel][0];
    double maxVolume = max(minVolume + tiny, m_tunnel[iposTunnel][1]);
    // number of step
    int nStepVol = max(static_cast<int>((maxVolume - minVolume) / m_disVolume), 1);
    // correct dis volume
    double disVolumeLoc = (maxVolume - minVolume) / nStepVol;
    ArrayXd lowValue(1);
    lowValue(0) = minVolume;
    ArrayXd stepGrid(1);
    stepGrid(0) = disVolumeLoc;
    ArrayXi nbStepGrid(1);
    nbStepGrid(0) = nStepVol;
    return make_shared<RegularSpaceGrid>(lowValue, stepGrid, nbStepGrid);
}

std::array<double, 2>  Tunnel::getMinMaxAtDate(const int &p_idate) const
{
    // position in tunnel :
    int iposTunnel  = m_fromDateToData[p_idate];
    // correct grid if necessary to rely get a grid
    double minVolume =  m_tunnel[iposTunnel][0];
    double maxVolume = max(minVolume, m_tunnel[iposTunnel][1]);
    return std::array<double, 2> {{minVolume, maxVolume}};
}

void Tunnel::print(const int &p_idate) const
{
    // position in tunnel :
    int iposTunnel  = m_fromDateToData[p_idate];
    // correct grid if necessary to rely get a grid
    double minVolume =  m_tunnel[iposTunnel][0];
    double maxVolume = max(minVolume + tiny, m_tunnel[iposTunnel][1]);
    // number of step
    int nStepVol = max(static_cast<int>((maxVolume - minVolume) / m_disVolume), 1);
    // correct dis volume
    double disVolumeLoc = (maxVolume - minVolume) / nStepVol;
    cout << "Low value " <<  minVolume << " Step Discretization " << disVolumeLoc << " nbStep " << nStepVol << endl ;
}
