using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MarketData.ValueAtRisk
{
// *****************************************************************************************************************************************************
  public class Contribution
  {
    public String Symbol{get;set;}
    public DateTime AnalysisDate{get;set;}
    public double ContributionValue{get;set;}
    public Contribution()
    {
    }
    public Contribution(String symbol,DateTime analysisDate,double contribution)
    {
      this.Symbol=symbol;
      this.ContributionValue=contribution;
      this.AnalysisDate=analysisDate;
    }
  }
  public class Contributions : List<Contribution>
  {
    public Contributions()
    {
    }
    public Contributions(List<Contribution> contributions)
    {
      foreach(Contribution contribution in contributions)Add(contribution);
    }
  }
  public class ContributionSorter : IComparer<Contribution>
  {
    public int Compare(Contribution c1,Contribution c2)
    {
      return c1.ContributionValue.CompareTo(c2.ContributionValue);
    }
  }
// *****************************************************************************************************************************************************
  public class WeightedReturn
  {
    public String Symbol{get;set;}
    public DateTime AnalysisDate{get;set;}
    public double WeightedReturnValue{get;set;}
    public WeightedReturn()
    {
    }
    public WeightedReturn(String symbol,DateTime analysisDate,double weightedReturn)
    {
      this.Symbol=symbol;
      this.WeightedReturnValue=weightedReturn;
      this.AnalysisDate=analysisDate;
    }
  }
  public class WeightedReturns : List<WeightedReturn>
  {
    public double GetTotalWeightAdjustedReturn()
    {
      return this.Sum(x=>x.WeightedReturnValue);
    }
    public Contributions GetContributions()
    {
      Contributions contributions=new Contributions();
      double totalWeightedReturn=GetTotalWeightAdjustedReturn();
      foreach(WeightedReturn weightedReturn in this)
      {
        contributions.Add(new Contribution(weightedReturn.Symbol,weightedReturn.AnalysisDate,weightedReturn.WeightedReturnValue/totalWeightedReturn));
      }
      return contributions;
    }
  }
// ******************************************************************************************************************************************************
  public class WeightedReturnsWithContribution
  {
    private Dictionary<int,WeightedReturns> weightedReturnsWithContribution=new Dictionary<int,WeightedReturns>();

    public WeightedReturnsWithContribution()
    {
    }
    public int Count
    {
      get{return weightedReturnsWithContribution.Count;}
    }
    public void Add(int index,WeightedReturn weightedReturn)
    {
      if(!weightedReturnsWithContribution.ContainsKey(index))weightedReturnsWithContribution.Add(index,new WeightedReturns());
      weightedReturnsWithContribution[index].Add(weightedReturn);
    }
    public double[] GetWeightedReturns()
    {
      List<int> keys=new List<int>(weightedReturnsWithContribution.Keys);
      keys.Sort();
      List<double> weightedReturns=new List<double>();
      foreach(int key in keys)
      {
        weightedReturns.Add(weightedReturnsWithContribution[key].GetTotalWeightAdjustedReturn());
      }
      return weightedReturns.ToArray<double>();
    }
    public List<Contributions> GetContributions()
    {
      List<int> keys=new List<int>(weightedReturnsWithContribution.Keys);
      keys.Sort();
      List<Contributions> contributionsList=new List<Contributions>();
      foreach(int key in keys)
      {
        WeightedReturns weightedReturns=weightedReturnsWithContribution[key];
        contributionsList.Add(weightedReturns.GetContributions());
      }
      return contributionsList;
    }
  }
}
