using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Windows.Media;
using System.Windows.Input;
using System.Threading.Tasks;
using System.Windows;
using MarketData;
using MarketData.Numerical;
using MarketData.Utils;
using MarketData.MarketDataModel;
using MarketData.Generator;
using MarketData.DataAccess;
using TradeBlotter.DataAccess;
using TradeBlotter.Command;
using TradeBlotter.Model;
using Microsoft.Research.DynamicDataDisplay.DataSources;
using TradeBlotter.UIUtils;
using TradeBlotter.Cache;

namespace TradeBlotter.ViewModels
{
  public class StickerPriceViewModel : WorkspaceViewModel
  {
		private RelayCommand copyToClipboardCommand;
    private RelayCommand refreshCommand;
    private List<String> symbols;
    private List<String> watchLists;
    private String selectedWatchList;
    private String selectedSymbol;
    private Price price = null;
    private String companyName;
    private ObservableCollection<ReturnItem> bvps = null;
    private bool busyIndicator = false;
    private Prices pricesIndex90 = null;
    private Prices pricesIndex720 = null;
    private Valuation valuation = null;
    private double selectedRequiredReturn = .15;
    private double bvpsOverride=double.NaN;

    public StickerPriceViewModel()
    {
      base.DisplayName = "Sticker Price";
      watchLists = WatchListDA.GetWatchLists();
      watchLists.Insert(0, Constants.CONST_ALL);
      selectedWatchList = watchLists.Find(x => x.Equals("Valuations"));
      symbols = WatchListDA.GetWatchList(selectedWatchList);
      selectedSymbol = null;
      pricesIndex90 = PricingDA.GetPrices("SPY", 90);
      pricesIndex720 = PricingDA.GetPrices("SPY", 720);
      bvps = new ObservableCollection<ReturnItem>();
      PropertyChanged += OnStickerPriceViewModelPropertyChanged;
      base.OnPropertyChanged("SelectedSymbol");
      base.OnPropertyChanged("RequiredReturn");
    }
    // ******************************************************************************************** P E R S I S T E N C E ********************************************************************************************
    public override bool CanPersist()
    {
      return true;
    }
    public override SaveParameters GetSaveParameters()
    {
      SaveParameters saveParams = new SaveParameters();
      if (null == selectedSymbol) return null;
      saveParams.Add(new KeyValuePair<String, String>("Type", GetType().Namespace + "." + GetType().Name));
      saveParams.Add(new KeyValuePair<String, String>("SelectedSymbol", selectedSymbol));
      saveParams.Add(new KeyValuePair<String, String>("SelectedWatchList", selectedWatchList));
      return saveParams;
    }
    public override void SetSaveParameters(SaveParameters saveParameters)
    {
      try
      {
        selectedSymbol = (from KeyValuePair<String, String> item in saveParameters where item.Key.Equals("SelectedSymbol") select item).FirstOrDefault().Value;
        selectedWatchList = (from KeyValuePair<String, String> item in saveParameters where item.Key.Equals("SelectedWatchList") select item).FirstOrDefault().Value;
        Referer=saveParameters.Referer;
        base.OnPropertyChanged("SelectedWatchList");
        base.OnPropertyChanged("SelectedSymbol");
      }
      catch (Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Exception:{0}",exception.ToString()));
      }
    }
    // ******************************************************************************************************************************************************
    public bool BusyIndicator
    {
      get { return busyIndicator; }
      set
      {
        busyIndicator = value;
        base.OnPropertyChanged("BusyIndicator");
      }
    }
    public ObservableCollection<ReturnItem> AllBVPS
    {
      get {return bvps ;}
      set 
      {
        bvps=value ;
        base.OnPropertyChanged("AllBVPS");
      }
    }
    private void OnStickerPriceViewModelPropertyChanged(object sender, PropertyChangedEventArgs eventArgs)
    {
      if (eventArgs.PropertyName.Equals("SelectedSymbol"))
      {
        base.DisplayName = "Sticker Price(" + selectedSymbol + ")";
        base.OnPropertyChanged("DisplayName");
        HandleSelectedSymbol();
      }
      else if (eventArgs.PropertyName.Equals("SelectedWatchList"))
      {
        HandleSelectedWatchList();
      }
      else if(eventArgs.PropertyName.Equals("AverageGrowth"))
      {
        HandleSelectedBVPS();
      }
    }
    private void HandleSelectedBVPS()
    {
      BusyIndicator = true;
      Task workerTask = Task.Factory.StartNew(() =>
      {
        if (null != selectedSymbol)
        {
          if(double.NaN.Equals(bvpsOverride))return;
          companyName=PricingDA.GetNameForSymbol(selectedSymbol);
          price=PricingDA.GetPrice(selectedSymbol);
          if(!double.NaN.Equals(bvpsOverride))valuation = ValuationGenerator.GenerateValuationWithOverride(selectedSymbol, pricesIndex90, pricesIndex720,bvpsOverride, null, new ValuationGenerator.OnErrorItemHandler(OnErrorItemHandler));
        }
      });
      workerTask.ContinueWith((continuation) =>
      {
        BusyIndicator = false;
        base.OnPropertyChanged("AllBVPS");
        base.OnPropertyChanged("EPS");
        base.OnPropertyChanged("PE");
        base.OnPropertyChanged("LowPE");
        base.OnPropertyChanged("TrailingPE");
        base.OnPropertyChanged("AvgLowTrailing");
        base.OnPropertyChanged("CurrentEstimatedPrice");
        base.OnPropertyChanged("PriceEstimate10Y");
        base.OnPropertyChanged("TodaysPriceForRequiredReturn");
        base.OnPropertyChanged("LatestPrice");
        base.OnPropertyChanged("PricingDate");
        base.OnPropertyChanged("MOS");
        base.OnPropertyChanged("MOSBackground");
        base.OnPropertyChanged("PEBackground");
        base.OnPropertyChanged("MOS80");
        base.OnPropertyChanged("MOS80Background");
        base.OnPropertyChanged("RGV");
        base.OnPropertyChanged("BVPS");
        base.OnPropertyChanged("PBVPS");
        base.OnPropertyChanged("IntrinsicValue");
        base.OnPropertyChanged("FundamentalValue");
        base.OnPropertyChanged("NetCurrentAssetValuePerShare");
        base.OnPropertyChanged("NetCurrentAssetValuePerShareBackground");
        base.OnPropertyChanged("DebtToEquity");
        base.OnPropertyChanged("DebtToEquityBackground");
        base.OnPropertyChanged("DividendYield");
        base.OnPropertyChanged("Title");
        base.OnPropertyChanged("PCF");
        base.OnPropertyChanged("SharesOutstanding");
        base.OnPropertyChanged("Beta");
        base.OnPropertyChanged("EarningsYield");
        base.OnPropertyChanged("EBIT");
        base.OnPropertyChanged("EnterpriseValue");
      });
    }
    private void HandleSelectedSymbol()
    {
      BusyIndicator = true;
      Task workerTask = Task.Factory.StartNew(() =>
      {
        if (null != selectedSymbol)
        {
          companyName=PricingDA.GetNameForSymbol(selectedSymbol);
          price=PricingDA.GetPrice(selectedSymbol);
          valuation = ValuationGenerator.GenerateValuation(selectedSymbol, pricesIndex90, pricesIndex720, null, new ValuationGenerator.OnErrorItemHandler(OnErrorItemHandler));
          bvps = new ObservableCollection<ReturnItem>();
          for (int index = 0; index < valuation.BVPSItems.Count; index++)
          {
            ReturnItem returnItem = valuation.BVPSItems[index];
            bvps.Add(returnItem);
          }
        }
      });
      workerTask.ContinueWith((continuation) =>
      {
        BusyIndicator = false;
        base.OnPropertyChanged("AllBVPS");
        base.OnPropertyChanged("EPS");
        base.OnPropertyChanged("PE");
        base.OnPropertyChanged("LowPE");
        base.OnPropertyChanged("TrailingPE");
        base.OnPropertyChanged("AvgLowTrailing");
        base.OnPropertyChanged("CurrentEstimatedPrice");
        base.OnPropertyChanged("PriceEstimate10Y");
        base.OnPropertyChanged("TodaysPriceForRequiredReturn");
        base.OnPropertyChanged("LatestPrice");
        base.OnPropertyChanged("PricingDate");
        base.OnPropertyChanged("MOS");
        base.OnPropertyChanged("MOSBackground");
        base.OnPropertyChanged("PEBackground");
        base.OnPropertyChanged("MOS80");
        base.OnPropertyChanged("MOS80Background");
        base.OnPropertyChanged("RGV");
        base.OnPropertyChanged("BVPS");
        base.OnPropertyChanged("PBVPS");
        base.OnPropertyChanged("IntrinsicValue");
        base.OnPropertyChanged("FundamentalValue");
        base.OnPropertyChanged("NetCurrentAssetValuePerShare");
        base.OnPropertyChanged("NetCurrentAssetValuePerShareBackground");
        base.OnPropertyChanged("AverageGrowth");
        base.OnPropertyChanged("DebtToEquity");
        base.OnPropertyChanged("DebtToEquityBackground");
        base.OnPropertyChanged("DividendYield");
        base.OnPropertyChanged("PExPBVPS");
        base.OnPropertyChanged("Title");
        base.OnPropertyChanged("PCF");
        base.OnPropertyChanged("SharesOutstanding");
        base.OnPropertyChanged("Beta");
        base.OnPropertyChanged("EarningsYield");
        base.OnPropertyChanged("EBIT");
        base.OnPropertyChanged("EnterpriseValue");
      });
    }
    public void OnErrorItemHandler(String symbol, String message)
    {
    }
    private void HandleSelectedWatchList()
    {
//      if (selectedWatchList.Equals(Constants.CONST_ALL)) symbols = PricingDA.GetSymbols();
      if (selectedWatchList.Equals(Constants.CONST_ALL)) symbols = SymbolCache.GetInstance().GetSymbols();
      else
      {
        symbols = WatchListDA.GetWatchList(selectedWatchList);
      }
      base.OnPropertyChanged("Symbols");
    }
// *************************************************************************** C O L O R  S C H E M E  ***************************************************************
    public Brush DebtToEquityBackground
    {
      get
      {
        if (null == valuation) return null;
        if(double.IsNaN(valuation.DebtToEquity)||double.IsInfinity(valuation.DebtToEquity))return BrushCollection.GetContextBrush(BrushCollection.BrushColor.LightGreen); 
        if (valuation.DebtToEquity>.50 ) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
        return BrushCollection.GetContextBrush(BrushCollection.BrushColor.LightGreen); 
      }
    }
    public Brush PExPBVPSBackground
    {
      get
      {
        if(null==valuation)return null;
        if(double.IsNaN(valuation.PExPBVPS)||double.IsInfinity(valuation.PExPBVPS))return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
        if(valuation.PExPBVPS>22.5)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
        return BrushCollection.GetContextBrush(BrushCollection.BrushColor.LightGreen);
      }
    }
    public Brush PEBackground
    {
      get
      {
        if(null==valuation)return null;
        if(valuation.PE>15 && valuation.PE<25)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Yellow);
        if(valuation.PE>=25)BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
        return BrushCollection.GetContextBrush(BrushCollection.BrushColor.LightGreen);
      }
    }
    public Brush MOSBackground
    {
      get
      {
        if(null==valuation || null==price)return null;
        if(price.Close>valuation.MOS)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
        return BrushCollection.GetContextBrush(BrushCollection.BrushColor.LightGreen);
      }
    }

