using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using MarketData.Generator;
using MarketData.Utils;
using MarketData.Generator.MovingAverage;

namespace MarketData.MarketDataModel
{
  public class YieldCurve : List<YieldCurveData>
  {
    public enum CurveType{Mo1,Mo2,Mo3,Mo6,Yr1,Yr2,Yr3,Yr5,Yr7,Yr10,Yr20,Yr30}
    public YieldCurve()
    {
    }
    public YieldCurve(List<YieldCurveData> yieldCurveData)
    {
      if(null==yieldCurveData)return;
      for(int index=0;index<yieldCurveData.Count;index++)Add(yieldCurveData[index]);
    }
    public List<DateTime> GetDistinctDates()
    {
      Dictionary<DateTime, DateTime> uniqueDates = new Dictionary<DateTime, DateTime>();
      foreach (YieldCurveData yieldData in this)
      {
        if (!uniqueDates.ContainsKey(yieldData.Date)) uniqueDates.Add(yieldData.Date, yieldData.Date);
      }
      List<DateTime> uniqueDatesList = new List<DateTime>(uniqueDates.Values);
      uniqueDatesList.Sort();
      return uniqueDatesList;
    }
		public static CurveType CurveTypeFromString(String strCurveType)
		{
		  if(strCurveType.Equals("Mo1",StringComparison.InvariantCultureIgnoreCase))return CurveType.Mo1;
		  if(strCurveType.Equals("Mo2",StringComparison.InvariantCultureIgnoreCase))return CurveType.Mo2;
		  if(strCurveType.Equals("Mo3",StringComparison.InvariantCultureIgnoreCase))return CurveType.Mo3;
		  if(strCurveType.Equals("Mo6",StringComparison.InvariantCultureIgnoreCase))return CurveType.Mo6;
		  if(strCurveType.Equals("Yr1",StringComparison.InvariantCultureIgnoreCase))return CurveType.Yr1;
		  if(strCurveType.Equals("Yr2",StringComparison.InvariantCultureIgnoreCase))return CurveType.Yr2;
		  if(strCurveType.Equals("Yr3",StringComparison.InvariantCultureIgnoreCase))return CurveType.Yr3;
		  if(strCurveType.Equals("Yr5",StringComparison.InvariantCultureIgnoreCase))return CurveType.Yr5;
		  if(strCurveType.Equals("Yr7",StringComparison.InvariantCultureIgnoreCase))return CurveType.Yr7;
		  if(strCurveType.Equals("Yr10",StringComparison.InvariantCultureIgnoreCase))return CurveType.Yr10;
		  if(strCurveType.Equals("Yr20",StringComparison.InvariantCultureIgnoreCase))return CurveType.Yr20;
		  if(strCurveType.Equals("Yr30",StringComparison.InvariantCultureIgnoreCase))return CurveType.Yr30;
      throw new Exception(String.Format("'{0}' is not a known curve type",strCurveType));
		}
		public static String CurveTypeToString(CurveType curveType)
		{
		  switch(curveType)
			{
			  case CurveType.Mo1 :
				  return "Mo1";
				case CurveType.Mo2 :
				  return "Mo2";
				case CurveType.Mo3 :
				  return "Mo3";
				case CurveType.Mo6 :
				  return "Mo6";
				case CurveType.Yr1 :
				  return "Yr1";
				case CurveType.Yr2 :
				  return "Yr2";
				case CurveType.Yr3 :
				  return "Yr3";
				case CurveType.Yr10 :
				  return "Yr10";
				case CurveType.Yr20 :
				  return "Yr20";
        default :
				  throw new Exception(String.Format("Unknown curve type enumeration EnumValue:{0}",(int)curveType));
			}
		}



// Return the data for specified tenor.  The data is ordered with the earliest date in the lowest index   
    public double[] GetYieldCurveDataOrderByDateAscending(CurveType curveType)
    {
      double[] array=null;
        switch (curveType)
        {
          case CurveType.Mo1 :
            array=(from YieldCurveData yieldCurveData in this orderby yieldCurveData.Date ascending select yieldCurveData.Mo1).ToArray();
            break;
          case CurveType.Mo2 :
            array=(from YieldCurveData yieldCurveData in this orderby yieldCurveData.Date ascending select yieldCurveData.Mo2).ToArray();
            break;
          case CurveType.Mo3 :
            array=(from YieldCurveData yieldCurveData in this orderby yieldCurveData.Date ascending select yieldCurveData.Mo3).ToArray();
            break;
          case CurveType.Mo6 :
            array=(from YieldCurveData yieldCurveData in this orderby yieldCurveData.Date ascending select yieldCurveData.Mo6).ToArray();
            break;
          case CurveType.Yr1 :
            array=(from YieldCurveData yieldCurveData in this orderby yieldCurveData.Date ascending select yieldCurveData.Yr1).ToArray();
            break;
          case CurveType.Yr2 :
            array=(from YieldCurveData yieldCurveData in this orderby yieldCurveData.Date ascending select yieldCurveData.Yr2).ToArray();
            break;
          case CurveType.Yr3 :
            array=(from YieldCurveData yieldCurveData in this orderby yieldCurveData.Date ascending select yieldCurveData.Yr3).ToArray();
            break;
          case CurveType.Yr5 :
            array=(from YieldCurveData yieldCurveData in this orderby yieldCurveData.Date ascending select yieldCurveData.Yr5).ToArray();
            break;
          case CurveType.Yr7 :
            array=(from YieldCurveData yieldCurveData in this orderby yieldCurveData.Date ascending select yieldCurveData.Yr7).ToArray();
            break;
          case CurveType.Yr10 :
            array=(from YieldCurveData yieldCurveData in this orderby yieldCurveData.Date ascending select yieldCurveData.Yr10).ToArray();
            break;
          case CurveType.Yr20 :
            array=(from YieldCurveData yieldCurveData in this orderby yieldCurveData.Date ascending select yieldCurveData.Yr20).ToArray();
            break;
          case CurveType.Yr30:
            array=(from YieldCurveData yieldCurveData in this orderby yieldCurveData.Date ascending select yieldCurveData.Yr30).ToArray();
            break;
        }
        return array;
    }
// Return the data for specified tenor.  The data is ordered with the earliest date in the highest index.  Thus the most recent date is in the lowest index   
    public double[] GetYieldCurveDataOrderByDateDescending(CurveType curveType)
    {
      double[] array=null;
        switch (curveType)
        {
          case CurveType.Mo1 :
            array=(from YieldCurveData yieldCurveData in this orderby yieldCurveData.Date descending select yieldCurveData.Mo1).ToArray();
            break;
          case CurveType.Mo2 :
            array=(from YieldCurveData yieldCurveData in this orderby yieldCurveData.Date descending select yieldCurveData.Mo2).ToArray();
            break;
          case CurveType.Mo3 :
            array=(from YieldCurveData yieldCurveData in this orderby yieldCurveData.Date descending select yieldCurveData.Mo3).ToArray();
            break;
          case CurveType.Mo6 :
            array=(from YieldCurveData yieldCurveData in this orderby yieldCurveData.Date descending select yieldCurveData.Mo6).ToArray();
            break;
          case CurveType.Yr1 :
            array=(from YieldCurveData yieldCurveData in this orderby yieldCurveData.Date descending select yieldCurveData.Yr1).ToArray();
            break;
          case CurveType.Yr2 :
            array=(from YieldCurveData yieldCurveData in this orderby yieldCurveData.Date descending select yieldCurveData.Yr2).ToArray();
            break;
          case CurveType.Yr3 :
            array=(from YieldCurveData yieldCurveData in this orderby yieldCurveData.Date descending select yieldCurveData.Yr3).ToArray();
            break;
          case CurveType.Yr5 :
            array=(from YieldCurveData yieldCurveData in this orderby yieldCurveData.Date descending select yieldCurveData.Yr5).ToArray();
            break;
          case CurveType.Yr7 :
            array=(from YieldCurveData yieldCurveData in this orderby yieldCurveData.Date descending select yieldCurveData.Yr7).ToArray();
            break;
          case CurveType.Yr10 :
            array=(from YieldCurveData yieldCurveData in this orderby yieldCurveData.Date descending select yieldCurveData.Yr10).ToArray();
            break;
          case CurveType.Yr20 :
            array=(from YieldCurveData yieldCurveData in this orderby yieldCurveData.Date descending select yieldCurveData.Yr20).ToArray();
            break;
          case CurveType.Yr30:
            array=(from YieldCurveData yieldCurveData in this orderby yieldCurveData.Date descending select yieldCurveData.Yr30).ToArray();
            break;
        }
        return array;
    }
    public DMAValues GetMovingAverage(CurveType curveType,int dayCount)
    {
      DMAValues dmaValues = new DMAValues();
      foreach (YieldCurveData yieldCurveData in this) 
      {
        DMAValue dmaValue = new DMAValue();
        dmaValue.Date = yieldCurveData.Date;
        switch (curveType)
        {
          case CurveType.Mo1 :
            dmaValue.Value = yieldCurveData.Mo1;
            break;
          case CurveType.Mo2 :
            dmaValue.Value = yieldCurveData.Mo2;
            break;
          case CurveType.Mo3 :
            dmaValue.Value = yieldCurveData.Mo3;
            break;
          case CurveType.Mo6 :
            dmaValue.Value = yieldCurveData.Mo6;
            break;
          case CurveType.Yr1 :
            dmaValue.Value = yieldCurveData.Yr1;
            break;
          case CurveType.Yr2 :
            dmaValue.Value = yieldCurveData.Yr2;
            break;
          case CurveType.Yr3 :
            dmaValue.Value = yieldCurveData.Yr3;
            break;
          case CurveType.Yr5 :
            dmaValue.Value = yieldCurveData.Yr5;
            break;
          case CurveType.Yr7 :
            dmaValue.Value = yieldCurveData.Yr7;
            break;
          case CurveType.Yr10 :
            dmaValue.Value = yieldCurveData.Yr10;
            break;
          case CurveType.Yr20 :
            dmaValue.Value = yieldCurveData.Yr20;
            break;
          case CurveType.Yr30:
            dmaValue.Value = yieldCurveData.Yr30;
            break;
        }
        dmaValues.Add(dmaValue);
      }
      return MovingAverageGenerator.GenerateMovingAverage(dmaValues, dayCount);
    }
  }
  public class YieldCurveData
  {
    private DateTime date;
    private double mo1;
    private double mo2;
    private double mo3;
    private double mo6;
    private double yr1;
    private double yr2;
    private double yr3;
    private double yr5;
    private double yr7;
    private double yr10;
    private double yr20;
    private double yr30;

