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

namespace TradeBlotter.ViewModels
{
  public class GainLossViewModel : WorkspaceViewModel
  {
    private enum Tasks{Accounts,SelectedSymbol,SelectedAccounts,LeastSquaresFit,UseDividends};
    private Dictionary<Tasks,Semaphore> semaphorePool=new Dictionary<Tasks,Semaphore>();
    private ObservableCollection<GainLossSummaryItem> gainLossSummaryItemCollection=new ObservableCollection<GainLossSummaryItem>();
    private ITotalGainLossGenerator gainLossGenerator=null;
    private IActiveGainLossGenerator activeGainLossGenerator=null;
    private ObservableCollection<GainLossCompoundModel> gainLossCompoundModelCollection=new ObservableCollection<GainLossCompoundModel>();  
    private GainLossCompoundModelCollection gainLossModelCollection=null;
    private GainLossCompoundModel selectedGainLossCompoundItem=null;
    private GainLossSummaryItem selectedGainLossSummaryItem=null;
    private String selectedSymbol =Constants.CONST_ALL;
    private TotalGainLossCollection totalGainLoss=null;  // total gain/loss
    private PortfolioTrades portfolioTrades = null;
    private String selectedCompanyName;
    private bool suspendUpdate=false;
    private String selectedAccounts;
    private List<String> accounts=null;
    private DateTime latestMarketDate=Utility.Epoch;
// RelayCommands
    private RelayCommand refreshCommand=null;
    private RelayCommand toggleReturnOrPercentCommand=null;   
    private RelayCommand toggleActiveOrTotalCommand=null;   
// RelayCommand for menu 
    private RelayCommand saveCommand=null;
    private RelayCommand stochasticsCommand=null;
    private RelayCommand relativeStrengthCommand=null;
    private RelayCommand macdCommand=null;
    private RelayCommand movingAverageCommand;
    private RelayCommand bollingerBandCommand=null;
    private RelayCommand priceHistoryCommand=null;
		private RelayCommand stickerValuationCommand=null;
		private RelayCommand dcfValuationCommand=null;
    private RelayCommand displayAnalystRatingsCommand=null;
    private RelayCommand displayHeadlinesCommand=null;
    private RelayCommand rollPriceForwardCommand=null;
    private RelayCommand dividendHistoryCommand=null;
    private RelayCommand displayHistoricalCommand=null;
    private RelayCommand proformaDividendRiskCommand = null;
//
    private ObservableCollection<String> symbols = new ObservableCollection<String>();
    private bool busyIndicator = false;
    private bool isLegendVisible = true;
    private bool useLeastSquaresFit=true; 
    private bool useCumulativeGainLoss=true;
    private Boolean showAsGainLoss = true;
    private Boolean showActiveGainLoss=false;    // show the total gain/loss graph in the view by default
    private Boolean includeDividends=false;  // include dividends in the calculation of TOTAL gain/loss, ACTIVE gain/loss never includes dividends
    private String busyContent = "Generating Gain/Loss...";

