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


namespace MarketData.Generator
{
  public class ParityGenerator
  {
    private enum Direction { Negative, Positive, None };
    private ParityGenerator()
    {
    }
    public static ParityElement GenerateBreakEven(String symbol)
    {
      try
      {
        ParityElement parityElement=new ParityElement();
        Price zeroPrice=null;
        PortfolioTrades portfolioTrades = PortfolioDA.GetTradesSymbol(symbol);
        if(null==portfolioTrades||0==portfolioTrades.Count)return null;
        PortfolioTrades openTrades=portfolioTrades.GetOpenTrades();
        DateTime pricingDate = PricingDA.GetLatestDate(symbol);
        Price latestPrice = PricingDA.GetPrice(symbol, pricingDate);
        GainLossGenerator gainLossGenerator=new GainLossGenerator();
        zeroPrice=ParityGenerator.GenerateGainLossValue(openTrades,latestPrice);
        parityElement.ParityOffsetPrice=zeroPrice.Close;
        parityElement.ParityOffsetPercent=((latestPrice.Close-zeroPrice.Close)/zeroPrice.Close);
        parityElement.Symbol=symbol;
        parityElement.PricingDate=pricingDate;
        return parityElement;
      }
      catch(Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,String.Format("{0}",exception));
        return null;
      }
    }
// generate gain/loss value for portfolio of like symbols
// This funtion will return the dollar price that the stock must either rise to (when G/L is negative) or fall to (when the G/L is positive)
// in order to produce a zero return (i.e.) a wash.
    public static Price GenerateGainLossValue(PortfolioTrades portfolioTrades,Price givenPrice)
    {
      double? lowerClamp=null;
      double? upperClamp=null;
      double? gainLoss=null;
      double? prevGuess=null;
      Direction direction=Direction.None;
      int iterations=0;

      if(null==portfolioTrades||0==portfolioTrades.Count) return null;
      Price price=givenPrice.Clone();
      gainLoss=portfolioTrades.GetGainLoss(price);
      if(gainLoss<0) direction=Direction.Negative;
      else direction=Direction.Positive;
      while(true)
      {
        if(IsZero(gainLoss)) break;
        if(null==lowerClamp&&null==upperClamp&&gainLoss<0&&direction.Equals(Direction.Negative))
        {
          prevGuess=price.Close;
          price.Close=price.Close+(price.Close/2.00);
          iterations++;
        }
        else if(null==lowerClamp&&null==upperClamp&&gainLoss>=0&&direction.Equals(Direction.Positive))
        {
          prevGuess=price.Close;
          price.Close=price.Close-(price.Close/2.00);
          iterations++;
        }
        else
        {
          if(gainLoss<0)
          {
            lowerClamp=price.Close;
            if(null==upperClamp) upperClamp=prevGuess;
            price.Close=(lowerClamp.Value+upperClamp.Value)/2.00;
            prevGuess=price.Close;
            iterations++;
          }
          else
          {
            upperClamp=price.Close;
            if(null==lowerClamp) lowerClamp=prevGuess;
            price.Close=(upperClamp.Value+lowerClamp.Value)/2.00;
            prevGuess=price.Close;
            iterations++;
          }
        }
        gainLoss=portfolioTrades.GetGainLoss(price);
      }
      return price;
    }
    public static bool IsZero(double? value)
    {
      if(null==value)
      {
        return true;
      }
      int intValue=(int)(value*10000.00);
      if(0==intValue) return true;
      return false;
    }
  }
}
