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

namespace TradeBlotter.Cache
{
  //public class CacheInfo
  //{
  //  public CacheInfo()
  //  {
  //  }
  //  public Prices Prices { get; set; }
  //}

  public class PriceCache : IDisposable
  {
    private Dictionary<String, Prices> priceCache = new Dictionary<String, Prices>();
    private Object thisLock = new Object();
    private Thread cacheMonitorThread = null;
    private bool threadRun = true;
    private int cacheRefreshAfter = 30000;
    private static PriceCache priceCacheInstance = null;

    private PriceCache()
    {
      cacheMonitorThread = new Thread(new ThreadStart(ThreadProc));
      cacheMonitorThread.Start();
    }
    public static PriceCache GetInstance()
    {
      lock (typeof(PriceCache))
      {
        if (null == priceCacheInstance) priceCacheInstance = new PriceCache();
        return priceCacheInstance;
      }
    }
    public void Dispose()
    {
      lock (thisLock)
      {
        threadRun = false;
        if (null != cacheMonitorThread)
        {
          cacheMonitorThread.Join();
        }
        priceCache.Clear();
        priceCacheInstance = null;
      }
    }
    public Prices GetPrices(String symbol, int days)
    {
      lock (thisLock)
      {
        DateTime now = DateTime.Now;
        Prices prices = null;
        Price price = null;
        if (priceCache.ContainsKey(symbol)) prices = priceCache[symbol];
        if (null != prices)
        {
          if (prices.Count >= days)
          {
            Prices priceRange = null;
            if (prices.Count == days) priceRange = prices;
            else priceRange = new Prices(prices.GetRange(0, days).ToArray());
            return priceRange;
          }
          if(prices.Count>0)price = prices[0];
          prices = PricingDA.GetPrices(symbol, days);
          if (null!=prices&&price.Date.Date.Equals(DateTime.Now.Date.Date)&&(prices.Count>0&&prices[0].Date.Date!=price.Date.Date)) prices.Insert(0,price);
          return prices;
        }
        prices = PricingDA.GetPrices(symbol, days);
        if (null != prices && 0 != prices.Count) priceCache.Add(symbol, prices);
        return prices;
      }
    }
    public Price GetLatestPrice(String symbol)
    {
      lock (thisLock)
      {
        DateTime now = DateTime.Now;
        Price price = null;
        Prices prices = null;
        if (priceCache.ContainsKey(symbol)) prices = priceCache[symbol];
        if (null!=prices)
        {
          if (0 == prices.Count)
          {
            price = MarketDataHelper.GetLatestPrice(symbol);
            if (null != price) prices.Add(price);
          }
          else
          {
            price = prices[0];
            if (price.Date.Date.Equals(now.Date.Date)) return price;
            price = MarketDataHelper.GetLatestPrice(symbol);
            if (null != price) prices.Insert(0,price);
          }
          return price;
        }
        price = MarketDataHelper.GetLatestPrice(symbol);
        if (null != price)
        {
          prices = new Prices();
          prices.Add(price);
          priceCache.Add(symbol, prices);
        }
        return price;
      }
    }
    public bool Contains(String symbol)
    {
      lock (thisLock)
      {
        return priceCache.ContainsKey(symbol);
      }
    }
    private void ThreadProc()
    {
      int quantums = 0;
      int quantumInterval = 500;
      while (threadRun)
      {
        Thread.Sleep(quantumInterval);
        quantums += quantumInterval;
        if (quantums > cacheRefreshAfter)
        {
          quantums = 0;
          lock (thisLock)
          {
            DateTime now = DateTime.Now;
            List<String> symbols = new List<String>(priceCache.Keys);
            foreach (String symbol in symbols)
            {
              Prices prices=priceCache[symbol];
              if (null ==prices || 0 == prices.Count) continue;
              Price price = prices[0];
              if (price.Date.Date.Equals(now.Date.Date))
              {
                prices.Remove(price);
                price=MarketDataHelper.GetLatestPrice(symbol);
                if(null==price)prices.Insert(0,price);
              }
              //if (price.Date.Date.Equals(now.Date.Date)) prices.Remove(price);
            }
          }
        }
      }
    }
  }
}