    public YieldCurveData()
    {
    }
    public DateTime Date
    {
      get { return date; }
      set { date = value; }
    }

    public bool IsValid()
    {
      if(Utility.IsEpoch(date))return false;
      if(double.IsNaN(mo1))return false;
      if(double.IsNaN(mo2))return false;
      if(double.IsNaN(mo3))return false;
      if(double.IsNaN(mo6))return false;
      if(double.IsNaN(yr1))return false;
      if(double.IsNaN(yr2))return false;
      if(double.IsNaN(yr3))return false;
      if(double.IsNaN(yr5))return false;
      if(double.IsNaN(yr7))return false;
      if(double.IsNaN(yr10))return false;
      if(double.IsNaN(yr20))return false;
      if(double.IsNaN(yr30))return false;
      return true;      
    }

    public double GetRate(String rateType)
    {
      if (rateType.Equals("1 Month Treasury")) return Mo1;
      else if (rateType.Equals("3 Month Treasury")) return Mo3;
      else if (rateType.Equals("2 Month Treasury")) return Mo2;
      else if (rateType.Equals("6 Month Treasury")) return Mo6;
      else if (rateType.Equals("1 Year Treasury")) return Yr1;
      else if (rateType.Equals("2 Year Treasury")) return Yr2;
      else if (rateType.Equals("3 Year Treasury")) return Yr3;
      else if (rateType.Equals("5 Year Treasury")) return Yr5;
      else if (rateType.Equals("7 Year Treasury")) return Yr7;
      else if (rateType.Equals("10 Year Treasury")) return Yr10;
      else if (rateType.Equals("20 Year Treasury")) return Yr20;
      else return 0.00;
    }
    public static List<String> GetRateTypesString()
    {
      List<String> riskFreeRateTypes = new List<String>();
      riskFreeRateTypes.Add("1 Month Treasury");
      riskFreeRateTypes.Add("2 Month Treasury");
      riskFreeRateTypes.Add("3 Month Treasury");
      riskFreeRateTypes.Add("6 Month Treasury");
      riskFreeRateTypes.Add("1 Year Treasury");
      riskFreeRateTypes.Add("2 Year Treasury");
      riskFreeRateTypes.Add("3 Year Treasury");
      riskFreeRateTypes.Add("5 Year Treasury");
      riskFreeRateTypes.Add("7 Year Treasury");
      riskFreeRateTypes.Add("10 Year Treasury");
      riskFreeRateTypes.Add("20 Year Treasury");
      return riskFreeRateTypes;
    }
    public double Mo1
    {
      get { return mo1; }
      set { mo1 = value; }
    }
    public double Mo2
    {
      get { return mo2; }
      set { mo2 = value; }
    }
    public double Mo3
    {
      get { return mo3; }
      set { mo3 = value; }
    }
    public double Mo6
    {
      get { return mo6; }
      set { mo6 = value; }
    }
    public double Yr1
    {
      get { return yr1; }
      set { yr1 = value; }
    }
    public double Yr2
    {
      get { return yr2; }
      set { yr2 = value; }
    }
    public double Yr3
    {
      get { return yr3; }
      set { yr3 = value; }
    }
    public double Yr5
    {
      get { return yr5; }
      set { yr5 = value; }
    }
    public double Yr7
    {
      get { return yr7; }
      set { yr7 = value; }
    }
    public double Yr10
    {
      get { return yr10; }
      set { yr10 = value; }
    }
    public double Yr20
    {
      get { return yr20; }
      set { yr20 = value; }
    }
    public double Yr30
    {
      get { return yr30; }
      set { yr30 = value; }
    }
  }
}
