using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Threading;
using System.Reflection;
using System.Runtime.Remoting.Messaging;
using System.Text;
using MarketData.MarketDataModel;
using MarketData.DataAccess;
using MarketData.Utils;
using MarketData.Numerical;
using MarketData;

namespace MarketData.Generator
{
  public class MACDGenerator
  {
    private MACDGenerator()
    {
    }
    public static MACDFastSlowSignals GenerateMACD(String symbol,int dayCount=120)
    {
      try
      {
        DateGenerator dateGenerator = new DateGenerator();
        DateTime startDate = DateTime.Now;
        if (null == symbol) return null;
        symbol = symbol.ToUpper();
        Dictionary<DateTime, MACDFastSlowSignal> macdFastSlowSignalsByDate = new Dictionary<DateTime, MACDFastSlowSignal>();
        startDate = dateGenerator.GetPrevBusinessDay(DateTime.Now); ;
        if (Utility.IsEpoch(startDate))
        {
          MDTrace.WriteLine(LogLevel.DEBUG,"No price dates for '" + symbol + "'");
          return null;
        }
        DateTime historicalDate = dateGenerator.GenerateHistoricalDate(startDate, dayCount);
        Prices prices = PricingDA.GetPrices(symbol, startDate, historicalDate);
        if (null == prices || 0 == prices.Count)
        {
          MDTrace.WriteLine(LogLevel.DEBUG,"No price dates for '" + symbol + "'");
          return null;
        }
        Price latestPrice = prices[0];
        String companyName = PricingDA.GetNameForSymbol(symbol);
        MACDSetup macdSetupSlow = new MACDSetup(12, 26, 9);
        MACDSetup macdSetupFast = new MACDSetup(8, 17, 9);
        MACDSignals macdSignalsSlow = MACDGenerator.GenerateMACD(prices, macdSetupSlow);
        MACDSignals macdSignalsFast = MACDGenerator.GenerateMACD(prices, macdSetupFast);

        Signals signalsSlow=SignalGenerator.GenerateSignals(macdSignalsSlow);
        signalsSlow=signalsSlow.CondenseSignals();
        Signals signalsFast=SignalGenerator.GenerateSignals(macdSignalsFast);
        signalsFast=signalsFast.CondenseSignals();

        for (int index = 0; index < macdSignalsSlow.Count; index++)
        {
          MACDSignal macdSignal = macdSignalsSlow[index];
          if (!macdFastSlowSignalsByDate.ContainsKey(macdSignal.Date))
          {
            MACDFastSlowSignal macdFastSlowSignal = new MACDFastSlowSignal();
            macdFastSlowSignal.Date = macdSignal.Date;
            macdFastSlowSignal.SignalSlow = macdSignal.Signal;
            macdFastSlowSignal.MACDSlow = macdSignal.MACD;
            macdFastSlowSignalsByDate.Add(macdSignal.Date, macdFastSlowSignal);
          }
        }
        for (int index = 0; index < macdSignalsFast.Count; index++)
        {
          MACDSignal macdSignal = macdSignalsFast[index];
          if (!macdFastSlowSignalsByDate.ContainsKey(macdSignal.Date)) continue;
          MACDFastSlowSignal macdFastSlowSignal = macdFastSlowSignalsByDate[macdSignal.Date];
          macdFastSlowSignal.SignalFast = macdSignal.Signal;
          macdFastSlowSignal.MACDFast = macdSignal.MACD;
        }
        MACDFastSlowSignals macdFastSlowSignals = new MACDFastSlowSignals(macdFastSlowSignalsByDate.Values);
        macdFastSlowSignals.Symbol = symbol;
        macdFastSlowSignals.FromDate = prices[prices.Count - 1].Date;
        macdFastSlowSignals.ThruDate = prices[0].Date;
        macdFastSlowSignals.Sort(new MACDFastSlowSignalsComparerAsc());
        macdFastSlowSignals.SlowCondensedSignals=signalsSlow;
        macdFastSlowSignals.FastCondensedSignals=signalsFast;

        return macdFastSlowSignals;
      }
      catch (Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,exception);
        return null;
      }
    }
    public static MACDSignals GenerateMACD(Prices prices, MACDSetup macdSetup)
    {
      try
      {
        MACDSignals macdSignals = new MACDSignals();
        for (int index = 0; index < prices.Count; index++)
        {
          MACDSignal macdSignal = new MACDSignal();
          float[] pricesArray = null;
          Price price = prices[index];
          macdSignal.Symbol = price.Symbol;
          macdSignal.Date = price.Date;
          pricesArray = prices.GetPrices(index, macdSetup.Fast);    // 12
          if (null == pricesArray) break;
          macdSignal.Fast = Numerics.Mean(ref pricesArray);
          pricesArray = prices.GetPrices(index, macdSetup.Slow);
          if (null == pricesArray) break;
          macdSignal.Slow = Numerics.Mean(ref pricesArray);  // 26
          macdSignal.MACD = macdSignal.Fast - macdSignal.Slow;
          macdSignals.Add(macdSignal);
        }
        for (int index = 0; index < macdSignals.Count; index++)
        {
          MACDSignal macdSignal = macdSignals[index];
          float[] macd = macdSignals.GetMACD(index, macdSetup.Signal);  // 9 
          if (null != macd) macdSignal.Signal = Numerics.Mean(ref macd);
          macdSignal.Histogram = macdSignal.MACD - macdSignal.Signal;
        }
        return macdSignals;
      }
      catch (Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,exception);
        return null;
      }
    }   
  }
}
