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

namespace TradeBlotter.ViewModels
{
  public class TradeEntryViewModel : WorkspaceViewModel
  {
    private BlotterTradeModel trade = null;
    private StopLimit stopLimit;
    private readonly TradeRepository tradeRepository;
    private RelayCommand saveCommand;
    private String statusText="";

    public TradeEntryViewModel(BlotterTradeModel trade,TradeRepository tradeRepository)
    {
      base.DisplayName="TradeEntry";
      this.trade=trade;
      this.tradeRepository=tradeRepository;
      if(PortfolioDA.HasStopLimit(trade.Symbol)) stopLimit=PortfolioDA.GetStopLimit(trade.Symbol);
      PropertyChanged+=OnTradeEntryViewModelPropertyChanged;
      UpdateProperties();
    }
    public override SaveParameters GetSaveParameters()
    {
      return null;
    }
    public override void SetSaveParameters(SaveParameters saveParameters)
    {
    }
    public override bool CanPersist()
    {
      return false;
    }
    public void SetActiveTrade(BlotterTradeModel trade)
    {
      this.trade = trade;
      UpdateProperties();
    }
    private void UpdateProperties()
    {
      base.OnPropertyChanged("Symbol");
      base.OnPropertyChanged("Price");
      base.OnPropertyChanged("CompanyName");
      base.OnPropertyChanged("TradeDate");
      base.OnPropertyChanged("SelectedTradeType");
      base.OnPropertyChanged("SelectedAccount");
      base.OnPropertyChanged("SelectedStatus");
      base.OnPropertyChanged("TradeId");
      base.OnPropertyChanged("Shares");
      base.OnPropertyChanged("Exposure");
      base.OnPropertyChanged("AvailableCash");
    }
    private void OnTradeEntryViewModelPropertyChanged(object sender, PropertyChangedEventArgs eventArgs)
    {
      if (eventArgs.PropertyName.Equals("Symbol"))
      {
        if(null!=trade && null!=trade.Symbol)
        {
          if(-1==trade.TradeId) // only suggest the price for a new trade (i.e.) a trade that has not yet been assigned a tradeid
          {
            Price price=PricingDA.GetPrice(trade.Symbol,trade.TradeDate);
            if(null==price) price=PricingDA.GetPrice(trade.Symbol);
            if(null!=price)trade.Price=price.Close;
            base.OnPropertyChanged("Price");
          }
          String companyName = PricingDA.GetNameForSymbol(trade.Symbol);
          if (null != companyName)
          {
            trade.CompanyName = companyName;
            base.OnPropertyChanged("CompanyName");
          }
        }
      }
      else if (eventArgs.PropertyName.Equals("TradeDate"))
      {
        base.OnPropertyChanged("Price");
      }
      else if (eventArgs.PropertyName.Equals("SelectedAccount") || eventArgs.PropertyName.Equals("Shares") || eventArgs.PropertyName.Equals("Price") || eventArgs.PropertyName.Equals("SellPrice"))
      {
        base.OnPropertyChanged("AvailableCash");
      }
    }
    public String TradeId
    {
      get { return -1==trade.TradeId?Constants.CONST_DASHES:trade.TradeId.ToString(); }
      set { ;}
    }
    public List<String> TradeTypeOptions
    {
      get { return new List<String>() { "Buy", "Sell" }; }
    }
// Buy/Sell
    public String SelectedTradeType
    {
      get 
      {
        if (null == trade.BuySell) return null;
        else if (trade.BuySell.Equals("S")) return "Sell";
        else if (trade.BuySell.Equals("B")) return "Buy";
        else return null;
      }
      set
      {
        if(String.IsNullOrEmpty(value)) return;
        trade.BuySell = value.Equals("Buy") ? "B" : "S";
        if (trade.BuySell.Equals("B"))
        {
          trade.Status = "OPEN";
          trade.SellPrice = double.NaN;
          trade.SellDate = Utility.Epoch;
          base.OnPropertyChanged("SellPrice");
          base.OnPropertyChanged("SellDate");
        }
        else
        {
          trade.Status = "CLOSED";
        }
        base.OnPropertyChanged("SelectedStatus");
        base.OnPropertyChanged("SelectedTradeType");
      }
    }
// ***************************************** A C C O U N T ***************************
    public List<String> AccountOptions
    {
      get { return PortfolioDA.GetAccounts(); }
    }
    public String SelectedAccount
    {
      get 
      { 
        return null==trade.Account||trade.Account.Equals("") ? null : trade.Account; 
      }
      set 
      { 
        trade.Account = value;
        base.OnPropertyChanged("SelectedAccount");
      }
    }
//************************************************************************************
    public List<String> TradeStatusOptions
    {
      get {return new List<String>(){"OPEN","CLOSED"}; }
    }
    public String SelectedStatus
    {
      get 
      { 
        return null==trade.Status||trade.Status.Equals("") ? null : trade.Status; 
      }
    }
    public DateTime TradeDate
    {
      get { return trade.TradeDate; }
      set 
      { 
        trade.TradeDate = value;
        Price price = null;
        if (!Utility.IsEpoch(trade.TradeDate) && !trade.TradeDate.Date.Equals(DateTime.Now.Date))
        {
          price = PricingDA.GetPrice(trade.Symbol, trade.TradeDate);
        }
        else
        {
          price = MarketDataHelper.GetLatestPrice(trade.Symbol);
          if (null == price) price = PricingDA.GetPrice(trade.Symbol);
        }
        if (null != price)
        {
          trade.Price = price.Close;
          base.OnPropertyChanged("TradeDate");
        }
      }
    }
    public String Symbol
    {
      get { return trade.Symbol; }
      set
      {
        trade.Symbol = value;
        trade.Symbol = trade.Symbol.ToUpper();
        base.OnPropertyChanged("Symbol");
      }
    }
    public double Shares
    {
      get
      {
        return trade.Shares;
      }
      set
      {
        trade.Shares = value;
        base.OnPropertyChanged("Shares");
        base.OnPropertyChanged("Exposure");
      }
    }
    public String CompanyName
    {
      get { return trade.CompanyName; }
      set
      {
        trade.CompanyName = value;
        base.OnPropertyChanged("CompanyName");
      }
    }
    public String Exposure
    {
      get { return Utility.FormatCurrency(trade.Exposure); }
      set { ;}
    }
    public String Price
    {
      get
      {
        return Utility.FormatPrice(trade.Price);
      }
      set
      {
        trade.Price = Utility.ParseCurrency(value);
        base.OnPropertyChanged("Price");
        base.OnPropertyChanged("Exposure");
      }
    }
    public String StopLimit
    {
      get
      {
        if(null==stopLimit)return Constants.NA;
        return Utility.FormatCurrency(stopLimit.StopPrice,2);
      }
      set
      {
        if(String.IsNullOrEmpty(value))stopLimit=null;
        else
        {
          if(null==stopLimit)
          {
            stopLimit=new StopLimit();
            stopLimit.Symbol=trade.Symbol;
            stopLimit.Active=1;
            stopLimit.StopType=StopLimitConstants.STOP_QUOTE;
          }
          stopLimit.StopPrice=Utility.ParseCurrency(value);
        }
        base.OnPropertyChanged("StopLimit");
      }
    }
    public String SellPrice
    {
      get
      {
        return Utility.FormatPrice(trade.SellPrice);
      }
      set
      {
        if (!trade.Status.Equals("CLOSED")) return;
        trade.SellPrice = Utility.ParseCurrency(value);
        base.OnPropertyChanged("SellPrice");
      }
    }
    public DateTime? SellDate
    {
      get 
      {
        if (Utility.IsEpoch(trade.SellDate)) return null;
        return trade.SellDate; 
      }
      set
      {
        trade.SellDate = value.Value;
        base.OnPropertyChanged("SellDate");
      }
    }
    public String Commission
    {
      get
      {
        return Utility.FormatCurrency(trade.Commission);
      }
      set
      {
        trade.Commission = Utility.ParseCurrency(value);
      }
    }
    public String Status
    {
      get
      { 
        return statusText;
      }
      set 
      { 
        if(!String.IsNullOrEmpty(value))
        {
          statusText = value; 
          base.OnPropertyChanged("Status");
        }
      }
    }
    public String AvailableCash
    {
      get
      {
        double availableCash = CashDA.GetBalance();
        if(null!=SelectedAccount)availableCash=CashDA.GetBalance(SelectedAccount);
        if (null == trade.BuySell) return Utility.FormatCurrency(availableCash);
        if(trade.BuySell.Equals("S") && double.IsNaN(trade.SellPrice) && double.IsNaN(trade.Shares))return Utility.FormatCurrency(availableCash);
        if(trade.BuySell.Equals("B") && double.IsNaN(trade.Price) && double.IsNaN(trade.Shares)) return Utility.FormatCurrency(availableCash);
        if(trade.BuySell.Equals("S")) availableCash += trade.SellPrice * trade.Shares;
        if(trade.BuySell.Equals("B")) availableCash -= trade.Price * trade.Shares;
        if (!double.IsNaN(trade.Commission)) availableCash -= trade.Commission;
        return Utility.FormatCurrency(availableCash);                            
      }
    }
// *******************************************************************************************************
// ****************************************** S A V E  C O M M A N D *************************************
// *******************************************************************************************************
    public ICommand SaveCommand
    {
      get
      {
        if(saveCommand == null)
        {
          saveCommand = new RelayCommand(param => this.Save(),param => this.CanSave);
        }
        return saveCommand;
      }
    }
    public void Save()
    {
      if (!tradeRepository.ContainsTrade(trade))
      {
        tradeRepository.AddTrade(trade);
        WatchListDA.AddToWatchList(trade.Symbol);
        base.OnPropertyChanged("TradeId");
        base.OnPropertyChanged("DisplayName");
        statusText = "Save completed.";
      }
      else
      {
        tradeRepository.UpdateTrade(trade);
        statusText="Update completed.";
      }
      UpdateStopLimit();
      base.OnPropertyChanged("Status");
    }
    private void UpdateStopLimit()
    {
      if(null==stopLimit&&PortfolioDA.HasStopLimit(trade.Symbol))PortfolioDA.DeleteStopLimit(trade.Symbol);
      else if(null!=stopLimit)PortfolioDA.InsertUpdateStopLimit(stopLimit);
    }
    public bool CanSave
    {
      get
      {
        try
        {
          DateGenerator dateGenerator=new DateGenerator();
          if (null == trade.TradeDate || Utility.IsEpoch(trade.TradeDate)) 
          {
            statusText=String.Format("Invalid Trade Date.");
            return false;
          }
          if (null == trade.BuySell || !(trade.BuySell.ToUpper().Equals("B") || trade.BuySell.ToUpper().Equals("S"))) 
          {
            statusText=String.Format("BuySell must contain either BUY or SELL.");
            return false;
          }
          if (null == trade.Status || (!trade.Status.Equals("OPEN") && !trade.Status.Equals("CLOSED")))
          {
            statusText=String.Format("Status must contain either OPEN or CLOSED.");
            return false;
          }
          if(null!=trade.Status&&(trade.Status.Equals("CLOSED")||trade.BuySell.ToUpper().Equals("S"))&&double.IsNaN(trade.SellPrice))
          {
            statusText="Close position requires a valid selling price.";
            return false;
          }
          if(null!=trade.Status&&(trade.Status.Equals("CLOSED") || trade.BuySell.ToUpper().Equals("S")) && Utility.IsEpoch(trade.SellDate))
          {
            statusText="Close position requires a valid sell date.";
            return false;
          }
          if(null!=trade.Status&&(trade.Status.Equals("OPEN")||trade.BuySell.ToUpper().Equals("B"))&&!Utility.IsEpoch(trade.SellDate))
          {
            statusText="An open position cannot contain a sell date.";
            return false;
          }
          if(null==trade.Symbol) 
          {
            statusText="A trade entry must contain a valid symbol.";
            return false;
          }
          if (0 == trade.Shares) 
          {
            statusText="A trade entry must contain a number of shares.";
            return false;
          }
          if (null == trade.Account || "".Equals(trade.Account)) 
          {
            statusText="A trade entry must contain a valid account.";
            return false;
          }
          if (0 == trade.Price)
          {
            statusText="A trade entry must contain a valid price that is greater than zero.";
            return false;
          }
          if(!Utility.IsEpoch(trade.TradeDate) && !dateGenerator.IsMarketOpen(trade.TradeDate))
          {
            statusText=String.Format("Trade date must be a valid market date. {0} is a holiday or weekend.  ",Utility.DateTimeToStringMMSDDSYYYY(trade.TradeDate));
            return false;
          }
          if(!Utility.IsEpoch(trade.SellDate)&&!dateGenerator.IsMarketOpen(trade.SellDate))
          {
            statusText=String.Format("Sell date must be a valid market date.  {0} is a holiday or weekend.  ",Utility.DateTimeToStringMMSDDSYYYY(trade.SellDate));
            return false;
          }
          statusText="Form is validated.";
          return true;
        }
        catch(Exception exception)
        {
          statusText=exception.ToString();
          return false;
        }
        finally
        {
          base.OnPropertyChanged("Status");
        }
      }
    }
  }
}
