using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MarketData.DataAccess;
using MarketData.MarketDataModel;

namespace MarketData.ValueAtRisk
{
  public class PortfolioHoldings : List<PortfolioHolding>
  {
    public PortfolioHoldings()
    {
    }
    public void SetReturnDays(int days)
    {
      for (int index = 0; index < Count; index++)
      {
        PortfolioHolding portfolioHolding = this[index];
        portfolioHolding.SetReturnDays(days);
      }
    }
    public double GetMarketValue()
    {
      return (from portfolioHolding in this select portfolioHolding.MarketValue).Sum();
    }
    public void UpdateDayCount(int dayCount)
    {
      for (int index = 0; index < Count; index++)
      {
        PortfolioHolding portfolioHolding = this[index];
        portfolioHolding.Prices = PricingDA.GetPrices(portfolioHolding.Symbol, portfolioHolding.AsOf, dayCount + 1);
        portfolioHolding.MarketValue = portfolioHolding.Prices[0].Close * portfolioHolding.Shares;
      }
      double totalMarketValue = (from portfolioHolding in this select portfolioHolding.MarketValue).Sum();
      ForEach(portfolioHolding => new Action(delegate() { portfolioHolding.Weight = portfolioHolding.MarketValue / totalMarketValue; }).Invoke());
    }
    public static PortfolioHoldings GetPortfolioHoldings(PortfolioTrades portfolioTrades,int dayCount,DateTime startDate)
    {
      if (null == portfolioTrades || 0 == portfolioTrades.Count) return null;
      PortfolioHoldings portfolioHoldings = new PortfolioHoldings();
      List<String> symbols = (from portfolioTrade in portfolioTrades select portfolioTrade.Symbol).Distinct().ToList();
      for (int index = 0; index < symbols.Count; index++)
      {
        String symbol = symbols[index];
        List<PortfolioTrade> trades = (from portfolioTrade in portfolioTrades where portfolioTrade.Symbol.Equals(symbol) select portfolioTrade).ToList();
        double totalShares = (from portfolioTrade in trades select portfolioTrade.Shares).Sum();
        double totalExposure=(from portfolioTrade in trades select portfolioTrade.Shares*portfolioTrade.Price).Sum();
        PortfolioHolding portfolioHolding = new PortfolioHolding();
        portfolioHolding.Symbol = symbol;
        portfolioHolding.Shares = totalShares;
        portfolioHolding.Prices = PricingDA.GetPrices(symbol, startDate, dayCount + 1);
        portfolioHolding.Weight = 0;
        if (null != portfolioHolding.Prices && 0 != portfolioHolding.Prices.Count) portfolioHolding.MarketValue = portfolioHolding.Prices[0].Close * totalShares;
        else portfolioHolding.MarketValue = 0.00;
        portfolioHolding.Exposure=totalExposure;
        portfolioHolding.AsOf = startDate;
        portfolioHoldings.Add(portfolioHolding);
      }
      double totalMarketValue = (from portfolioHolding in portfolioHoldings select portfolioHolding.MarketValue).Sum();
      double totalPortfolioExposure = (from portfolioHolding in portfolioHoldings select portfolioHolding.Exposure).Sum();
      if(0.00!=totalMarketValue)portfolioHoldings.ForEach(portfolioHolding => new Action(delegate() { portfolioHolding.Weight = portfolioHolding.MarketValue / totalMarketValue;}).Invoke());
      if (0.00 != totalPortfolioExposure) portfolioHoldings.ForEach(portfolioHolding => new Action(delegate() { portfolioHolding.WeightExp = portfolioHolding.Exposure / totalPortfolioExposure; }).Invoke());
      return portfolioHoldings;
    }
  }
// Weight : This is the market value based weight
// WeightExp : This is the exposure based weight
  public class PortfolioHolding
  {
    private String symbol;
    private DateTime asOf;
    private double shares;
    private double weight;
    private double weightExp;
    private double marketValue;
    private double exposure;
    private int returnDays = 1;
    private Prices prices;
    private double[] returns = null;
    private double contribution;         // This is used in the VaR analysis and is populated with the contribution to VaR at the time of the analysis
    private DateTime contributionDate;   // This is used in the VaR analysis and is populated with the contribution to VaR at the time of the analysis 

    public PortfolioHolding()
    {
    }
    public PortfolioHolding(PortfolioHolding portfolioHolding)
    {
      prices = portfolioHolding.prices;
      shares=portfolioHolding.shares;
      symbol = portfolioHolding.symbol;
      weight = portfolioHolding.weight;
      marketValue = portfolioHolding.marketValue;
      weightExp = portfolioHolding.weightExp;
      exposure=portfolioHolding.exposure;
      returnDays = portfolioHolding.returnDays;
      returns = portfolioHolding.returns;
      asOf = portfolioHolding.AsOf;
      contribution=portfolioHolding.contribution;
      contributionDate=portfolioHolding.contributionDate;
    }
    public String Symbol
    {
      get { return symbol; }
      set { symbol = value; }
    }
    public DateTime AsOf
    {
      get { return asOf; }
      set { asOf = value; }
    }
    public double Shares
    {
      get { return shares; }
      set { shares = value; }
    }
    public double Contribution
    {
      get{return contribution;}
      set{contribution=value;}
    }
    public DateTime ContributionDate
    {
      get{return contributionDate;}
      set{contributionDate=value;}
    }
    public void SetReturnDays(int days)
    {
      if (returnDays == days) return;
      returnDays = days;
      returns = prices.GetReturnsAsDoubleArray(returnDays);
    }
    public Prices Prices
    {
      get { return prices; }
      set { prices = value; returns = prices.GetReturnsAsDoubleArray(returnDays); }
    }
    public double Weight
    {
      get { return weight; }
      set { weight = value; }
    }
    public double WeightExp
    {
      get { return weightExp; }
      set { weightExp = value; }
    }
    public double[] Returns
    {
      get { return returns; }
    }
    public double MarketValue
    {
      get { return marketValue; }
      set { marketValue = value; }
    }
    public double Exposure
    {
      get{return exposure;}
      set{exposure=value;}
    }
  }
}