    public GainLossViewModel()
    {
      latestMarketDate=PremarketDA.GetLatestMarketDate();
      semaphorePool.Add(Tasks.SelectedSymbol,new Semaphore(1,1));
      semaphorePool.Add(Tasks.SelectedAccounts,new Semaphore(1,1));
      semaphorePool.Add(Tasks.LeastSquaresFit,new Semaphore(1,1));
      semaphorePool.Add(Tasks.Accounts,new Semaphore(1,1));
      semaphorePool.Add(Tasks.UseDividends,new Semaphore(1,1));
      base.DisplayName = "GainLossView";
      PropertyChanged += OnGainLossViewModelPropertyChanged;
      BusyIndicator = true;
			suspendUpdate=true;
      Task workerTask = Task.Factory.StartNew(() =>
      {
        semaphorePool[Tasks.Accounts].WaitOne();
        portfolioTrades = PortfolioDA.GetTrades();
        if(null!=portfolioTrades&&0!=portfolioTrades.Count)
        {
          accounts = portfolioTrades.Accounts;
        }
      });
      workerTask.ContinueWith((continuation) =>
      {
        BusyIndicator = false;
        SelectedAccounts=AccountsToString(accounts);
				suspendUpdate=false;
        SetSymbols();
        semaphorePool[Tasks.Accounts].Release();
      });
    }
    public override SaveParameters GetSaveParameters()
    {
      return null;
    }
    public override void SetSaveParameters(SaveParameters saveParameters)
    {
    }
    public override bool CanPersist()
    {
      return false;
    }
    public bool BusyIndicator
    {
      get { return busyIndicator; }
      set
      {
        busyIndicator = value;
        base.OnPropertyChanged("BusyIndicator");
      }
    }
    public String BusyContent
    {
      get { return busyContent; }
      set
      {
        busyContent = value;
        base.OnPropertyChanged("BusyContent");
      }
    }
    private void OnGainLossViewModelPropertyChanged(object sender, PropertyChangedEventArgs eventArgs)
    {
      if (eventArgs.PropertyName.Equals("SelectedSymbol"))HandleSelectedSymbol();
      else if (eventArgs.PropertyName.Equals("SelectedAccounts"))HandleSelectedAccounts();
      else if (eventArgs.PropertyName.Equals("LeastSquaresFit"))HandleLeastSquaresFit();
      else if (eventArgs.PropertyName.Equals("SelectedGainLossCompoundItem"))HandleSelectedGainLossCompoundItem();
      else if(eventArgs.PropertyName.Equals("CheckBoxUseCumulativeReturns")) HandleCheckBoxUseCumulativeReturns();
    }
    public void HandleCheckBoxUseCumulativeReturns()
    {
      gainLossGenerator=null;
      activeGainLossGenerator=null;
      base.OnPropertyChanged("SelectedSymbol");
    }
    public void HandleSelectedGainLossCompoundItem()
    {
      if(null==selectedGainLossCompoundItem)return;
      BusyIndicator = true;
      Task workerTask = Task.Factory.StartNew(() =>
      {
        DateTime selectedDate=selectedGainLossCompoundItem.Date;
        PortfolioTrades tradesOnOrBefore=portfolioTrades.GetTradesOnOrBefore(selectedDate);
        GainLossSummaryItemCollection gainLossSummaryItems=new GainLossSummaryItemCollection(tradesOnOrBefore,gainLossGenerator,activeGainLossGenerator,selectedDate);
        gainLossSummaryItemCollection=new ObservableCollection<GainLossSummaryItem>(gainLossSummaryItems);
      });
      workerTask.ContinueWith((continuation) =>
      {
        BusyIndicator = false;
        base.OnPropertyChanged("GainLossSummaryItemCollection");
      });
    }
    public void InstantiateGenerators()
    {
      if(null==gainLossGenerator)
      {
        if(useCumulativeGainLoss)gainLossGenerator=new GainLossGeneratorCum();
        else gainLossGenerator=new GainLossGenerator();
      }
      if(null==activeGainLossGenerator) activeGainLossGenerator=new ActiveGainLossGenerator();
    }
    public void HandleLeastSquaresFit()
    {
      try                                                                                             
      {
        semaphorePool[Tasks.LeastSquaresFit].WaitOne();
        base.OnPropertyChanged("LeastSquares");
      }
      finally
      {
        semaphorePool[Tasks.LeastSquaresFit].Release();
      }
    }
    public void HandleSelectedAccounts()
    {
      try
      {
        semaphorePool[Tasks.SelectedAccounts].WaitOne();
        if(suspendUpdate)return;
        MDTrace.WriteLine(String.Format("[GainLossViewModel::OnGainLossViewModelPropertyChanged]SelectedAccounts '{0}'",selectedAccounts));
        portfolioTrades = PortfolioDA.GetTradesForAccounts(ParseAccounts(selectedAccounts));
        SetSymbols();
      }
      finally
      {
        semaphorePool[Tasks.SelectedAccounts].Release();
      }
    }
    public void HandleSelectedSymbol()
    {
      try
      {
        semaphorePool[Tasks.SelectedSymbol].WaitOne();
        gainLossCompoundModelCollection=null;
        gainLossSummaryItemCollection=null;
        if(suspendUpdate)return;
        if (null == selectedSymbol||"".Equals(selectedAccounts))
        {
          UpdateProperties();
          return;
        }
        MDTrace.WriteLine(String.Format("[GainLossViewModel::OnGainLossViewModelPropertyChanged]SelectedSymbol '{0}'",selectedSymbol));
        BusyIndicator = true;
        Task workerTask = Task.Factory.StartNew(() =>
        {
          DividendPayments dividendPayments=null;
          if(Constants.CONST_ALL.Equals(selectedSymbol))
          {
            portfolioTrades = PortfolioDA.GetTrades();
            if(includeDividends)dividendPayments=DividendPaymentDA.GetDividendPayments();
            selectedCompanyName="";
          }
          else 
          {
            portfolioTrades = PortfolioDA.GetTrades(selectedSymbol);
            if(includeDividends)dividendPayments=DividendPaymentDA.GetDividendPaymentsForSymbol(selectedSymbol);
            selectedCompanyName=PricingDA.GetNameForSymbol(selectedSymbol);
          }
          if(null!=portfolioTrades&&0!=portfolioTrades.Count)
          {
            accounts = portfolioTrades.Accounts;
          }
          portfolioTrades=portfolioTrades.FilterAccount(ParseAccounts(selectedAccounts));
          if(null!=dividendPayments)dividendPayments=dividendPayments.FilterAccounts(selectedAccounts);

// check the TotalGainLoss generator and build appropriately                                
          InstantiateGenerators();
          LocalPriceCache.GetInstance().Refresh();
          GainLossCollection gainLoss = null; 
          gainLoss=activeGainLossGenerator.GenerateGainLoss(portfolioTrades);  // gainLoss contains the gain/loss from active positions.  Never includes dividends .. just positions
// Call the appropriate TotalGainLoss method depending on whether we should include dividends or not.
          if(includeDividends)totalGainLoss=gainLossGenerator.GenerateTotalGainLossWithDividends(portfolioTrades,dividendPayments);  
          else totalGainLoss=gainLossGenerator.GenerateTotalGainLoss(portfolioTrades);  

          gainLossModelCollection=null;
          gainLossModelCollection=new GainLossCompoundModelCollection(gainLoss,totalGainLoss);
          if(null!=gainLossModelCollection)
          {
            gainLossModelCollection.Sort(new SortGainLossCompoundModelYearDescendingOrder());
            gainLossCompoundModelCollection=new ObservableCollection<GainLossCompoundModel>(gainLossModelCollection);
          }
          GainLossSummaryItemCollection gainLossSummaryItems=new GainLossSummaryItemCollection(portfolioTrades,gainLossGenerator,activeGainLossGenerator);
          gainLossSummaryItemCollection=new ObservableCollection<GainLossSummaryItem>(gainLossSummaryItems);
        });
        workerTask.ContinueWith((continuation) =>
        {
          BusyIndicator = false;
          UpdateProperties();
        });
      }
      finally
      {
        semaphorePool[Tasks.SelectedSymbol].Release();
      }
    }
    public void UpdateProperties()
    {
      base.OnPropertyChanged("Accounts");
      base.OnPropertyChanged("Data");
      base.OnPropertyChanged("MA21");
      base.OnPropertyChanged("MA55");
      base.OnPropertyChanged("MA90");
      base.OnPropertyChanged("Title");
      base.OnPropertyChanged("GainLossCompoundModelCollection");
      base.OnPropertyChanged("GainLossSummaryItemCollection");
      base.OnPropertyChanged("LeastSquares");
      base.OnPropertyChanged("LeastSquaresTitle");
    }                                                                                                       
    public void SetSymbols()
    {
      symbols = new ObservableCollection<String>();
      symbols.Add(Constants.CONST_ALL);
      List<String> tradedSymbols = portfolioTrades.Symbols;
      foreach (String symbol in tradedSymbols) symbols.Add(symbol);
      base.OnPropertyChanged("Symbols");
      SelectedSymbol=symbols[0];
    }
    public ObservableCollection<String> Symbols
    {
      get
      {
        return symbols;
      }
      set
      {  
        symbols = value;                                               
        base.OnPropertyChanged("Symbols");
      }
    }
    public String SelectedSymbol
    {
      get
      {
        MDTrace.WriteLine(String.Format("[GainLossViewModel::SelectedSymbol] Get {0}",selectedSymbol));
        return selectedSymbol; 
      }
      set 
      {
        MDTrace.WriteLine(String.Format("[GainLossViewModel::SelectedSymbol] Set {0}",selectedSymbol)); 
        selectedSymbol = value; 
        base.OnPropertyChanged("SelectedSymbol");                                                        
      }
    }
    public List<String> Accounts
    {
      get
      {
        semaphorePool[Tasks.Accounts].WaitOne();
        MDTrace.WriteLine(String.Format("[GainLossViewModel::Accounts] {0}",accounts==null?"null":"non-null"));
        semaphorePool[Tasks.Accounts].Release();
        return accounts;
      }                                                                                               
    }
    public String SelectedAccounts
    {
      get
      {
        MDTrace.WriteLine(String.Format("[GainLossViewModel:SelectedAccounts]Get '{0}'",selectedAccounts));
        return selectedAccounts; 
      }
      set 
      { 
        MDTrace.WriteLine(String.Format("[GainLossViewModel:SelectedAccounts]Set '{0}'",value));
        selectedAccounts = value; 
        base.OnPropertyChanged("SelectedAccounts");
        portfolioTrades = PortfolioDA.GetTradesForAccounts(ParseAccounts(selectedAccounts));
				if(null==portfolioTrades)return;
				accounts = portfolioTrades.Accounts;
 				SetSymbols();
      }
    }
    private static String AccountsToString(List<String> accounts)
    {
      StringBuilder sb=new StringBuilder();
      for(int index=0;index<accounts.Count;index++)
      {
        sb.Append(accounts[index]);
        if(index<accounts.Count-1)sb.Append(",");
      }
      return sb.ToString();
    }
    private List<String> ParseAccounts(String strAccounts)
    {
      String[] accounts=strAccounts.Split(','); 
      return accounts.ToList();
    }
// *************************************************************************************************************************************************************************
// *************************************************************************** L I N E   G R A P H  D A T A  ***************************************************************
// *************************************************************************************************************************************************************************
    public CompositeDataSource Data
    {
      get
      {
        if (null == gainLossModelCollection) return null;
        CompositeDataSource compositeDataSource=null;
        if(showActiveGainLoss)compositeDataSource = GainLossModel.GainLoss(gainLossModelCollection,showAsGainLoss);
        else compositeDataSource = GainLossModel.TotalGainLoss(gainLossModelCollection,showAsGainLoss);
        return compositeDataSource;
      }
    }
    public CompositeDataSource LeastSquares
    {
      get
      {
        if(!useLeastSquaresFit||null==gainLossModelCollection)return null;
        if(showActiveGainLoss)return GainLossModel.LeastSquares(gainLossModelCollection,showAsGainLoss);
        else return GainLossModel.TotalLeastSquares(gainLossModelCollection,showAsGainLoss);
      }
    }
    public CompositeDataSource MA21
    {
      get
      {
        if (null == gainLossModelCollection) return null;
        CompositeDataSource compositeDataSource = null;
        DMAValues dmaValues=null;
        if(showActiveGainLoss)
        {
          if(showAsGainLoss)dmaValues=MovingAverageGenerator.GenerateMovingAverage(gainLossModelCollection.DMAValuesActiveGainLoss,21);
          else dmaValues=MovingAverageGenerator.GenerateMovingAverage(gainLossModelCollection.DMAValuesActiveGainLossPercent,21);
          compositeDataSource = MovingAverageModel.CreateCompositeDataSource(dmaValues);
        }
        else
        {
          if(showAsGainLoss)dmaValues=MovingAverageGenerator.GenerateMovingAverage(gainLossModelCollection.DMAValuesTotalGainLoss,21);
          else dmaValues=MovingAverageGenerator.GenerateMovingAverage(gainLossModelCollection.DMAValuesTotalGainLossPercent,21);
          compositeDataSource = MovingAverageModel.CreateCompositeDataSource(dmaValues);
        }
        return compositeDataSource;
      }
    }
    public CompositeDataSource MA55
    {
      get
      {
        if (null == gainLossModelCollection) return null;
        CompositeDataSource compositeDataSource = null;
        DMAValues dmaValues=null;
        if(showActiveGainLoss)
        {
          if(showAsGainLoss)dmaValues=MovingAverageGenerator.GenerateMovingAverage(gainLossModelCollection.DMAValuesActiveGainLoss,55);
          else dmaValues=MovingAverageGenerator.GenerateMovingAverage(gainLossModelCollection.DMAValuesActiveGainLossPercent,55);
          compositeDataSource = MovingAverageModel.CreateCompositeDataSource(dmaValues);
        }
        else
        {
          if(showAsGainLoss)dmaValues=MovingAverageGenerator.GenerateMovingAverage(gainLossModelCollection.DMAValuesTotalGainLoss,55);
          else dmaValues=MovingAverageGenerator.GenerateMovingAverage(gainLossModelCollection.DMAValuesTotalGainLossPercent,55);
          compositeDataSource = MovingAverageModel.CreateCompositeDataSource(dmaValues);
        }
        return compositeDataSource;
      }
    }
    public CompositeDataSource MA90
    {
      get
      {
        if (null == gainLossModelCollection) return null;
        CompositeDataSource compositeDataSource = null;
        DMAValues dmaValues=null;
        if(showActiveGainLoss)
        {
          if(showAsGainLoss)dmaValues=MovingAverageGenerator.GenerateMovingAverage(gainLossModelCollection.DMAValuesActiveGainLoss,90);
          else dmaValues=MovingAverageGenerator.GenerateMovingAverage(gainLossModelCollection.DMAValuesActiveGainLossPercent,90);
          compositeDataSource = MovingAverageModel.CreateCompositeDataSource(dmaValues);
        }
        else
        {
          if(showAsGainLoss)dmaValues=MovingAverageGenerator.GenerateMovingAverage(gainLossModelCollection.DMAValuesTotalGainLoss,90);
          else dmaValues=MovingAverageGenerator.GenerateMovingAverage(gainLossModelCollection.DMAValuesTotalGainLossPercent,90);
          compositeDataSource = MovingAverageModel.CreateCompositeDataSource(dmaValues);
        }
        return compositeDataSource;
      }
    }
// ***********************************************************************************************************************************************************************************
// ****************************************************************************** C H E C K  B O X E S  ******************************************************************************
// ***********************************************************************************************************************************************************************************
    public Boolean CheckBoxLegendVisible
    {
      get
      {
        return isLegendVisible;
      }
      set
      {
        isLegendVisible = value;
        base.OnPropertyChanged("CheckBoxLegendVisible");
        base.OnPropertyChanged("LegendVisible");
      }
    }
    public Boolean CheckBoxIncludeDividends
    {
      get
      {
        return includeDividends;
      }
      set
      {
        includeDividends = value;
        base.OnPropertyChanged("CheckBoxIncludeDividends");
        base.OnPropertyChanged("SelectedSymbol");
      }
    }
    public Boolean CheckBoxUseCumulativeReturns
    {
      get
      {
        return useCumulativeGainLoss;
      }
      set
      {
        useCumulativeGainLoss=value;
        base.OnPropertyChanged("CheckBoxUseCumulativeReturns");
      }
    }
    public Boolean CheckBoxSuspendUpdate
    {
      get
      {
        return suspendUpdate;
      }
      set
      {
        suspendUpdate = value;
        base.OnPropertyChanged("CheckBoxSuspendUpdate");
        if(!suspendUpdate)base.OnPropertyChanged("SelectedSymbol");
      }
    }
    public String LeastSquaresTitle
    {
      get
      {
        if(null==gainLossModelCollection)return "LeastSquares";
        LeastSquaresResult leastSquaresResult=GainLossModel.LeastSquaresFit(gainLossModelCollection,showAsGainLoss);
        return "LeastSquares="+Utility.FormatNumber(leastSquaresResult.Slope*-1.00,2);       
      }
    }
    public Boolean LeastSquaresFit
    {
      get
      {
        return useLeastSquaresFit;
      }
      set
      {
        useLeastSquaresFit = value;
        base.OnPropertyChanged("LeastSquaresFit");
      }
    }
    public String LegendVisible
    {
      get
      {
        if (isLegendVisible) return "true";
        return "false";
      }
      set
      {
        isLegendVisible = Boolean.Parse(value);
        base.OnPropertyChanged("LegendVisible");
      }
    }
    public override String Title
    {
      get
      {
        if(null==gainLossModelCollection||0==gainLossModelCollection.Count)return "";
        StringBuilder sb = new StringBuilder();
        sb.Append(showActiveGainLoss?"Active":"Total").Append(" ");
        sb.Append("Gain/Loss ");
        if (showAsGainLoss) sb.Append("($)");
        else sb.Append("(%)");
        if (!Constants.CONST_ALL.Equals(selectedSymbol))sb.Append(" (").Append(selectedAccounts).Append(") ").Append(" - ").Append(selectedCompanyName).Append(" (").Append(selectedSymbol).Append(") ");
        else sb.Append(" (").Append(selectedAccounts).Append(") ").Append(" - ").Append(selectedCompanyName); 
        DateTime fromDate=gainLossModelCollection.Select(x => x.Date).Min();
        DateTime toDate = gainLossModelCollection.Select(x => x.Date).Max();
        sb.Append(" from ").Append(Utility.DateTimeToStringMMHDDHYYYY(fromDate));
        sb.Append(" Thru ").Append(Utility.DateTimeToStringMMHDDHYYYY(toDate));
        return sb.ToString();
      }
    }
    private void Refresh()
    {
      latestMarketDate = PremarketDA.GetLatestMarketDate();
      base.OnPropertyChanged("SelectedSymbol");
    }
    public ICommand RefreshCommand
    {
      get
      {
        if (refreshCommand == null)
        {
          refreshCommand = new RelayCommand(param => this.Refresh(), param => { return true;});
        }
        return refreshCommand;
      }
    }
// This is the button that controls the display in terms of percentages or dollar values
    public String PercentButtonText
    {
      get
      {
        if (!showAsGainLoss) return "Show $";
        else return "Show %";
      }
    }
    public ICommand ToggleReturnOrPercentCommand
    {
      get
      {
        if (toggleReturnOrPercentCommand == null)
        {
          toggleReturnOrPercentCommand = new RelayCommand(action =>
          {
            showAsGainLoss = !showAsGainLoss;
            base.OnPropertyChanged("SelectedSymbol");
            base.OnPropertyChanged("PercentButtonText");
          }, action => { return true; });
        }
        return toggleReturnOrPercentCommand;
      }
    }
// This is the button that controls the display in terms of active vs total return display on the graph
    public String ActiveTotalButtonText
    {
      get
      {
        if (!showActiveGainLoss) return "Show Active G/L";
        else return "Show Total G/L";
      }
    }
    public ICommand ToggleActiveOrTotalCommand
    {
      get
      {
        if (toggleActiveOrTotalCommand == null)
        {
          toggleActiveOrTotalCommand = new RelayCommand(action =>
          {
            showActiveGainLoss=!showActiveGainLoss;
            base.OnPropertyChanged("SelectedSymbol");
            base.OnPropertyChanged("ActiveTotalButtonText");
          }, action => { return true; });
        }
        return toggleActiveOrTotalCommand;
      }
    }

// *************************************************************************************************************************************************************************
// ***************************************************************************** T A B L E  D A T A  ***********************************************************************
// *************************************************************************************************************************************************************************
// The compound model collection is the data behind the views left-hand grid.  This view shows the compound gain/loss since inception
    public ObservableCollection<GainLossCompoundModel> GainLossCompoundModelCollection
    {
      get
      {
        return gainLossCompoundModelCollection;
      }
    }
// The summary item collection is the data behind the views right-hand grid.  This view shows the gain/loss for the date that is selected in the compound model
    public ObservableCollection<GainLossSummaryItem> GainLossSummaryItemCollection
    {
      get
      {
        return gainLossSummaryItemCollection;
      }
    }
// ****************************************************************************** G R I D   S E L E C T I O N S ***********************************************
// The selected item in the compoint model
    public GainLossCompoundModel SelectedGainLossCompoundItem
    {
      get
      {
        return selectedGainLossCompoundItem;
      }
      set
      {
        selectedGainLossCompoundItem = value;
        base.OnPropertyChanged("SelectedGainLossCompoundItem");
      }
    }
// The selected item in the summary model
    public GainLossSummaryItem SelectedGainLossSummaryItem
    {
      get
      {
        return selectedGainLossSummaryItem;
      }
      set
      {
        selectedGainLossSummaryItem = value;
        base.OnPropertyChanged("SelectedGainLossSummaryItem");
      }
    }
    // ************************************************************************************************************************************************************************************
    // ************************************************************************************************************************************************************************************
    // ************************************************************************************************************************************************************************************
      public ObservableCollection<MenuItem> MenuItems
      {
        get
        {
          ObservableCollection<MenuItem> collection = new ObservableCollection<MenuItem>();
          collection.Add(new MenuItem() { Text = "Display Bollinger Band", MenuItemClickedCommand = DisplayBollingerBand, StaysOpenOnClick = false });
          collection.Add(new MenuItem() { Text = "Display Dividend History", MenuItemClickedCommand = DisplayDividendHistory, StaysOpenOnClick = false });
          collection.Add(new MenuItem() { Text = "Display Proforma Dividend Risk", MenuItemClickedCommand = DisplayProformaDividendRisk, StaysOpenOnClick = false });
          collection.Add(new MenuItem() { Text = "Display Sticker Valuation", MenuItemClickedCommand = DisplayStickerValuation, StaysOpenOnClick = false });
          collection.Add(new MenuItem() { Text = "Display Historical", MenuItemClickedCommand = DisplayHistorical, StaysOpenOnClick = false });
          collection.Add(new MenuItem() { Text = "Display Stochastics", MenuItemClickedCommand = DisplayStochastic, StaysOpenOnClick = false });
          collection.Add(new MenuItem() { Text = "Display Relative Strength", MenuItemClickedCommand = DisplayRelativeStrength, StaysOpenOnClick = false });
          collection.Add(new MenuItem() { Text = "Display MACD", MenuItemClickedCommand = DisplayMACD, StaysOpenOnClick = false });
          collection.Add(new MenuItem() { Text = "Display Moving Average", MenuItemClickedCommand = DisplayMovingAverage, StaysOpenOnClick = false });
          collection.Add(new MenuItem() { Text = "Display Price History", MenuItemClickedCommand = DisplayPriceHistory, StaysOpenOnClick = false });
          collection.Add(new MenuItem() { Text = "Display DCF Valuation", MenuItemClickedCommand = DisplayDCFValuation, StaysOpenOnClick = false });
          collection.Add(new MenuItem() { Text = "Display Analyst Ratings", MenuItemClickedCommand = DisplayAnalystRatings, StaysOpenOnClick = false });
          collection.Add(new MenuItem() { Text = "Display Headlines", MenuItemClickedCommand = DisplayHeadlines, StaysOpenOnClick = false });
          collection.Add(new MenuItem() { Text = "Roll Price Forward", MenuItemClickedCommand = RollPriceForward, StaysOpenOnClick = false });
          return collection;
        }
      }

