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

namespace MarketData.Cache
{
  // cache by symbol + div_ex_date
  public class DividendHistoryByDixExYear:Dictionary<int,DividendHistory>
  {
    private int maxYear=int.MinValue;
    private int minYear=int.MaxValue;

    public DividendHistoryByDixExYear()
    {
    }
    public new void Add(int key,DividendHistory dividendHistory)
    {
      base.Add(key,dividendHistory);
      if(key>maxYear) maxYear=key;
      if(key<minYear) minYear=key;
    }
    public int MaxYear
    {
      get { return maxYear; }
    }
    public int MinYear
    {
      get { return minYear; }
    }
  }

  public class DividendHistoryCache
  {
    private Dictionary<String,DividendHistoryByDixExYear> dividendHistoryCache=new Dictionary<String,DividendHistoryByDixExYear>();
    private static DividendHistoryCache instance=null;
    private Object thisLock=new Object();

    private DividendHistoryCache()
    {
    }
    public void Dispose()
    {
      lock(thisLock)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,"[DividendHistoryCache:Dispose]Joined...");
        instance=null;
      }
    }
    public static DividendHistoryCache GetInstance()
    {
      lock(typeof(DividendHistoryCache))
      {
        if(null==instance) instance=new DividendHistoryCache();
        return instance;
      }
    }
    public void ClearCache()
    {
      lock(typeof(DividendHistoryCache))
      {
        dividendHistoryCache.Clear();
      }
    }
    public void Add(DividendHistory dividendHistory)
    {
      lock(typeof(DividendHistoryCache))
      {
        int[] divExYears=dividendHistory.Select(x=>x.DivExDate.Year).Distinct().ToArray<int>();
        String[] symbols=dividendHistory.Select(x=>x.Symbol).Distinct().ToArray<String>();

        foreach(String symbol in symbols)
        {
          foreach(int divExYear in divExYears)
          {
            DividendHistory historyList=new DividendHistory(dividendHistory.Where(x => x.DivExDate.Year.Equals(divExYear)&&x.Symbol.Equals(symbol)).ToList());
            Add(symbol,divExYear,historyList);
          }
        }
      }
    }
    private void Add(String symbol,int divExYear,DividendHistory dividendHistory)
    {
      lock(typeof(DividendHistoryCache))
      {
        if(!dividendHistoryCache.ContainsKey(symbol))
        {
          DividendHistoryByDixExYear dividendHistoryByDivExYear=new DividendHistoryByDixExYear();
          dividendHistoryByDivExYear.Add(divExYear,dividendHistory);
          dividendHistoryCache.Add(symbol,dividendHistoryByDivExYear);
        }
        else
        {
          DividendHistoryByDixExYear dividendHistoryByDixExYear=dividendHistoryCache[symbol];
          if(!dividendHistoryByDixExYear.ContainsKey(divExYear))
          {
            dividendHistoryByDixExYear.Add(divExYear,dividendHistory);
          }
        }
      }
    }
    public DividendHistory GetDividendHistory(String symbol, int[] divExYears)
    {
      DividendHistory dividendHistory=new DividendHistory();

      foreach(int divExYear in divExYears)
      {
        if(!DividendHistoryCache.GetInstance().ContainsDividendHistory(symbol,divExYear))
        {
          DividendHistory dividendHistoryList=DividendHistoryDA.GetDividendHistory(symbol,new int[] { divExYear });
          if(0==dividendHistoryList.Count) DividendHistoryCache.GetInstance().Add(symbol,divExYear,dividendHistoryList);
          else DividendHistoryCache.GetInstance().Add(dividendHistoryList);
          dividendHistory.AddRange(dividendHistoryList);
        }
        else
        {
          dividendHistory.AddRange(DividendHistoryCache.GetInstance().GetDividendHistory(symbol,divExYear));
        }
      }
      return dividendHistory;
    } 
    private DividendHistory GetDividendHistory(String symbol,int divExYear)
    {
      lock(typeof(DividendHistoryCache))
      {
        if(!dividendHistoryCache.ContainsKey(symbol)) return null;
        DividendHistoryByDixExYear dividendHistoryByDixExYear=dividendHistoryCache[symbol];
        if(!dividendHistoryByDixExYear.ContainsKey(divExYear)) return null;
        return dividendHistoryByDixExYear[divExYear];
      }
    }
    public bool ContainsDividendHistory(String symbol,int divExYear)
    {
      lock(typeof(DividendHistoryCache))
      {
        if(!dividendHistoryCache.ContainsKey(symbol)) return false;
        DividendHistoryByDixExYear dividendHistoryByDixExYear=dividendHistoryCache[symbol];
        if(!dividendHistoryByDixExYear.ContainsKey(divExYear)) return false;
        return true;
      }
    }
  }
}
