using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MarketData.Numerical;
using MarketData.DataAccess;
using MarketData.MarketDataModel;
using MarketData.Utils;

namespace MarketData.Generator.TermStructure
{
  public class TermStructureInterpolatorByDate : Dictionary<DateTime,TermStructureInterpolator>
  {
  }
  public class TermStructureInterpolator
  {
    private Dictionary<int, double> splineRates = new Dictionary<int, double>();
    private CurveData curveData = null;
    private DateTime tradeDate;

    public TermStructureInterpolator(DateTime tradeDate)
    {
      this.tradeDate=tradeDate;
      SetCurveData();
    }
    public DateTime TradeDate { get; private set; }
    public CurveData CurveData
    {
      get
      {
        return curveData;
      }
    }
    public Dictionary<int, double> SplineRates
    {
      get
      {
        return splineRates;
      }
    }
    public double GetRate(int days)
    {
      int index = 0;
      if (null == curveData) return double.NaN;
      for (; index < curveData.CurveTenors.Count;index++ )
      {
        Tenor tenor = curveData.CurveTenors[index];
        int tenorDays=Tenor.GetTenorDays(tenor.Item);
        if(tenorDays == days) return double.Parse(tenor.Value);
        if(tenorDays>days) break;
      }
      double differenceDays=days-Tenor.GetTenorDays(curveData.CurveTenors[index].Item);
      double dailyRate=(curveData.CurveTenors[index].ValueNum - curveData.CurveTenors[index-1].ValueNum) / (curveData.CurveTenors[index].Days - curveData.CurveTenors[index-1].Days);
      double rate = curveData.CurveTenors[index].ValueNum + (differenceDays * dailyRate);
      return rate;
    }
    private void SetCurveData()
    {
      YieldCurveData yieldCurveData=YieldCurveDA.GetYieldCurve(tradeDate);
      if(null==yieldCurveData)return;
      curveData=new CurveData();
      Tenors tenors=new Tenors();
      curveData.CurveTenors=tenors;
      tenors.Add(new Tenor("1D",Utility.FormatNumber(yieldCurveData.Mo1,2)));
      tenors.Add(new Tenor("1M",Utility.FormatNumber(yieldCurveData.Mo1,2)));
      tenors.Add(new Tenor("3M",Utility.FormatNumber(yieldCurveData.Mo3,2)));
      tenors.Add(new Tenor("6M",Utility.FormatNumber(yieldCurveData.Mo6,2)));
      tenors.Add(new Tenor("1Y",Utility.FormatNumber(yieldCurveData.Yr1,2)));
      tenors.Add(new Tenor("2Y",Utility.FormatNumber(yieldCurveData.Yr2,2)));
      tenors.Add(new Tenor("3Y",Utility.FormatNumber(yieldCurveData.Yr3,2)));
      tenors.Add(new Tenor("5Y",Utility.FormatNumber(yieldCurveData.Yr5,2)));
      tenors.Add(new Tenor("7Y",Utility.FormatNumber(yieldCurveData.Yr7,2)));
      tenors.Add(new Tenor("10Y",Utility.FormatNumber(yieldCurveData.Yr10,2)));
      tenors.Add(new Tenor("20Y",Utility.FormatNumber(yieldCurveData.Yr20,2)));
      tenors.Add(new Tenor("30Y",Utility.FormatNumber(yieldCurveData.Yr30,2)));

      List<Element> sourcePairs = new List<Element>();
      List<Element> destPairs = new List<Element>();

      sourcePairs.Add(new Element(0,double.Parse(curveData.GetTenorValue("1D"))));
      sourcePairs.Add(new Element(30,double.Parse(curveData.GetTenorValue("1M"))));
      sourcePairs.Add(new Element(90,double.Parse(curveData.GetTenorValue("3M"))));
      sourcePairs.Add(new Element(180,double.Parse(curveData.GetTenorValue("6M"))));
      sourcePairs.Add(new Element(360,double.Parse(curveData.GetTenorValue("1Y"))));
      sourcePairs.Add(new Element(720,double.Parse(curveData.GetTenorValue("2Y"))));
      sourcePairs.Add(new Element(1080,double.Parse(curveData.GetTenorValue("3Y"))));
      sourcePairs.Add(new Element(1800,double.Parse(curveData.GetTenorValue("5Y"))));
      sourcePairs.Add(new Element(2520,double.Parse(curveData.GetTenorValue("7Y"))));
      sourcePairs.Add(new Element(3600,double.Parse(curveData.GetTenorValue("10Y"))));
      sourcePairs.Add(new Element(7200,double.Parse(curveData.GetTenorValue("20Y"))));
      sourcePairs.Add(new Element(10800,double.Parse(curveData.GetTenorValue("30Y"))));

      for (int index = 0; index <= 10800; index++)destPairs.Add(new Element(index, 0));
      Element[] sourcePairsArray = sourcePairs.ToArray();
      Element[] destPairsArray = destPairs.ToArray();
      CatmullRom.PerformSpline(sourcePairsArray,destPairsArray);
      for (int index = 0; index < destPairsArray.Length; index++)
      {
        if (!splineRates.ContainsKey((int)destPairsArray[index].Column))
        {
          splineRates.Add((int)destPairsArray[index].Column, destPairsArray[index].Row);
        }
      }
    }
  }


// *************************************************************************************************************************************************************

  public class TermStructureRatesGenerator
  {
    private TermStructureInterpolatorByDate termStructureInterpolatorByDate = new TermStructureInterpolatorByDate();

    public TermStructureRatesGenerator()
    {
    }
    public void Add(DateTime tradeDate)
    {
      if (termStructureInterpolatorByDate.ContainsKey(tradeDate)) return;
      termStructureInterpolatorByDate.Add(tradeDate,new TermStructureInterpolator(tradeDate));
    }
    public CurveData GetTermStructureCurve(DateTime tradeDate)
    {
      if (null == termStructureInterpolatorByDate||!termStructureInterpolatorByDate.ContainsKey(tradeDate)) return null;
      TermStructureInterpolator termStructureInterpolator = termStructureInterpolatorByDate[tradeDate];
      return termStructureInterpolator.CurveData;
    }
    public double GetRate(DateTime tradeDate,int days)
    {
      if (!termStructureInterpolatorByDate.ContainsKey(tradeDate)) return double.NaN;
      TermStructureInterpolator termStructureInterpolator = termStructureInterpolatorByDate[tradeDate];
      return termStructureInterpolator.GetRate(days);
    }
  }
}
