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

namespace TradeBlotter.ViewModels
{
  public class PricingViewModel : WorkspaceViewModel
  {
    private List<String> watchLists;
    private List<String> symbols;
    private String selectedWatchList;
    private List<Int32> dayCounts;
    private Int32 selectedDayCount;
    private Prices prices = null;
    private double averagePrice=double.NaN;
    private double maxPrice=double.NaN;
    private double minPrice=double.NaN;
    private String symbol;
    private String selectedCompany;
    private String saveDocument;
    private bool showRatings = true;
    private AnalystRatings analystRatings = null;
    private RelayCommand saveCommand;
    private RelayCommand refreshCommand;
    private bool useLeastSquaresFit=false; 
    private bool busyIndicator = false;

    public PricingViewModel()
    {
      base.DisplayName="Price";
      watchLists = WatchListDA.GetWatchLists();
      watchLists.Insert(0, Constants.CONST_ALL);
      selectedWatchList = watchLists.Find(x => x.Equals("Valuations"));
      symbols = WatchListDA.GetWatchList(selectedWatchList);
      dayCounts = new List<Int32>();
      dayCounts.Add(60);
      dayCounts.Add(90);
      dayCounts.Add(180);
      dayCounts.Add(360);
      dayCounts.Add(720);
      dayCounts.Add(1440);
      dayCounts.Add(3600);
      selectedDayCount = dayCounts[1];
      PropertyChanged += OnPricingViewModelPropertyChanged;
    }
    public override SaveParameters GetSaveParameters()
    {
      SaveParameters saveParams = new SaveParameters();
      if (null == symbol) return null;
      saveParams.Add(new KeyValuePair<String, String>("Type", GetType().Namespace + "." + GetType().Name));
      saveParams.Add(new KeyValuePair<String, String>("SelectedSymbol", symbol));
      saveParams.Add(new KeyValuePair<String, String>("SelectedWatchList", selectedWatchList));
      saveParams.Add(new KeyValuePair<String, String>("SelectedDayCount", selectedDayCount.ToString()));
      saveParams.Add(new KeyValuePair<String, String>("UseLeastSquaresFit", useLeastSquaresFit.ToString()));
      return saveParams;
    }
    public override void SetSaveParameters(SaveParameters saveParameters)
    {
      try
      {
        Referer=saveParameters.Referer;
        symbol = (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;
        base.OnPropertyChanged("SelectedWatchList");
        selectedDayCount = Int32.Parse((from KeyValuePair<String, String> item in saveParameters where item.Key.Equals("SelectedDayCount") select item).FirstOrDefault().Value);
        base.OnPropertyChanged("SelectedSymbol");
        try{useLeastSquaresFit = Boolean.Parse((from KeyValuePair<String, String> item in saveParameters where item.Key.Equals("UseLeastSquaresFit") select item).FirstOrDefault().Value);}catch(Exception){;}
      }
      catch (Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Exception:{0}",exception.ToString()));
      }
    }
    public override bool CanPersist()
    {
      return true;
    }
    public ObservableCollection<PriceModel> AllPrices
    {
      get;
      private set;
    }
    public bool BusyIndicator
    {
      get { return busyIndicator; }
      set
      {
        busyIndicator = value;
        base.OnPropertyChanged("BusyIndicator");
      }
    }
    private void OnPricingViewModelPropertyChanged(object sender, PropertyChangedEventArgs eventArgs)
    {
      if (eventArgs.PropertyName.Equals("SelectedSymbol") || (eventArgs.PropertyName.Equals("SelectedDayCount") && null != symbol))
      {
        BusyIndicator = true;
        Task workerTask = Task.Factory.StartNew(() =>
        {
          base.DisplayName = "Price(" + symbol + ")";
          base.OnPropertyChanged("DisplayName");
          prices = PricingDA.GetPrices(symbol, selectedDayCount);
          averagePrice=prices.Mean();
          maxPrice=prices.Max();
          minPrice=prices.Min();
          selectedCompany = PricingDA.GetNameForSymbol(symbol);
          analystRatings = AnalystRatingsDA.GetAnalystRatings(symbol, prices[prices.Count - 1].Date, prices[0].Date);
          float[] returns1d = prices.GetReturns();
          float[] returns5d = prices.GetReturns(5);
          float[] returns10d = prices.GetReturns(10);
          float[] returns15d = prices.GetReturns(15);
          float[] returns30d = prices.GetReturns(30);
          float[] returns60d = prices.GetReturns(60);
          float[] returns200d=prices.GetReturns(200);
          String companyName = PricingDA.GetNameForSymbol(symbol);
          List<PriceModel> priceModels = new List<PriceModel>();
          for (int index = 0; index < prices.Count; index++)
          {
            Price price = prices[index];
            float return1d = (index < returns1d.Length - 1) ? returns1d[index] : 0;
            float return5d = (index < returns5d.Length - 1) ? returns5d[index] : 0;
            float return10d = (index < returns10d.Length - 1) ? returns10d[index] : 0;
            float return15d = (index < returns15d.Length - 1) ? returns15d[index] : 0;            
            float return30d = (index < returns30d.Length - 1) ? returns30d[index] : 0;
            float return60d = (index < returns60d.Length - 1) ? returns60d[index] : 0;
            float return200d = (index < returns200d.Length - 1) ? returns200d[index] : 0;
            PriceModel priceModel = new PriceModel(price, return1d, return5d, return10d, return15d, return30d,return60d,return200d,companyName);
            priceModels.Add(priceModel);
          }
          List<PriceModel> priceModelList = priceModels.ToList();
          this.AllPrices = new ObservableCollection<PriceModel>(priceModelList);
        });
        workerTask.ContinueWith((continuation) =>
        {
          BusyIndicator = false;
          base.OnPropertyChanged("AllPrices");
          base.OnPropertyChanged("Close");
          base.OnPropertyChanged("LeastSquares");
          base.OnPropertyChanged("RatingsPoints");
          base.OnPropertyChanged("Markers");
          base.OnPropertyChanged("Title");
        });
      }
      else if (eventArgs.PropertyName.Equals("SelectedWatchList"))
      {
//        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");
      }
      else if (eventArgs.PropertyName.Equals("ShowRatings"))
      {
        base.OnPropertyChanged("RatingsPoints");
        base.OnPropertyChanged("Markers");
      }
    }
    public override String Title
    {
      get
      {
        if (null == selectedCompany || null == prices || 0 == prices.Count) return "";
        StringBuilder sb=new StringBuilder();
        float change=float.NaN;
        Prices prices2day=new Prices(prices.Take(2).ToList());
        if(2==prices2day.Count)change=prices2day.GetReturns()[0];
        sb.Append(selectedCompany);
        sb.Append(" (").Append(symbol).Append(") ");
        sb.Append(Utility.DateTimeToStringMMHDDHYYYY(prices[prices.Count-1].Date));
        sb.Append(" Thru ");
        sb.Append(Utility.DateTimeToStringMMHDDHYYYY(prices[0].Date));
        sb.Append(" (").Append(Utility.FormatCurrency(prices[0].Close));
        if(!float.IsNaN(change))
        {
          sb.Append(",");
          sb.Append(change>=0.00?"+":"").Append(Utility.FormatPercent((double)change));
        }
        sb.Append(")");
        return sb.ToString();
      }
    }
    public List<String> WatchListNames
    {
      get
      {
        return watchLists;
      }
      set { ;}
    }
    public String SelectedWatchList
    {
      get { return selectedWatchList; }
      set { selectedWatchList = value; base.OnPropertyChanged("SelectedWatchList"); }
    }
    public List<String> Symbols
    {
      get
      {
        return symbols;
      }
    }
    public String SelectedSymbol
    {
      get { return symbol; }
      set
      {
        if (value == symbol || String.IsNullOrEmpty(value)) return;
        symbol = value;
        base.OnPropertyChanged("SelectedSymbol");
      }
    }
    public List<Int32> DayCounts
    {
      get { return dayCounts; }
    }
    public Int32 SelectedDayCount
    {
      get { return selectedDayCount; }
      set { selectedDayCount = value; base.OnPropertyChanged("SelectedDayCount"); }
    }
    public CompositeDataSource Close
    {
      get
      {
        CompositeDataSource compositeDataSource = PricesModel.Close(prices);
        return compositeDataSource;
      }
    }
    public CompositeDataSource LeastSquares
    {
      get
      {
        if(!useLeastSquaresFit)return null;
        CompositeDataSource compositeDataSource = PricesModel.LeastSquares(prices);
        return compositeDataSource;
      }
    }
    public CompositeDataSource RatingsPoints
    {
      get
      {
        if (!showRatings) return null;
        Price latestPrice = null!=prices&&0!=prices.Count?prices[0]:null;
        CompositeDataSource compositeDataSource = RatingsModel.Ratings(analystRatings,latestPrice);
        return compositeDataSource;
      }
    }
    public CenteredTextMarker[] Markers
    {
      get
      {
        if (!showRatings) return null;
        if (null == analystRatings) return null;
        List<CenteredTextMarker> centeredTextMarkers = new List<CenteredTextMarker>();
        for (int index = 0; index < analystRatings.Count; index++)
        {
          CenteredTextMarker centerTextMarker = new CenteredTextMarker();
          AnalystRating analystRating = analystRatings[index];
          StringBuilder sb = new StringBuilder();
          sb.Append("(").Append(analystRating.RatingsChange).Append(")");
          if (0.00 != analystRating.PriceTarget)
          {
            sb.Append(Utility.FormatCurrency(analystRating.PriceTarget));
          }
          centerTextMarker.Text = sb.ToString();
          if(analystRating.PriceTarget>averagePrice)centerTextMarker.VerticalShift="30";
          centeredTextMarkers.Add(centerTextMarker);
        }
        return centeredTextMarkers.ToArray();
      }
    }
    private void Refresh()
    {
      base.OnPropertyChanged("SelectedSymbol");
    }
    private bool CanRefresh
    {
      get { return true; }
    }
    public ICommand RefreshCommand
    {
      get
      {
        if (refreshCommand == null)
        {
          refreshCommand = new RelayCommand(param => this.Refresh(), param => this.CanRefresh);
        }
        return refreshCommand;
      }
    }
    public String SaveDocument
    {
      get { return saveDocument; }
      set { saveDocument = value; base.OnPropertyChanged("SaveDocument"); }
    }
    private void Save()
    {
      StringBuilder sb = new StringBuilder();
      sb.Append("Prices_").Append(symbol).Append(".xls");
      SaveDocument = sb.ToString();
    }
    private bool CanSave
    {
      get { return true; }
    }
    public ICommand SaveCommand
    {
      get
      {
        if (saveCommand == null)
        {
          saveCommand = new RelayCommand(param => this.Save(), param => this.CanSave);
        }
        return saveCommand;
      }
    }
    public bool ShowRatings
    {
      get { return showRatings; }
      set { showRatings = value; base.OnPropertyChanged("ShowRatings"); }
    }
    public Boolean CheckBoxLeastSquaresFit
    {
      get
      {
        return useLeastSquaresFit;
      }
      set
      {
        useLeastSquaresFit = value;
        base.OnPropertyChanged("CheckBoxLeastSquaresFit");
        base.OnPropertyChanged("UseLeastSquaresFit");
        base.OnPropertyChanged("LeastSquares");
      }
    }
    public String UseLeastSquaresFit
    {              
      get
      {
        if(useLeastSquaresFit)return "true";
        return "false";
      }
      set
      {
        useLeastSquaresFit=Boolean.Parse("value");
        base.OnPropertyChanged("UseLeastSquaresFit");
      }
    }
  }
}