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.Input;
using System.Threading.Tasks;
using MarketData;
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 System.Threading;
using TradeBlotter.Cache;

namespace TradeBlotter.ViewModels
{
  public class AnalystRatingsViewModel : WorkspaceViewModel
  {
    private enum Tasks{SelectedDate,SelectedSymbol,SelectedWatchList};
    private Dictionary<Tasks,Semaphore> semaphorePool=new Dictionary<Tasks,Semaphore>();
    private const String DISPLAY_NAME = "Analyst Ratings";
    private List<String> symbols;
    private List<String> watchLists;
    private List<String> dates;
    private String selectedWatchList;
    private String selectedSymbol;
    private String selectedCompany;
    private String selectedDate = null;
    private ObservableCollection<AnalystRating> analystRatingsCollection = null;
    private bool busyIndicator = false;
    private RelayCommand resetCommand;
    private RelayCommand stochasticsCommand;
    private RelayCommand macdCommand;
    private RelayCommand bollingerBandCommand;
    private RelayCommand priceHistoryCommand;
    private RelayCommand stickerValuationCommand;
    private RelayCommand dcfValuationCommand;
    private RelayCommand dividendHistoryCommand;
    private RelayCommand displayHeadlinesCommand;
    private RelayCommand displayHistoricalCommand;
    private AnalystRating selectedItem;

    public AnalystRatingsViewModel(bool loadedFromParams=false)
    {
      semaphorePool.Add(Tasks.SelectedDate,new Semaphore(1,1));
      semaphorePool.Add(Tasks.SelectedSymbol,new Semaphore(1,1));
      semaphorePool.Add(Tasks.SelectedWatchList,new Semaphore(1,1));
      base.DisplayName = DISPLAY_NAME;
      watchLists = WatchListDA.GetWatchLists();
      watchLists.Insert(0, Constants.CONST_ALL);
      selectedWatchList = watchLists.Find(x => x.Equals("Valuations"));
      symbols = WatchListDA.GetWatchList(selectedWatchList);
      symbols.Insert(0, Constants.CONST_ALL);
      selectedSymbol = symbols[0];
      dates = AnalystRatingsDA.GetAnalystRatingsDates(); 
      dates.Insert(0, Constants.CONST_ALL);
      if (dates.Count > 1) selectedDate = dates[1];
      else selectedDate = dates[0];
      PropertyChanged += OnAnalystRatingsViewModelPropertyChanged;
      if(!loadedFromParams)
      {
        base.OnPropertyChanged("SelectedDate");
        base.OnPropertyChanged("SelectedSymbol");
      }
    }
// ******************************************************************************************** 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>("SelectedCompany", selectedCompany));
      saveParams.Add(new KeyValuePair<String, String>("SelectedWatchList", selectedWatchList));
      saveParams.Add(new KeyValuePair<String, String>("SelectedDate", selectedDate));
      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;
        selectedCompany = (from KeyValuePair<String, String> item in saveParameters where item.Key.Equals("SelectedCompany") select item).FirstOrDefault().Value;
        selectedDate = (from KeyValuePair<String, String> item in saveParameters where item.Key.Equals("SelectedDate") select item).FirstOrDefault().Value;
        if (null == selectedDate) selectedDate = Constants.CONST_ALL;
        Referer=saveParameters.Referer;
        base.OnPropertyChanged("SelectedWatchList");
        base.OnPropertyChanged("SelectedSymbol");
      }
      catch (Exception)
      {
      }
    }
