using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Windows.Threading;
using System.ComponentModel;
using System.Threading;
using System.Windows.Media;
using MarketData;
using MarketData.Utils;
using MarketData.Helper;
using MarketData.MarketDataModel;
using MarketData.DataAccess;
using TradeBlotter.Model;
using TradeBlotter.DataAccess;
using TradeBlotter.Command;
using TradeBlotter.UIUtils;
using TradeBlotter.Cache;

namespace TradeBlotter.ViewModels
{
  public class TradeViewModel : WorkspaceViewModel
  {
    private double weight;
    private readonly BlotterTradeModel trade;
    private readonly TradeRepository tradeRepository;
    private bool isSelected;
    private int todaysChangeDirection = 0;
    private int returnChangeDirection = 0;
    private int gainLossChangeDirection = 0;

    public TradeViewModel(BlotterTradeModel trade, TradeRepository tradeRepository)
    {
      UseCache=false;
      if (null == trade) throw new ArgumentNullException("trade");
      if (null == tradeRepository) throw new ArgumentNullException("tradeRepository");
      this.trade = trade;
      this.tradeRepository = tradeRepository;
      PropertyChanged += OnTradeViewModelPropertyChanged;
    }
    public bool UseCache{get;set;}
    public override SaveParameters GetSaveParameters()
    {
      return null;
    }
    public override void SetSaveParameters(SaveParameters saveParameters)
    {
    }
    public override bool CanPersist()
    {
      return false;
    }
    private void OnTradeViewModelPropertyChanged(object sender, PropertyChangedEventArgs eventArgs)
    {
    }
    public int TradeId
    {
      get { return trade.TradeId; }
      set { trade.TradeId = value; }
    }
    public String Symbol
    {
      get { return trade.Symbol; }
      set { trade.Symbol = value; base.OnPropertyChanged("Symbol"); }
    }
    public DateTime TradeDate
    {
      get { return trade.TradeDate; }
      set { trade.TradeDate = value; base.OnPropertyChanged("TradeDate"); }
    }
    public double Shares 
    {
      get { return trade.Shares; }
      set { trade.Shares = value; base.OnPropertyChanged("Shares"); }
    }
    public double Price 
    {
      get { return trade.Price; }
      set { trade.Price = value; base.OnPropertyChanged("Price"); }
    }
    public String BuySell
    {
      get { return trade.BuySell; }
      set { trade.BuySell=value; base.OnPropertyChanged("BuySell"); }
    }
    public String Exposure
    {
      get 
      { 
        return trade.IsClosed?Constants.CONST_DASHES:Utility.FormatCurrency(trade.Exposure); 
      }
    }
    public String SellDate
    {
      get { return trade.IsClosed?Utility.DateTimeToStringMMSDDSYYYY(trade.SellDate):Constants.CONST_DASHES; }
      set { trade.SellDate = DateTime.Parse(value); base.OnPropertyChanged("SellDate"); }
    }
    public String SellPrice
    {
//      get { return trade.IsClosed?Utility.FormatCurrency(trade.SellPrice):Constants.CONST_DASHES; }
      get { return trade.IsClosed?Utility.FormatPrice(trade.SellPrice):Constants.CONST_DASHES; }
      set { trade.SellPrice = double.Parse(value); base.OnPropertyChanged("SellPrice"); }
    }
    public String Account
    {
      get { return trade.Account; }
      set { trade.Account = value; base.OnPropertyChanged("Account"); }
    }
    public String Status
    {
      get { return trade.Status; }
      set { trade.Status = value; base.OnPropertyChanged("Status"); }
    }
    public int DaysHeld
    {
      get
      {
        DateGenerator dateGenerator = new DateGenerator();
        if (trade.IsOpen) return dateGenerator.DaysBetween(DateTime.Now,trade.TradeDate);
        else return dateGenerator.DaysBetween(trade.SellDate,trade.TradeDate);
      }
    }
    public bool IsOpen
    {
      get { return trade.IsOpen; }
    }
    public void Invalidate()
    {
      Price price = null;
      if(UseCache)price=PriceCache.GetInstance().GetLatestPrice(trade.Symbol);
      if (null == price) price = PricingDA.GetPrice(trade.Symbol);
      if (null == price) return;
      trade.LatestPrice = price.Close;
      trade.PriceDate = price.Date;
      trade.HasLatestPrice = true;
    }
    public void Validate()
    {
      base.OnPropertyChanged("GainLoss");
      base.OnPropertyChanged("Return");
      base.OnPropertyChanged("PriceDate");
      base.OnPropertyChanged("CurrentPrice");
      base.OnPropertyChanged("TodaysChange");
    }
    public String CurrentPrice
    {
      get 
      {
        return Utility.FormatPrice(trade.LatestPrice); 
//        return Utility.FormatCurrency(trade.LatestPrice); 
      }
      set { trade.LatestPrice = double.Parse(value); base.OnPropertyChanged("CurrentPrice"); }
    }
    public String PriceDate
    {
      get { return Utility.DateTimeToStringMMSDDSYYYYHHMMSS(trade.PriceDate); }
      set { trade.PriceDate = DateTime.Parse(value); base.OnPropertyChanged("PriceDate"); }
    }
    public String Commission
    {
      get
      {
        return Utility.FormatCurrency(trade.Commission);
      }
      set { trade.Commission = double.Parse(value); base.OnPropertyChanged("Commission"); }
    }
    public String GainLoss
    {
      get 
      {
        double gainLoss = 0;
        if (trade.IsClosed) gainLoss = (trade.SellPrice * trade.Shares) - (trade.Price * trade.Shares);
        else gainLoss = (trade.LatestPrice * trade.Shares) - (trade.Price * trade.Shares);
        if (gainLoss > 0) gainLossChangeDirection = 1;
        else if (gainLoss < 0) gainLossChangeDirection = -1;
        else gainLossChangeDirection = 0;
        base.OnPropertyChanged("GainLossColor");
        return Utility.FormatCurrency(gainLoss); 
      }
    }
    public Brush GainLossColor
    {
      get
      {
        if (gainLossChangeDirection > 0) return new SolidColorBrush(Colors.Green);
        else if (gainLossChangeDirection < 0) return new SolidColorBrush(Colors.Red);
        return new SolidColorBrush(Colors.Black);
      }
    }
    public String Return
    {
      get
      {
        double calculatedReturn=0;
        if (trade.IsClosed)calculatedReturn=((trade.SellPrice - trade.Price) / trade.Price);
        else calculatedReturn = ((trade.LatestPrice - trade.Price) / trade.Price);
        if (calculatedReturn > 0) returnChangeDirection = 1;
        else if (calculatedReturn < 0) returnChangeDirection = -1;
        else returnChangeDirection = 0;
        base.OnPropertyChanged("ReturnColor");
        return Utility.FormatPercent(calculatedReturn);
      }
    }
    public Brush ReturnColor
    {
      get
      {
        if(trade.IsClosed)return new SolidColorBrush(Colors.Blue);
        if (returnChangeDirection > 0) return new SolidColorBrush(Colors.Green);
        else if (returnChangeDirection < 0) return new SolidColorBrush(Colors.Red);
        return new SolidColorBrush(Colors.Black);
      }
    }
    public Brush TodaysChangeColor
    {
      get
      {
        if (todaysChangeDirection > 0) return new SolidColorBrush(Colors.Green);
        else if (todaysChangeDirection < 0) return new SolidColorBrush(Colors.Red);
        return new SolidColorBrush(Colors.Black);
      }
    }
    public String TodaysChange
    {
      get
      {
        if (trade.IsClosed) { todaysChangeDirection = 0; return Constants.CONST_DASHES; }
        if (trade.IsOpen && trade.TradeDate.Date.Equals(DateTime.Now.Date)) { todaysChangeDirection = 0; return Constants.CONST_DASHES; }
        DateGenerator dateGenerator = new DateGenerator();
        DateTime prevBusinessDay = dateGenerator.FindPrevBusinessDay(DateTime.Now);
        Price price=PricingDA.GetPrice(trade.Symbol,prevBusinessDay);
        if (null == price) { todaysChangeDirection = 0; return Constants.CONST_DASHES; }
        double todaysChange = (trade.LatestPrice * trade.Shares) - (price.Close * trade.Shares);
        if (todaysChange > 0) todaysChangeDirection = 1;
        else if (todaysChange < 0) todaysChangeDirection = -1;
        else todaysChangeDirection = 0;
        return Utility.FormatCurrency(todaysChange);
      }
      set
      {
        TodaysChange = value;
        base.OnPropertyChanged("TodaysChange");
        base.OnPropertyChanged("TodaysChangeColor");
      }
    }
    public String MarketValue
    {
      get
      {
        if(!trade.HasLatestPrice)
        {
          Invalidate();
          base.OnPropertyChanged("PriceDate");
          base.OnPropertyChanged("CurrentPrice");
        }
        if (trade.IsClosed) return Constants.CONST_DASHES;
        return trade.HasLatestPrice?Utility.FormatCurrency(trade.Shares*trade.LatestPrice):"0.00";
      }
    }
    public String Weight
    {
      get
      {
        return double.IsNaN(weight)||trade.IsClosed ? Constants.CONST_DASHES : Utility.FormatPercent(weight);
      }
      set
      {
        weight = Utility.ParsePercent(value);
      }
    }
    public override string DisplayName
    {
      get
      {
        return "Trade";
      }
    }
    public bool IsSelected
    {
      get{return isSelected;}
      set
      {
        if (value == isSelected) return;
        isSelected = value;
        base.OnPropertyChanged("IsSelected");
      }
    }
  }
}