      public ICommand DisplayBollingerBand
      {
        get
        {
          if (bollingerBandCommand == null)
          {
            bollingerBandCommand = new RelayCommand(param => this.DisplayBollingerBandCommand(), 
              param => { return null != selectedGainLossSummaryItem && null!=selectedGainLossSummaryItem.Symbol; });
          }
          return bollingerBandCommand;
        }
      }
      public ICommand DisplayDividendHistory
      {
        get
        {
          if (dividendHistoryCommand == null)
          {
            dividendHistoryCommand = new RelayCommand(param => 
            {
              SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.DividendHistoryViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + ",SelectedWatchList,{All}");
              saveParams.Referer=this;
              WorkspaceInstantiator.Invoke(saveParams);
            }, param => { return null != selectedGainLossSummaryItem && null != selectedGainLossSummaryItem.Symbol; });
          }
          return dividendHistoryCommand;
        }
      }
      public ICommand DisplayProformaDividendRisk
      {
        get
        {
          if (proformaDividendRiskCommand == null)
          {
            proformaDividendRiskCommand = new RelayCommand(param =>
            {
              SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.DividendRiskParityViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + "");
              saveParams.Referer = this;
              WorkspaceInstantiator.Invoke(saveParams);
            }, param => { return null != selectedGainLossSummaryItem && null != selectedGainLossSummaryItem.Symbol; });
          }
          return proformaDividendRiskCommand;
        }
      }
      public ICommand DisplayStickerValuation
      {
        get
        {
          if (null == stickerValuationCommand)
          {
            stickerValuationCommand = new RelayCommand(param =>
            {
              SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.StickerPriceViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + ",SelectedWatchList,{All}");
              saveParams.Referer=this;
              WorkspaceInstantiator.Invoke(saveParams);
            }, param => { return null != selectedGainLossSummaryItem && null!=selectedGainLossSummaryItem.Symbol; });
          }
          return stickerValuationCommand;
        }
      }
      public ICommand DisplayHistorical
      {
        get
        {
          if (displayHistoricalCommand == null)
          {
            displayHistoricalCommand = new RelayCommand(param => 
            {
              SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.HistoricalViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + ",SelectedWatchList,{All}");
              saveParams.Referer=this;
              WorkspaceInstantiator.Invoke(saveParams);
            }, param => { return null != selectedGainLossSummaryItem && null != selectedGainLossSummaryItem.Symbol; });
          }
          return displayHistoricalCommand;
        }
      }
      public ICommand DisplayStochastic
      {
        get
        {
          if (stochasticsCommand == null)
          {
            stochasticsCommand = new RelayCommand(param => this.DisplayStochasticCommand(), 
              param => { return null != selectedGainLossSummaryItem && null!=selectedGainLossSummaryItem.Symbol; });
          }
          return stochasticsCommand;
        }
      }
      public ICommand DisplayRelativeStrength
      {
        get
        {
          if (relativeStrengthCommand == null)
          {
            relativeStrengthCommand = new RelayCommand(param => this.DisplayRelativeStrengthCommand(), 
              param => { return null != selectedGainLossSummaryItem && null!=selectedGainLossSummaryItem.Symbol; });
          }
          return relativeStrengthCommand;
        }
      }
      public ICommand DisplayMACD
      {
        get
        {
          if (macdCommand == null)
          {
            macdCommand = new RelayCommand(param => this.DisplayMACDCommand(), 
              param => { return null != selectedGainLossSummaryItem && null!=selectedGainLossSummaryItem.Symbol; });
          }
          return macdCommand;
        }
      }
      public ICommand DisplayMovingAverage
      {
        get
        {
          if (movingAverageCommand == null)
          {
            movingAverageCommand = new RelayCommand(param => this.DisplayMovingAverageCommand(), param => { return null != selectedGainLossSummaryItem && null != selectedGainLossSummaryItem.Symbol; });
          }
          return movingAverageCommand;
        }
      }
      public ICommand DisplayPriceHistory
      {
        get
        {
          if (priceHistoryCommand == null)
          {
            priceHistoryCommand = new RelayCommand(param => this.DisplayPriceHistoryCommand(), 
              param => { return null != selectedGainLossSummaryItem && null!=selectedGainLossSummaryItem.Symbol; });
          }
          return priceHistoryCommand;
        }
      }
      public ICommand DisplayDCFValuation
      {
        get
        {
          if (null == dcfValuationCommand)
          {
            dcfValuationCommand = new RelayCommand(param =>
            {
              SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.DCFValuationViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + ",SelectedWatchList,{All}");
              saveParams.Referer=this;
              WorkspaceInstantiator.Invoke(saveParams);
            }, param => { return null != selectedGainLossSummaryItem && null!=selectedGainLossSummaryItem.Symbol; });
          }
          return dcfValuationCommand;
        }
      }
      public ICommand DisplayAnalystRatings
      {
        get
        {
          if (null == displayAnalystRatingsCommand)
          {
            displayAnalystRatingsCommand = new RelayCommand(param =>
            {
              SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.AnalystRatingsViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + ",SelectedWatchList,{All}");
              saveParams.Referer=this;
              WorkspaceInstantiator.Invoke(saveParams);
            }, param => { return null != selectedGainLossSummaryItem && null!=selectedGainLossSummaryItem.Symbol; });
          }
          return displayAnalystRatingsCommand;
        }
      }
      public ICommand DisplayHeadlines
      {
        get
        {
          if (null == displayHeadlinesCommand)
          {
            displayHeadlinesCommand = new RelayCommand(param =>
            {
              SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.HeadlinesViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + ",SelectedWatchList,Valuations");
              saveParams.Referer=this;
              WorkspaceInstantiator.Invoke(saveParams);
            }, param => { return null != selectedGainLossSummaryItem && null!=selectedGainLossSummaryItem.Symbol; });
          }
          return displayHeadlinesCommand;
        }
      }
      public ICommand RollPriceForward
      {
        get
        {
          if (null == rollPriceForwardCommand)
          {
            rollPriceForwardCommand = new RelayCommand(param =>
            {
              Price previousPrice=PricingDA.GetPrice(selectedGainLossSummaryItem.Symbol);
              Price latestPrice=PricingMarketDataHelper.RollPriceForward(selectedGainLossSummaryItem.Symbol);
              System.Windows.MessageBox.Show(String.Format("{0} price rolled forward from {1} to {2}",selectedGainLossSummaryItem.Symbol,previousPrice.Date.ToShortDateString(),latestPrice.Date.ToShortDateString()),"Info",MessageBoxButton.OK,MessageBoxImage.Information);
              ClearCache();
              HandleSelectedSymbol();
            }, param => 
            {
              if(null == selectedGainLossSummaryItem || null==selectedGainLossSummaryItem.Symbol)return false;
              Price symbolPrice=GBPriceCache.GetInstance().GetPriceOrLatestAvailable(selectedGainLossSummaryItem.Symbol,latestMarketDate);
              if(null==symbolPrice)return false;
              if(symbolPrice.Date.Equals(latestMarketDate))return false;
              DateGenerator dateGenerator=new DateGenerator();
              DateTime prevBusinessDay=dateGenerator.FindPrevBusinessDay(latestMarketDate);
              if(!symbolPrice.Date.Equals(prevBusinessDay))return false;

              // This method was slowing things down quite considerably as it was constantly hitting the pricingDA.GetLatestDate()
              // Refactored to the above code and seeing how that works out.
              //DateTime latestDate=PremarketDA.GetLatestMarketDate();
              //DateTime latestDateSymbol=PricingDA.GetLatestDate(selectedGainLossSummaryItem.Symbol);
              //if(latestDate.Equals(latestDateSymbol))return false;
              //DateGenerator dateGenerator=new DateGenerator();
              //DateTime prevBusinessDay=dateGenerator.FindPrevBusinessDay(latestDate);
              //if(!latestDateSymbol.Equals(prevBusinessDay))return false;
              return true;
            });
          }
          return rollPriceForwardCommand;
        }
      }
      private void ClearCache()
      {
        try{LocalPriceCache.GetInstance().Clear();}catch(Exception){;}
        try{GBPriceCache.GetInstance().Clear();}catch(Exception){;}
        try{PriceCache.GetInstance().Clear();}catch(Exception){;}
      }