    public Brush MOS80Background
    {
      get
      {
        if (null == valuation || null == price) return null;
        if (price.Close > valuation.MOS80) return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
        return BrushCollection.GetContextBrush(BrushCollection.BrushColor.LightGreen);
      }
    }
    public Brush NetCurrentAssetValuePerShareBackground
    {
      get
      {
        if (null == valuation || null == price) return null;
        if (price.Close*.67 < valuation.NetCurrentAssetValuePerShare)return BrushCollection.GetContextBrush(BrushCollection.BrushColor.LightGreen);
        return BrushCollection.GetContextBrush(BrushCollection.BrushColor.Red);
      }
    }
// *****************************************************************************************************************************************************************
    public override String Title
    {
      get 
      {
        if (null != companyName && null!=selectedSymbol) return "Sticker Price - (" + selectedSymbol+") "+companyName;
        return "Sticker Price";
      }
    }
    public String PCF
    {
      get
      {
        return valuation == null ? Constants.CONST_DASHES : Utility.FormatNumber(valuation.PCF(price.Close),2);
      }
    }
    public String SharesOutstanding
    {
      get
      {
        return valuation == null ? Constants.CONST_DASHES : Utility.FormatNumber(valuation.SharesOutstanding,0,true);
      }
    }
    public double RequiredReturn
    {
      get
      {
        return selectedRequiredReturn;
      }
      set
      {
        selectedRequiredReturn = value;
        base.OnPropertyChanged("SelectedRequiredReturn");
      }
    }
    public String AverageGrowth
    {
      get
      {
        if(!double.NaN.Equals(bvpsOverride))return Utility.FormatPercent(bvpsOverride);
        return valuation == null ? Constants.CONST_DASHES : Utility.FormatPercent(valuation.AverageBVPSGrowth);
      }
      set
      {
        bvpsOverride=Utility.ParsePercent(value);
        base.OnPropertyChanged("AverageGrowth");
      }
    }
    public String DividendYield
    {
      get
      {
        if(null==price)return valuation == null ? Constants.CONST_DASHES : Utility.FormatPercent(valuation.DividendYield);
        else return Utility.FormatPercent(DividendHistoryGenerator.GetDividendYield(selectedSymbol,price));
      }
    }
    public String EarningsYield
    {
      get
      {
        if (null == valuation) return Constants.CONST_DASHES;
        if (!double.IsNaN(valuation.EarningsYield)) return Utility.FormatPercent(valuation.EarningsYield);
        if (!double.IsNaN(valuation.PE) && !double.IsNaN(valuation.LatestPrice) && 0.00 != valuation.LatestPrice) return Utility.FormatPercent(valuation.PE / valuation.LatestPrice);
        return Constants.CONST_DASHES;
      }
    }
    public String EBIT
    {
      get
      {
        if (null == valuation || double.IsNaN(valuation.EBIT)) return Constants.CONST_DASHES;
        return Utility.FormatCurrency(valuation.EBIT);
      }
    }
    public String EnterpriseValue
    {
      get
      {
        if (null == valuation || double.IsNaN(valuation.EnterpriseValue)) return Constants.CONST_DASHES;
        return Utility.FormatCurrency(valuation.EnterpriseValue);
      }
    }
    public String Beta
    {
      get
      {
        return valuation == null || double.IsNaN(valuation.Beta720) || 0 == valuation.Beta720 ? Constants.CONST_DASHES : Utility.FormatNumber(valuation.Beta720,2);
      }
    }
    public String SharesOustanding
    {
      get
      {
        return valuation == null || double.IsNaN(valuation.SharesOutstanding) || 0==valuation.SharesOutstanding? Constants.CONST_DASHES : Utility.FormatNumber(valuation.LatestPrice/(valuation.OperatingCashflow/valuation.SharesOutstanding));
      }
    }
    public String DebtToEquity
    {
      get
      {
        return valuation == null ? Constants.CONST_DASHES : Utility.FormatNumber(valuation.DebtToEquity,2);
      }
    }
    public String PExPBVPS
    {
      get
      {
        return valuation == null ? Constants.CONST_DASHES : Utility.FormatNumber(valuation.PExPBVPS,2);
      }
    }
    public String LowPE
    {
      get
      {
        return valuation == null ? Constants.CONST_DASHES : Utility.FormatCurrency(valuation.LowPE);
      }
    }
    public String TrailingPE
    {
      get
      {
        return valuation == null ? Constants.CONST_DASHES : Utility.FormatCurrency(valuation.TrailingPE);
      }
    }
    public String AvgLowTrailing
    {
      get
      {
        return valuation == null ? Constants.CONST_DASHES : Utility.FormatCurrency(valuation.AverageLowTrailing);
      }
    }
    public String CurrentEstimatedPrice
    {
      get
      {
        return valuation == null ? Constants.CONST_DASHES : Utility.FormatCurrency(valuation.CurrentStockEstimatePrice);
      }
    }
    public String PriceEstimate10Y
    {
      get
      {
        return valuation == null ? Constants.CONST_DASHES : Utility.FormatCurrency(valuation.PriceEstimate10Y);
      }
    }
    public String TodaysPriceForRequiredReturn
    {
      get
      {
        return valuation == null ? Constants.CONST_DASHES : Utility.FormatCurrency(valuation.TodaysPriceForRequiredReturn);
      }
    }
    public String PE
    {
      get
      {
        return valuation == null ? Constants.CONST_DASHES : Utility.FormatNumber(valuation.PE,2);
      }
      set
      {
        if(null==valuation)return;
        if(null==price)price=new Price();
        double modifiedPE=Utility.ParseCurrency(value);
        if(modifiedPE.Equals(valuation.PE))return;
        valuation.PE=modifiedPE;
        if(null!=valuation.EPS&&0!=valuation.EPS)price.Close=valuation.LatestPrice=modifiedPE*valuation.EPS;
        base.OnPropertyChanged("PE");
        base.OnPropertyChanged("LatestPrice");
        base.OnPropertyChanged("PEBackground");
        base.OnPropertyChanged("DividendYield");
      }
    }

