using System;
using System.Text;
using System.Linq;
using MarketData.Utils;
using System.Collections.Generic;
using MarketData.ValueAtRisk;
using MarketData.Numerical;

namespace MarketData.MarketDataModel
{
  public class PortfolioHoldingsWithBeta : List<PortfolioHoldingWithBeta>
  {
    private PortfolioHoldingsWithBeta()
    {
    }
// Copy Constructor
    public PortfolioHoldingsWithBeta(List<PortfolioHoldingWithBeta> portfolioHoldingsWithBeta)
    {
      PortfolioBeta = 0.00;
      if (null == portfolioHoldingsWithBeta) return;
      foreach (PortfolioHoldingWithBeta portfolioHoldingWithBeta in portfolioHoldingsWithBeta) Add(portfolioHoldingWithBeta);
      foreach (PortfolioHoldingWithBeta portfolioHoldingWithBeta in this) PortfolioBeta += portfolioHoldingWithBeta.WeightedBeta;
    }
    public PortfolioHoldingsWithBeta(PortfolioHoldings portfolioHoldings,DateTime analysisDate)
    {
      PortfolioBeta = 0.00;
      if (null == portfolioHoldings) return;
      foreach (PortfolioHolding portfolioHolding in portfolioHoldings) Add(new PortfolioHoldingWithBeta(portfolioHolding, analysisDate));
      foreach (PortfolioHoldingWithBeta portfolioHoldingWithBeta in this) PortfolioBeta += portfolioHoldingWithBeta.WeightedBeta;
      foreach (PortfolioHoldingWithBeta portfolioHoldingWithBeta in this) portfolioHoldingWithBeta.BetaContribution = portfolioHoldingWithBeta.WeightedBeta / PortfolioBeta;
    }
    public PortfolioHoldingsWithBeta(PortfolioTrades portfolioTrades, DateTime analysisDate)
    {
      PortfolioBeta = 0.00;
      double totalExposure = 0.00;
      if (null == portfolioTrades) return;
      List<MarketDataModel.Position> positions = portfolioTrades.GetPositions(analysisDate);
      foreach (MarketDataModel.Position position in positions) Add(new PortfolioHoldingWithBeta(position, analysisDate));
      foreach (PortfolioHoldingWithBeta portfolioHoldingWithBeta in this) totalExposure += portfolioHoldingWithBeta.Exposure;
      foreach (PortfolioHoldingWithBeta portfolioHoldingWithBeta in this)
      {
        portfolioHoldingWithBeta.WeightExp = portfolioHoldingWithBeta.Exposure / totalExposure;
        portfolioHoldingWithBeta.WeightedBeta = portfolioHoldingWithBeta.WeightExp * portfolioHoldingWithBeta.Beta;
      }
      foreach (PortfolioHoldingWithBeta portfolioHoldingWithBeta in this) PortfolioBeta += portfolioHoldingWithBeta.WeightedBeta;
      foreach (PortfolioHoldingWithBeta portfolioHoldingWithBeta in this) portfolioHoldingWithBeta.BetaContribution = portfolioHoldingWithBeta.WeightedBeta / PortfolioBeta;
    }
    public double PortfolioBeta { get; private set; }
    public double Exposure
    {
      get
      {
        return (from PortfolioHoldingWithBeta portfolioHoldingWithBeta in this select portfolioHoldingWithBeta.Exposure).Sum();
      }
    }
  }
  public class PortfolioHoldingWithBeta
  {
    private PortfolioHoldingWithBeta()
    {
    }
    // Assumes that the portfolioTrade is an open trade
//    public PortfolioHoldingWithBeta(MarketDataModel.Position position, DateTime? analysisDate = null)
    public PortfolioHoldingWithBeta(MarketDataModel.Position position, DateTime analysisDate)
    {
      Symbol = position.Symbol;
      Exposure = position.Exposure;
      //if (null == analysisDate) analysisDate = DateTime.Now;
      Beta = BetaGenerator.Beta(position.Symbol, analysisDate);
    }
//    public PortfolioHoldingWithBeta(PortfolioHolding portfolioHolding, DateTime? analysisDate = null)
    public PortfolioHoldingWithBeta(PortfolioHolding portfolioHolding, DateTime analysisDate)
    {
      //if (null == analysisDate) analysisDate = DateTime.Now;
      Symbol = portfolioHolding.Symbol;
      Exposure = portfolioHolding.Exposure;
      WeightExp = portfolioHolding.WeightExp;
      Beta = BetaGenerator.Beta(portfolioHolding.Symbol, analysisDate);
      WeightedBeta = portfolioHolding.WeightExp * Beta;
    }
    public String Symbol { get; set; }
    public double Exposure { get; set; }
    public double Beta { get; private set; }
    public double WeightExp { get; set; }
    public double WeightedBeta { get; set; }
    public double BetaContribution { get; set; }
  }
}