// **************************************************************************************************************************************************************************************
// ******************************************************************************** C O M M A N D S *************************************************************************************
// **************************************************************************************************************************************************************************************
      public void DisplayBollingerBandCommand()
      {
        SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.BollingerBandViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + ",SelectedWatchList,{All},SelectedDayCount,180,SyncTradeToBand,FALSE");
        saveParams.Referer=this;
        WorkspaceInstantiator.Invoke(saveParams);
      }
      public void DisplayRelativeStrengthCommand()
      {
        SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.RSIViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + ",SelectedWatchList,{All},SelectedDayCount,60,SelectedRSIDayCount,3");
        saveParams.Referer=this;
        WorkspaceInstantiator.Invoke(saveParams);
      }
      public void DisplayStochasticCommand()
      {
        SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.StochasticsViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + ",SelectedWatchList,{All},SelectedDayCount,90");
        saveParams.Referer=this;
        WorkspaceInstantiator.Invoke(saveParams);
      }
      public void DisplayMACDCommand()
      {
        SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.MACDViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + ",SelectedWatchList,{All},SelectedDayCount,90");
        saveParams.Referer=this;
        WorkspaceInstantiator.Invoke(saveParams);
      }
      public void DisplayMovingAverageCommand()
      {
        SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.MovingAverageViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + ",SelectedWatchList,{All},SelectedDayCount,360");
        saveParams.Referer=this;
        WorkspaceInstantiator.Invoke(saveParams);
      }
      public void DisplayPriceHistoryCommand()
      {
        SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.PricingViewModel,SelectedSymbol," + selectedGainLossSummaryItem.Symbol + ",SelectedWatchList,{All},SelectedDayCount,90");
        saveParams.Referer=this;
        WorkspaceInstantiator.Invoke(saveParams);
      }