    public String EPS
    {
      get 
      {
        return valuation == null ? Constants.CONST_DASHES : Utility.FormatCurrency(valuation.EPS);
      }
      set
      {
        if(null==valuation)return;
        double modifiedEPS=Utility.ParseCurrency(value);
        if(modifiedEPS.Equals(valuation.EPS))return;
        valuation.EPS=modifiedEPS;
        if(null!=valuation.EPS&&0!=valuation.EPS)valuation.PE=valuation.LatestPrice/valuation.EPS;
        base.OnPropertyChanged("EPS");
        base.OnPropertyChanged("PE");
        base.OnPropertyChanged("PExPBVPS");
        base.OnPropertyChanged("LatestPrice");
        base.OnPropertyChanged("PEBackground");
        base.OnPropertyChanged("PExPBVPSBackground");
      }
    }
    public String LatestPrice
    {
      get
      {
        return price == null ? Constants.CONST_DASHES : Utility.FormatCurrency(price.Close);
      }
      set
      {
        if(null==valuation)return;
        if(null==price)price=new Price();
        double modifiedPrice=Utility.ParseCurrency(value);
        if(modifiedPrice.Equals(price.Close))return;
        price.Close=modifiedPrice;
        valuation.LatestPrice=price.Close;
        valuation.DividendYield=DividendHistoryGenerator.GetDividendYield(price.Symbol,price);
        if(null!=valuation.EPS&&0!=valuation.EPS&&!double.IsNaN(valuation.EPS))valuation.PE=valuation.LatestPrice/valuation.EPS;
        if(null!=valuation.BVPS&&0!=valuation.BVPS)valuation.PBVPS=valuation.LatestPrice/valuation.BVPS;
        base.OnPropertyChanged("DividendYield");
        base.OnPropertyChanged("LatestPrice");
        base.OnPropertyChanged("PBVPS");
        base.OnPropertyChanged("PE");
        base.OnPropertyChanged("PExPBVPS");
        base.OnPropertyChanged("PEBackground");
        base.OnPropertyChanged("PExPBVPSBackground");
        base.OnPropertyChanged("PCF");
      }
    }
    public String PricingDate
    {
      get
      {
        return price == null ? Constants.CONST_DASHES : Utility.DateTimeToStringMMHDDHYYYY(price.Date);
      }
    }
    public String MOS
    {
      get
      {
        return valuation == null ? Constants.CONST_DASHES : Utility.FormatCurrency(valuation.MOS);
      }
    }
// *****************************************************************************************************************************************************************
// *****************************************************************************************************************************************************************
    public String MOS80
    {
      get
      {
        return valuation == null ? Constants.CONST_DASHES : Utility.FormatCurrency(valuation.MOS80);
      }
    }
		public String BVPS
		{
			get
			{
        return valuation == null ? Constants.CONST_DASHES : Utility.FormatNumber(valuation.BVPS, 2);
			}
		}
		public String PBVPS
		{
			get
			{
        return valuation == null ? Constants.CONST_DASHES : Utility.FormatNumber(valuation.PBVPS, 2);
			}
		}
    public String RGV
    {
      get
      {
        return valuation == null ? Constants.CONST_DASHES : Utility.FormatNumber(valuation.RGV, 2);
      }
    }
    public String IntrinsicValue
    {
      get
      {
        return valuation == null ? Constants.CONST_DASHES : Utility.FormatCurrency(valuation.IntrinsicValue);
      }
    }
    public String FundamentalValue
    {
      get
      {
        return valuation == null ? Constants.CONST_DASHES : Utility.FormatCurrency(valuation.FundamentalValue);
      }
    }
    public String NetCurrentAssetValuePerShare
    {
      get
      {
        return valuation == null ? Constants.CONST_DASHES : Utility.FormatCurrency(valuation.NetCurrentAssetValuePerShare);
      }
    }
    public List<String> Symbols
    {
      get
      {
        return symbols;
      }
    }
    public String SelectedSymbol
    {
      get
      {
        return selectedSymbol;
      }
      set
      {
        if (value == selectedSymbol || String.IsNullOrEmpty(value)) return;
        selectedSymbol = value;
        base.OnPropertyChanged("SelectedSymbol");
      }
    }
    public List<String> WatchListNames
    {
      get
      {
        return watchLists;
      }
      set { ;}
    }
    public String SelectedWatchList
    {
      get { return selectedWatchList; }
      set { selectedWatchList = value; base.OnPropertyChanged("SelectedWatchList"); }
    }
    public ICommand RefreshCommand
    {
      get
      {
        if (refreshCommand == null)
        {
          refreshCommand = new RelayCommand(param => this.Refresh(), param => {return true;});
        }
        return refreshCommand;
      }
    }
    public void Refresh()
    {
      bvpsOverride=double.NaN;
      base.OnPropertyChanged("SelectedSymbol");
    }
    public ICommand CopyToClipboardCommand
    {
      get
      {
        if (copyToClipboardCommand == null)
        {
          copyToClipboardCommand = new RelayCommand(param => this.CopyToClipboard(), param => this.CanCopyToClipboard);
        }
        return copyToClipboardCommand;
      }
    }
		public void CopyToClipboard()
		{
			StringBuilder sb=new StringBuilder();
			
			sb.Append("Date,BVPS,Return").Append("\r\n");;
			for(int index=0;index<bvps.Count;index++)
			{
				ReturnItem returnItem=bvps[index];
				sb.Append(Utility.DateTimeToStringMMHDDHYYYY(returnItem.Date)).Append(",").Append(Utility.FormatCurrency(returnItem.Value)).Append(",").Append(Utility.FormatPercent(returnItem.Return));
				if(index<bvps.Count-1)sb.Append("\r\n");
			}
			Clipboard.SetData("Text",sb.ToString());
		}
		public bool CanCopyToClipboard
		{
			get
			{
				if(null==bvps||0==bvps.Count)return false;
				return true;
			}
		}
  }
}

