using System;
using System.Linq;
using System.Collections.Generic;
using MarketData;
using MarketData.MarketDataModel;
using MarketData.MarketDataModel.GainLoss;
using MarketData.Utils;
using MarketData.DataAccess;
using MarketData.Cache;

namespace MarketData.Generator.GainLoss
{
// ***************************************************************** G A I N  L O S S  G E N E R A T O R  **********************************************************
  public class ActiveGainLossGenerator : IActiveGainLossGenerator
  {
    public ActiveGainLossGenerator()
    {
    }
    //public void RefreshPriceCache()
    //{
    //  LocalPriceCache.GetInstance().Refresh();
    //}
// *****************************************************************************************************************************************************************
// ************************************************ G E N E R A T E  A C T I V E  G A I N  L O S S  /  G A I N  L O S S  P E R C E N T *****************************
// *****************************************************************************************************************************************************************
    public GainLossCollection GenerateGainLoss(PortfolioTrades portfolioTrades,DateTime? maxDateRef=null)
    {
      if (null == portfolioTrades || 0 == portfolioTrades.Count) return null;
      LocalPriceCache.GetInstance().Add(portfolioTrades);
      DateTime minTradeDate = portfolioTrades.GetMinTradeDate();
      DateTime maxDate = PricingDA.GetLatestDate();
      if(null!=maxDateRef)maxDate=maxDateRef.Value;
      Dictionary<DateTime,GainLossItem> gainLoss = new Dictionary<DateTime, GainLossItem>();
      DateGenerator dateGenerator = new DateGenerator();
      List<DateTime> holdingDates = dateGenerator.GenerateHistoricalDates(maxDate, minTradeDate);
      for (int index = holdingDates.Count - 1; index >= 0; index--)
      {
        DateTime holdingDate = holdingDates[index];
        double? gainLossHoldings = null;
        double totalExposure = 0.00;
        double totalCostBasis=0.00;
        double totalMarketValue=0.00;
        PortfolioTrades openTrades = portfolioTrades.GetOpenTradesOn(holdingDate);
        if (null == openTrades || 0 == openTrades.Count)
        {
          gainLoss.Add(holdingDate, new GainLossItem(holdingDate, 0,0,false));
          continue;
        }
        if(!LocalPriceCache.GetInstance().ContainsPrice(openTrades.Symbols,holdingDate))
				{
          if(holdingDate.Date.Equals(maxDate))
          {
            LocalPriceCache.GetInstance().Add(openTrades.Symbols,holdingDate);
          }else continue;
				}
        foreach (PortfolioTrade portfolioTrade in openTrades)
        {
          double? gainLossItem = null;
          double? exposure = null;
          double? costBasis=null;
          double? marketValue=null;

          costBasis=GainLossHelper.GetCostBasis(holdingDate,portfolioTrade);
          gainLossItem=GainLossHelper.GetGainLoss(holdingDate, portfolioTrade);
          marketValue=GainLossHelper.GetMarketValue(holdingDate,portfolioTrade);
          if (null == gainLossItem) continue;
          if (null == gainLossHoldings) gainLossHoldings = gainLossItem;
          else gainLossHoldings += gainLossItem;
          exposure = GainLossHelper.GetExposure(holdingDate,portfolioTrade);
          if (null != exposure) totalExposure += exposure.Value;
          if(null!=costBasis)totalCostBasis+=costBasis.Value;
          if(null!=marketValue)totalMarketValue+=marketValue.Value;
        }
        GainLossItem gainLossElement = null;
        double totalGainLossPercent=0;
        if(0!=totalCostBasis)totalGainLossPercent=((totalMarketValue-totalCostBasis)/totalCostBasis)*100.00;
        if(null==gainLossHoldings)
        {
          MDTrace.WriteLine(LogLevel.DEBUG,String.Format("ActiveGainLossGenerator:GenerateGainLoss 'GainLossHoldings' is null for on {0}",Utility.DateTimeToStringMMHDDHYYYY(holdingDate)));
          continue;
        }
        if (null == gainLossHoldings)gainLossElement = new GainLossItem(holdingDate,gainLossHoldings.Value,totalGainLossPercent,totalExposure,false);
        else gainLossElement = new GainLossItem(holdingDate, gainLossHoldings.Value,totalGainLossPercent,totalExposure,false); 
        gainLoss.Add(holdingDate, gainLossElement);
      }
      GainLossCollection gainLossList = new GainLossCollection(gainLoss.Values);  
      gainLossList.Sort();
      return gainLossList;
    }
  }
}