// **************************************************************************************************************************************************
// ************************************************************* T O O L T I P   C A L L O U T*******************************************************
// **************************************************************************************************************************************************
    public String DollarChangePercent
    {
      get
      {
        return "'$ Change(%)' is calculated as a percentage of dollar change in market value from the previous period to the current period.\nThis number may appear skewed if share count has changed day over day.";
      }
    }
    public String Parity
    {
      get
      {
        if(null== selectedGainLossSummaryItem || null==selectedGainLossSummaryItem.Symbol)return "No row selected.";
        StringBuilder sb=new StringBuilder();
        PortfolioTrades portfolioTrades=PortfolioDA.GetOpenTradesSymbol(selectedGainLossSummaryItem.Symbol);
        double weightAdjustedDividendYield=portfolioTrades.GetWeightAdjustedDividendYield();
        DateTime currentDate=PricingDA.GetLatestDate(selectedGainLossSummaryItem.Symbol);

        String companyName=PricingDA.GetNameForSymbol(selectedGainLossSummaryItem.Symbol);
        if(null!=companyName)sb.Append(companyName).Append("\n");

        CompanyProfile companyProfile=CompanyProfileDA.GetCompanyProfile(selectedGainLossSummaryItem.Symbol);
        if(null!=companyProfile)
        {
           sb.Append(companyProfile.Sector??Constants.CONST_QUESTION).Append("/").Append(companyProfile.Industry??Constants.CONST_QUESTION).Append("\n");
        }

        if(null!=portfolioTrades&&0!=portfolioTrades.Count)
        {
          double shares=(from PortfolioTrade portfolioTrade in portfolioTrades select portfolioTrade.Shares).Sum();
          double exposure=portfolioTrades.Sum(x=>x.Exposure());
// Calculate the gain loss so that we can show the difference between our all time high percentage and where we are right now
          InstantiateGenerators();
          GainLossCollection gainLoss=activeGainLossGenerator.GenerateGainLoss(portfolioTrades);  // gainLoss contains the gain/loss from active positions.  Never includes dividends .. just positions

          GainLossItem maxGainLossItem = gainLoss.OrderByDescending(x => x.GainLossPercent).FirstOrDefault();
          GainLossItem minGainLossItem=gainLoss.OrderBy(x => x.GainLossPercent).FirstOrDefault();

          String accounts=Utility.ListToString(portfolioTrades.Accounts);
          sb.Append("You own '").Append(selectedGainLossSummaryItem.Symbol).Append("' in ").Append(portfolioTrades.Count).Append(" lot(s) (").Append(Utility.FormatNumber(shares,0,true)).Append(" shares) ").Append("Exposure: ").Append(Utility.FormatCurrency(exposure));
          sb.Append("\n").Append("Accounts: ").Append(accounts);
          if(!double.IsNaN(weightAdjustedDividendYield))
          {
            sb.Append("\n").Append("Dividend Yield: ").Append(Utility.FormatPercent(weightAdjustedDividendYield)).Append(" ");
            sb.Append("(").Append(Utility.FormatCurrency(exposure*weightAdjustedDividendYield)).Append("/Yr.)");
          }

          ParityElement parityElement=ParityGenerator.GenerateBreakEven(selectedGainLossSummaryItem.Symbol);
          if(null!=parityElement)
          {
            sb.Append("\n").Append(parityElement.ToString());
            sb.Append("\n").Append("All Time Gain/Loss: ").Append(maxGainLossItem.GainLossPercent<0?"":"+").Append(Utility.FormatPercent(maxGainLossItem.GainLossPercent/100));
            sb.Append(" (").Append(minGainLossItem.GainLossPercent<0?"":"+").Append(Utility.FormatPercent(minGainLossItem.GainLossPercent/100)).Append(")");
          }
        }
        else sb.Append("You don't hold any shares of '").Append(selectedGainLossSummaryItem.Symbol).Append("'");
        sb.Append(".");
        DateGenerator dateGenerator=new DateGenerator();
        DateTime priorDate=dateGenerator.FindPrevBusinessDay(currentDate);
        Price p1=PricingDA.GetPrice(selectedGainLossSummaryItem.Symbol,currentDate);
        Price p2=PricingDA.GetPrice(selectedGainLossSummaryItem.Symbol,priorDate);
        if(null==p2&&null!=p1)
        {
          priorDate=dateGenerator.FindPrevBusinessDay(priorDate);
          p2=PricingDA.GetPrice(selectedGainLossSummaryItem.Symbol,priorDate);
        }
        if(null==p1||null==p2)return sb.ToString();
        sb.Append("\n");
        double change=(p1.Close-p2.Close)/p2.Close;
        sb.Append(String.Format("Latest Price {0} {1} ({2}{3})",Utility.DateTimeToStringMMSDDSYYYY(p1.Date),Utility.FormatCurrency(p1.Close),change<0?"-":"+",Utility.FormatPercent(Math.Abs(change))));
        if(companyProfile.FreezePricing)sb.Append(" ").Append("**Frozen**");
        sb.Append("\n").Append(String.Format("Source: {0}",p1.SourceAsString()));
        return sb.ToString();
      }
    }
  }
}