// ******************************************************************************************************************************************************
    public bool BusyIndicator
    {
      get { return busyIndicator; }
      set
      {
        busyIndicator = value;
        base.OnPropertyChanged("BusyIndicator");
      }
    }
    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 Headlines", MenuItemClickedCommand = DisplayHeadlines, 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 = DisplayStochastics, StaysOpenOnClick = false });
        collection.Add(new MenuItem() { Text = "Display MACD", MenuItemClickedCommand = DisplayMACD, 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 Dividend History", MenuItemClickedCommand = DisplayDividendHistory, StaysOpenOnClick = false });
        return collection;
      }
    }
    private void OnAnalystRatingsViewModelPropertyChanged(object sender, PropertyChangedEventArgs eventArgs)
    {
        if (eventArgs.PropertyName.Equals("SelectedDate"))
        {
          try{semaphorePool[Tasks.SelectedDate].WaitOne();HandleSelectedDate();}finally{semaphorePool[Tasks.SelectedDate].Release();}
        }
        else if (eventArgs.PropertyName.Equals("SelectedSymbol")) 
        {
          try{semaphorePool[Tasks.SelectedSymbol].WaitOne();HandleSelectedSymbol();}finally{semaphorePool[Tasks.SelectedSymbol].Release();}
        }
        else if (eventArgs.PropertyName.Equals("SelectedWatchList"))
        {
          try{semaphorePool[Tasks.SelectedWatchList].WaitOne();HandleSelectedWatchList();}finally{semaphorePool[Tasks.SelectedWatchList].Release();}
        }
    }
    private void HandleSelectedDate()
    {
      BusyIndicator = true;
      Task workerTask = Task.Factory.StartNew(() =>
      {
        if (Constants.CONST_ALL.Equals(selectedDate))
        {
          MDTrace.WriteLine(LogLevel.DEBUG, "AnalystRatingsViewModel::HandleSelectedDate->C1");
          AnalystRatings analystRatings = AnalystRatingsDA.GetAnalystRatings(selectedSymbol);
          selectedCompany = PricingDA.GetNameForSymbol(selectedSymbol);
          if (null != analystRatings && 0 != analystRatings.Count) analystRatingsCollection = new ObservableCollection<AnalystRating>(analystRatings);
          else analystRatingsCollection = null;
        }
        else if (null != selectedSymbol && !Constants.CONST_ALL.Equals(selectedSymbol))
        {
          MDTrace.WriteLine(LogLevel.DEBUG, "AnalystRatingsViewModel::HandleSelectedDate->C2");
          AnalystRatings analystRatings = AnalystRatingsDA.GetAnalystRatings(selectedSymbol, DateTime.Parse(selectedDate));
          selectedCompany = PricingDA.GetNameForSymbol(selectedSymbol);
          if (null != analystRatings && 0 != analystRatings.Count) analystRatingsCollection = new ObservableCollection<AnalystRating>(analystRatings);
          else analystRatingsCollection = null;
        }
        else
        {
          MDTrace.WriteLine(LogLevel.DEBUG, "AnalystRatingsViewModel::HandleSelectedDate->C3");
          AnalystRatings analystRatings = AnalystRatingsDA.GetAnalystRatings(DateTime.Parse(selectedDate));
          if (null != analystRatings && 0 != analystRatings.Count) analystRatingsCollection = new ObservableCollection<AnalystRating>(analystRatings);
          else analystRatingsCollection = null;
        }
      });
      workerTask.ContinueWith((continuation)=>
      {
        BusyIndicator = false;
        base.OnPropertyChanged("AllItems");
        base.OnPropertyChanged("Title");
      });
    }
    private void HandleSelectedSymbol()
    {
      BusyIndicator = true;
      Task workerTask = Task.Factory.StartNew(() =>
      {
        if (null != selectedSymbol && !Constants.CONST_ALL.Equals(selectedSymbol)) base.DisplayName = DISPLAY_NAME + "(" + selectedSymbol + ")";
        if (null != selectedSymbol && Constants.CONST_ALL.Equals(selectedSymbol) && null != selectedDate && Constants.CONST_ALL.Equals(selectedDate))
        {
          MDTrace.WriteLine(LogLevel.DEBUG, "AnalystRatingsViewModel::HandleSelectedSymbol->C1");
          analystRatingsCollection.Clear();
          SelectedDate = dates[1];
        }
        else if (null == selectedSymbol || Constants.CONST_ALL.Equals(selectedSymbol))
        {
          MDTrace.WriteLine(LogLevel.DEBUG, "AnalystRatingsViewModel::HandleSelectedSymbol->C2");
          AnalystRatings analystRatings = null;
          if (null == selectedDate || Constants.CONST_ALL.Equals(selectedDate)) analystRatings = AnalystRatingsDA.GetAnalystRatings();
          else analystRatings = AnalystRatingsDA.GetAnalystRatings(DateTime.Parse(selectedDate));
          if (null != analystRatings && 0 != analystRatings.Count) analystRatingsCollection = new ObservableCollection<AnalystRating>(analystRatings);
          else analystRatingsCollection = null;
        }
        else if (Constants.CONST_ALL.Equals(selectedDate))
        {
          MDTrace.WriteLine(LogLevel.DEBUG, "AnalystRatingsViewModel::HandleSelectedSymbol->C3");
          AnalystRatings analystRatings = AnalystRatingsDA.GetAnalystRatings(selectedSymbol);
          selectedCompany = PricingDA.GetNameForSymbol(selectedSymbol);
          if (null != analystRatings && 0 != analystRatings.Count) analystRatingsCollection = new ObservableCollection<AnalystRating>(analystRatings);
          else analystRatingsCollection = null;
        }
        else if (null != selectedSymbol)
        {
          MDTrace.WriteLine(LogLevel.DEBUG, "AnalystRatingsViewModel::HandleSelectedSymbol->C4");
          analystRatingsCollection.Clear();
          SelectedDate = Constants.CONST_ALL;
        }
        else
        {
          MDTrace.WriteLine(LogLevel.DEBUG, "AnalystRatingsViewModel::HandleSelectedSymbol->C5");
          AnalystRatings analystRatings = AnalystRatingsDA.GetAnalystRatings(DateTime.Parse(selectedDate));
          if (null != analystRatings && 0 != analystRatings.Count) analystRatingsCollection = new ObservableCollection<AnalystRating>(analystRatings);
          else analystRatingsCollection = null;
        }
      });
      workerTask.ContinueWith((continuation) =>
      {
        BusyIndicator = false;
        base.OnPropertyChanged("AllItems");
        base.OnPropertyChanged("Title");
        base.OnPropertyChanged("DisplayName");
      });
    }
    private void HandleSelectedWatchList()
    {
      MDTrace.WriteLine(LogLevel.DEBUG, "AnalystRatingsViewModel::HandleSelectedDate");
//      if (selectedWatchList.Equals(Constants.CONST_ALL)) symbols = PricingDA.GetSymbols();
      if (selectedWatchList.Equals(Constants.CONST_ALL)) symbols = SymbolCache.GetInstance().GetSymbols();
      else
      {
        symbols = WatchListDA.GetWatchList(selectedWatchList);
        symbols.Insert(0, Constants.CONST_ALL);
      }
      base.OnPropertyChanged("Symbols");
    }
    public ObservableCollection<AnalystRating> AllItems
    {
      get { return analystRatingsCollection; }
    }
    public String Description
    {
      get
      {
        if(null== selectedItem || null==selectedItem.Symbol)return "No row selected.";
        CompanyProfile companyProfile=CompanyProfileDA.GetCompanyProfile(selectedItem.Symbol);
        if(null==companyProfile || null==companyProfile.Description)return "No description found.";
        return companyProfile.Description;
      }
    }
    public String ZacksRank
    {
      get
      {
        if(null== selectedItem || null==selectedItem.Symbol)return "No row selected.";
        ZacksRank zacksRank=ZacksRankDA.GetZacksRank(selectedItem.Symbol);
        if(null==zacksRank)return "No Zacks rank";
        return zacksRank.Symbol+": latest Zacks Rank:"+zacksRank.Rank+" "+(null==zacksRank.Type?"":zacksRank.Type)+" "+zacksRank.Date.ToShortDateString();
      }
    }
    public override String Title
    {
      get 
      {
        if (null != selectedSymbol && !Constants.CONST_ALL.Equals(selectedSymbol)) return "Analyst Ratings - " + selectedCompany + " (" + selectedSymbol + ")";
        return "Analyst Ratings"; 
      }
    }
    private void Reset()
    {
      MDTrace.WriteLine(LogLevel.DEBUG, "AnalystRatingsViewModel::Reset");
      selectedSymbol = symbols[0];
      selectedDate = dates[0];
      base.OnPropertyChanged("SelectedSymbol");
    }
    private bool CanReset
    {
      get { return true; }
    }
    public ICommand ResetCommand
    {
      get
      {
        if (resetCommand == null)
        {
          resetCommand = new RelayCommand(param => this.Reset(), param => this.CanReset);
        }
        return resetCommand;
      }
    }
    public List<String> Dates
    {
      get
      {
        return dates;
      }
    }
    public List<String> Symbols
    {
      get
      {
        return symbols;
      }
    }
    public String SelectedSymbol
    {
      get
      { 
        return selectedSymbol; 
      }
      set
      {
        MDTrace.WriteLine(LogLevel.DEBUG, "AnalystRatingsViewModel::SelectedSymbol");
        if (value == selectedSymbol || String.IsNullOrEmpty(value)) return;
        selectedSymbol = value;
        if (selectedSymbol.Equals(Constants.CONST_ALL))
        {
          selectedDate = dates[0];
        }
        base.OnPropertyChanged("SelectedSymbol");
      }
    }
    public String SelectedDate
    {
      get { return selectedDate; }
      set
      {
        MDTrace.WriteLine(LogLevel.DEBUG, "AnalystRatingsViewModel::SelectedDate");
        selectedDate = value;
        base.OnPropertyChanged("SelectedDate");
      }
    }
    public List<String> WatchListNames
    {
      get
      {
        return watchLists;
      }
      set { ;}
    }
    public String SelectedWatchList
    {
      get { return selectedWatchList; }
      set { selectedWatchList = value; base.OnPropertyChanged("SelectedWatchList"); }
    }
      public ICommand DisplayHistorical
      {
        get
        {
          if (displayHistoricalCommand == null)
          {
            displayHistoricalCommand = new RelayCommand(param => 
            {
              SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.HistoricalViewModel,SelectedSymbol," + selectedItem.Symbol + ",SelectedWatchList,{All}");
              saveParams.Referer=this;
              WorkspaceInstantiator.Invoke(saveParams);
            }, param => { return null != selectedItem && null != selectedItem.Symbol; });
          }
          return displayHistoricalCommand;
        }
      }
    public ICommand DisplayHeadlines
    {
      get
      {
        if (null == displayHeadlinesCommand)
        {
          displayHeadlinesCommand = new RelayCommand(param =>
          {
            SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.HeadlinesViewModel,SelectedSymbol," + selectedItem.Symbol + ",SelectedWatchList,Valuations");
            saveParams.Referer=this;
            WorkspaceInstantiator.Invoke(saveParams);
          }, param => { return null != selectedItem && null!=selectedItem.Symbol; });
        }
        return displayHeadlinesCommand;
      }
    }
    public ICommand DisplayMACD
    {
      get
      {
        if (macdCommand == null)
        {
          macdCommand = new RelayCommand(param => this.DisplayMACDCommand(), param => { return null != selectedItem && null != selectedItem.Symbol; });
        }
        return macdCommand;
      }
    }
    public ICommand DisplayStochastics
    {
      get
      {
        if (stochasticsCommand == null)
        {
          stochasticsCommand = new RelayCommand(param => this.DisplayStochasticsCommand(), param => { return null != selectedItem && null != selectedItem.Symbol; });
        }
        return stochasticsCommand;
      }
    }
    public void DisplayStochasticsCommand()
    {
      SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.StochasticsViewModel,SelectedSymbol," + selectedItem.Symbol + ",SelectedWatchList,{All},SelectedDayCount,180");
      saveParams.Referer=this;
      WorkspaceInstantiator.Invoke(saveParams);
    }
    public void DisplayMACDCommand()
    {
      SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.MACDViewModel,SelectedSymbol," + selectedItem.Symbol + ",SelectedWatchList,{All},SelectedDayCount,180");
      saveParams.Referer=this;
      WorkspaceInstantiator.Invoke(saveParams);
    }
    public ICommand DisplayStickerValuation
    {
      get
      {
        if (null == stickerValuationCommand)
        {
          stickerValuationCommand = new RelayCommand(param =>
          {
            SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.StickerPriceViewModel,SelectedSymbol," + selectedItem.Symbol + ",SelectedWatchList,{All}");
            saveParams.Referer=this;
            WorkspaceInstantiator.Invoke(saveParams);
          }, param => { return null != selectedItem && null!=selectedItem.Symbol; });
        }
        return stickerValuationCommand;
      }
    }
    public ICommand DisplayDCFValuation
    {
      get
      {
        if (null == dcfValuationCommand)
        {
          dcfValuationCommand = new RelayCommand(param =>
          {
            SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.DCFValuationViewModel,SelectedSymbol," + selectedItem.Symbol + ",SelectedWatchList,{All}");
            saveParams.Referer=this;
            WorkspaceInstantiator.Invoke(saveParams);
          }, param => { return null != selectedItem && null!=selectedItem.Symbol; });
        }
        return dcfValuationCommand;
      }
    }
    public ICommand DisplayPriceHistory
    {
      get
      {
        if (priceHistoryCommand == null)
        {
          priceHistoryCommand = new RelayCommand(param => this.DisplayPriceHistoryCommand(), param => { return null != selectedItem && null != selectedItem.Symbol; });
        }
        return priceHistoryCommand;
      }
    }
    public ICommand DisplayDividendHistory
    {
      get
      {
        if (dividendHistoryCommand == null)
        {
          dividendHistoryCommand = new RelayCommand(param => 
          {
            SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.DividendHistoryViewModel,SelectedSymbol," + selectedItem.Symbol + ",SelectedWatchList,{All}");
            saveParams.Referer=this;
            WorkspaceInstantiator.Invoke(saveParams);
          }, param => { return null != selectedItem && null != selectedItem.Symbol; });
        }
        return dividendHistoryCommand;
      }
    }
    public void DisplayPriceHistoryCommand()
    {
      SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.PricingViewModel,SelectedSymbol," + selectedItem.Symbol + ",SelectedWatchList,{All},SelectedDayCount,180");
      saveParams.Referer=this;
      WorkspaceInstantiator.Invoke(saveParams);
    }
    public ICommand DisplayBollingerBand
    {
      get
      {
        if (bollingerBandCommand == null)
        {
          bollingerBandCommand = new RelayCommand(param => this.DisplayBollingerBandCommand(), param => { return null != selectedItem && null != selectedItem.Symbol; });
        }
        return bollingerBandCommand;
      }
    }
    public void DisplayBollingerBandCommand()
    {
      SaveParameters saveParams = SaveParameters.Parse("Type,TradeBlotter.ViewModels.BollingerBandViewModel,SelectedSymbol," + selectedItem.Symbol + ",SelectedWatchList,{All},SelectedDayCount,180");
      saveParams.Referer=this;
      WorkspaceInstantiator.Invoke(saveParams);
    }
    public AnalystRating SelectedItem
    {
      get
      {
        return selectedItem;
      }
      set
      {
        selectedItem = value;
      }
    }
  }
}
