using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MarketData.MarketDataModel;
using MarketData.Utils;
using System.Collections.ObjectModel;
using Microsoft.Research.DynamicDataDisplay.DataSources;
using MarketData;
using MarketData.Numerical;

namespace TradeBlotter.Model
{
  public class DividendPaymentModelCollection : ObservableCollection<DividendPaymentModel>
  {
    public DividendPaymentModelCollection(DividendPayments dividendPayments)
    {
      try
      {
        if (null == dividendPayments || 0 == dividendPayments.Count) return;
        List<DividendPayment> dividendPaymentsOrdered = dividendPayments.OrderByDescending(x => x.PaymentDate).ThenBy(x => x.Account).ThenBy(x => x.Symbol).ToList();
        int currentYear = -1;
        for (int index = dividendPaymentsOrdered.Count - 1; index >= 0; index--)
        {
          DividendPaymentModel dividendPaymentModel = new DividendPaymentModel(dividendPaymentsOrdered[index]);
          if (0 == Count) dividendPaymentModel.TotalAmount = dividendPaymentModel.Amount;
          else dividendPaymentModel.TotalAmount = this[0].TotalAmount + dividendPaymentModel.Amount;
          if (currentYear != dividendPaymentModel.PaymentDate.Year) { currentYear = dividendPaymentModel.PaymentDate.Year; dividendPaymentModel.TotalAnnualAmount = dividendPaymentModel.Amount; }
          else dividendPaymentModel.TotalAnnualAmount = this[0].TotalAnnualAmount + dividendPaymentModel.Amount;
          Insert(0, dividendPaymentModel);
        }
      }
      catch (Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG, String.Format("{0}",exception));
      }
    }
// This method just takes the total for each day and then splines the result to get a smooth curve
    public CompositeDataSource ToCompositeDataSource(bool useTotal)
    {
      if (0 == Count) return null;
      List<DividendPaymentModel> dividendPaymentsModelList = new List<DividendPaymentModel>();
      DateTime currentDate = Utility.Epoch;
      foreach (DividendPaymentModel dividendPaymentModel in this)
      {
        if (currentDate.Equals(Utility.Epoch))
        {
          currentDate = dividendPaymentModel.PaymentDate;
          dividendPaymentsModelList.Add(dividendPaymentModel);
        }
        else if(!currentDate.Date.Equals(dividendPaymentModel.PaymentDate))
        {
          currentDate = dividendPaymentModel.PaymentDate;
          dividendPaymentsModelList.Add(dividendPaymentModel);
        }
      }

      List<Element> sourcePairs = new List<Element>();
      List<Element> destPairs = new List<Element>();
      DateGenerator dateGenerator = new DateGenerator();
      DateTime minDate = dividendPaymentsModelList.Min(x => x.PaymentDate);
      DateTime maxDate = dividendPaymentsModelList.Max(x => x.PaymentDate);
      List<DateTime> historicalDates=dateGenerator.GenerateHistoricalDates(maxDate, minDate);
      foreach (DateTime historicalDate in historicalDates) destPairs.Add(new Element(dateGenerator.DaysBetweenActual(minDate,historicalDate.Date), 0));
      foreach (DividendPaymentModel dividendPaymentModel in dividendPaymentsModelList)
      {
        sourcePairs.Add(new Element(dateGenerator.DaysBetweenActual(minDate,dividendPaymentModel.PaymentDate), dividendPaymentModel.TotalAmount));
      }
      Element[] sourcePairsArray = sourcePairs.ToArray();
      Element[] destPairsArray = destPairs.ToArray();
      CatmullRom.PerformSpline(sourcePairsArray, destPairsArray);

      CompositeDataSource compositeDataSource;
      var xData = new EnumerableDataSource<DateTime>(destPairsArray.Select(x => dateGenerator.DaysAddActual(minDate,Math.Abs((int)x.Column))));
      xData.SetXMapping(x => x.Ticks / 10000000000.0);
      var yData = new EnumerableDataSource<double>(destPairsArray.Select(y => y.Row));
      yData.SetYMapping(y => y);
      compositeDataSource = xData.Join(yData);
      return compositeDataSource;
    }
// This method takes the points only at the payment dates
    public CompositeDataSource CollectionToCompositeDataSource(bool useTotal)
    {
      if (0 == Count) return null;
      List<DividendPaymentModel> dividendPaymentsModelList = new List<DividendPaymentModel>();
      DateTime currentDate = Utility.Epoch;
      foreach (DividendPaymentModel dividendPaymentModel in this)
      {
        if (currentDate.Equals(Utility.Epoch))
        {
          currentDate = dividendPaymentModel.PaymentDate;
          dividendPaymentsModelList.Add(dividendPaymentModel);
        }
        else if (!currentDate.Date.Equals(dividendPaymentModel.PaymentDate))
        {
          currentDate = dividendPaymentModel.PaymentDate;
          dividendPaymentsModelList.Add(dividendPaymentModel);
        }
      }
      CompositeDataSource compositeDataSource;
      var xData = new EnumerableDataSource<DateTime>(dividendPaymentsModelList.Select(x => x.PaymentDate));
      xData.SetXMapping(x => x.Ticks / 10000000000.0);
      var yData = new EnumerableDataSource<double>(dividendPaymentsModelList.Select(y => y.TotalAmount));
      yData.SetYMapping(y => y);
      compositeDataSource = xData.Join(yData);
      return compositeDataSource;
    }
    //public ObservableCollection<DividendPaymentModel> Clone()
    //{
    //  ObservableCollection<DividendPaymentModel> dividendPayments = new ObservableCollection<DividendPaymentModel>();
    //  foreach (DividendPaymentModel dividendPaymentModel in this) Add(dividendPaymentModel);
    //  return dividendPayments;
    //}
  }
  public class DividendPaymentModel : DividendPayment
  {
    public DividendPaymentModel()
    {
    }
    public DividendPaymentModel(DividendPayment dividendPayment)
    {
      this.PaymentDate = dividendPayment.PaymentDate;
      this.Symbol = dividendPayment.Symbol;
      this.Account = dividendPayment.Account;
      this.Amount = dividendPayment.Amount;
    }
    public double TotalAmount { get; set; }
    public double TotalAnnualAmount { get; set; }
  }
}
