using System;
using System.Windows.Input;
using System.ComponentModel;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Text;
using System.Linq;
using System.Threading.Tasks;
using System.Threading;
using MarketData.DataAccess;
using MarketData.MarketDataModel;
using MarketData.Utils;
using TradeBlotter.Command;
using TradeBlotter.Cache;
using TradeBlotter.Model;
using Telerik.Charting;
using Telerik.Windows.Controls.Charting;
using MarketData;

namespace TradeBlotter.ViewModels
{
  public class SectorViewModel : WorkspaceViewModel
  {
    private PortfolioTrades portfolioTrades = null;
    private List<PieDataPoint> sectorIndustryDataPointsExposure = null;
    private List<PieDataPoint> sectorIndustryDataPointsContribution = null;
    private List<String> selectedOperations = null;
    private String selectedAccount = Constants.CONST_ALL;
    private String selectedOperation;
    private RelayCommand refreshCommand;
    private bool useRealPrice = false;
    private bool includeCash = false;
    private bool busyIndicator = false;
    private double cashBalance = double.NaN;

    public SectorViewModel()
    {
      base.DisplayName = "Asset Allocation";
      selectedOperations = new List<String>();
      selectedOperations.Add("Sector");
      selectedOperations.Add("Industry");
			selectedOperations.Add("Names");
      selectedOperation = selectedOperations[0];
      PropertyChanged += OnSectorViewModelPropertyChanged;
      base.OnPropertyChanged("SelectedOperation");
    }
    public override SaveParameters GetSaveParameters()
    {
      return null;
    }
    public override void SetSaveParameters(SaveParameters saveParameters)
    {
    }
    public override bool CanPersist()
    {
      return false;
    }
    protected override void OnDispose()
    {
    }
    public bool BusyIndicator
    {
      get
      {
        return busyIndicator;
      }
      set
      {
        busyIndicator = value;
        base.OnPropertyChanged("BusyIndicator");
      }
    }
    private void OnSectorViewModelPropertyChanged(object sender, PropertyChangedEventArgs eventArgs)
    {
      if (eventArgs.PropertyName.Equals("SelectedOperation") || eventArgs.PropertyName.Equals("UseRealPrice") || eventArgs.PropertyName.Equals("IncludeCash") || eventArgs.PropertyName.Equals("SelectedAccount"))
      {
        BusyIndicator = true;
        Task workerTask = Task.Factory.StartNew(() =>
        {
          if (null == portfolioTrades)portfolioTrades = PortfolioDA.GetOpenTrades();
          CreateSectorIndustryExposure(portfolioTrades, selectedOperation);
          CreateSectorIndustryContribution(portfolioTrades, selectedOperation);
        });
        workerTask.ContinueWith((continuation)=>
        {
          BusyIndicator = false;
          base.OnPropertyChanged("PieDataExposure");
          base.OnPropertyChanged("PieDataContribution");
          base.OnPropertyChanged("TitleExposure");
          base.OnPropertyChanged("TitleContribution");
        });
      }
    }
    public PortfolioTrades GetAccountTrades()
    {
      if (Constants.CONST_ALL.Equals(selectedAccount)) return portfolioTrades;
      return portfolioTrades.FilterAccount(selectedAccount);
    }
    private void CreateSectorIndustryExposure(PortfolioTrades portfolioTrades, String sectorIndustry)
    {
      try
      {
        double totalExposure = 0.00;
        Dictionary<String, double> sectorIndustryExposure = new Dictionary<String, double>();
        PortfolioTrades accountTrades = GetAccountTrades();
        cashBalance = double.NaN;
        if (includeCash)
        {
//          double cashBalance = CashDA.GetBalance();
          cashBalance = CashDA.GetBalance();
          if (Constants.CONST_ALL.Equals(selectedAccount)) cashBalance = CashDA.GetBalance();
          else cashBalance = CashDA.GetBalance(selectedAccount);
          if (!double.IsNaN(cashBalance))
          {
            totalExposure += cashBalance;
            sectorIndustryExposure.Add("Cash", cashBalance);
          }
        }
        foreach (PortfolioTrade portfolioTrade in accountTrades)
        {
          totalExposure += portfolioTrade.Price * portfolioTrade.Shares;
          if (sectorIndustry.Equals("Sector"))
          {
            String sector = PricingDA.GetSectorForSymbol(portfolioTrade.Symbol);
            if(null==sector)sector="Unclassified";
            if (sectorIndustryExposure.ContainsKey(sector))
            {
              sectorIndustryExposure[sector] += (portfolioTrade.Price * portfolioTrade.Shares);
            }
            else
            {
              sectorIndustryExposure.Add(sector, portfolioTrade.Price * portfolioTrade.Shares);
            }
          }
          else if (sectorIndustry.Equals("Industry"))
          {
            String industry = PricingDA.GetIndustryForSymbol(portfolioTrade.Symbol);
            if(null==industry)industry="Unclassified";
            if (sectorIndustryExposure.ContainsKey(industry))
            {
              sectorIndustryExposure[industry] += (portfolioTrade.Price * portfolioTrade.Shares);
            }
            else
            {
              sectorIndustryExposure.Add(industry, portfolioTrade.Price * portfolioTrade.Shares);
            }
          }
				  else
				  {
            if (sectorIndustryExposure.ContainsKey(portfolioTrade.Symbol))
            {
              sectorIndustryExposure[portfolioTrade.Symbol] += (portfolioTrade.Price * portfolioTrade.Shares);
            }
            else
            {
              sectorIndustryExposure.Add(portfolioTrade.Symbol, portfolioTrade.Price * portfolioTrade.Shares);
            }
				  }
        }
        List<String> keys = new List<String>(sectorIndustryExposure.Keys);
        sectorIndustryDataPointsExposure = new List<PieDataPoint>();
        foreach (String key in keys)
        {
          sectorIndustryExposure[key] = (sectorIndustryExposure[key] / totalExposure) * 100.00;
          PieDataPoint pieDataPoint = new PieDataPoint();
          pieDataPoint.Label = key + " " + String.Format("{0:F}", sectorIndustryExposure[key]) + "%";
          pieDataPoint.Value = sectorIndustryExposure[key];
          sectorIndustryDataPointsExposure.Add(pieDataPoint);
        }
      }
      catch(Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Exception:{0}",exception.ToString()));
      }
    }
    private void CreateSectorIndustryContribution(PortfolioTrades portfolioTrades, String sectorIndustry)
    {
      double totalExposure = 0.00;
      Dictionary<String, double> sectorIndustryContribution = new Dictionary<String, double>();
      PortfolioTrades accountTrades = GetAccountTrades();
      foreach (PortfolioTrade portfolioTrade in accountTrades)
      {
        Price price = null;
        if (useRealPrice) price = PriceCache.GetInstance().GetLatestPrice(portfolioTrade.Symbol);
        if (null == price) price = PricingDA.GetPrice(portfolioTrade.Symbol);
        totalExposure += price.Close * portfolioTrade.Shares;
        if (sectorIndustry.Equals("Sector"))
        {
          String sector = PricingDA.GetSectorForSymbol(portfolioTrade.Symbol);
          if(null==sector)sector="Unclassified";
          if (sectorIndustryContribution.ContainsKey(sector))
          {
            sectorIndustryContribution[sector] += (price.Close * portfolioTrade.Shares);
          }
          else
          {
            sectorIndustryContribution.Add(sector, price.Close * portfolioTrade.Shares);
          }
        }
        else if(sectorIndustry.Equals("Industry"))
        {
          String industry = PricingDA.GetIndustryForSymbol(portfolioTrade.Symbol);
          if(null==industry)industry="Unclassified";
          if (sectorIndustryContribution.ContainsKey(industry))
          {
            sectorIndustryContribution[industry] += (price.Close * portfolioTrade.Shares);
          }
          else
          {
            sectorIndustryContribution.Add(industry, price.Close * portfolioTrade.Shares);
          }
        }
				else
				{
          if (sectorIndustryContribution.ContainsKey(portfolioTrade.Symbol))
          {
            sectorIndustryContribution[portfolioTrade.Symbol] += (price.Close * portfolioTrade.Shares);
          }
          else
          {
            sectorIndustryContribution.Add(portfolioTrade.Symbol, price.Close * portfolioTrade.Shares);
          }
				}
      }
      List<String> keys = new List<String>(sectorIndustryContribution.Keys);
      sectorIndustryDataPointsContribution = new List<PieDataPoint>();
      foreach (String key in keys)
      {
        sectorIndustryContribution[key] = (sectorIndustryContribution[key] / totalExposure) * 100.00;
        PieDataPoint pieDataPoint = new PieDataPoint();
        pieDataPoint.Label = key + " " + String.Format("{0:F}", sectorIndustryContribution[key]) + "%";
        pieDataPoint.Value = sectorIndustryContribution[key];
        sectorIndustryDataPointsContribution.Add(pieDataPoint);
      }
    }
    public List<PieDataPoint> PieDataExposure
    {
      get
      {
        return sectorIndustryDataPointsExposure;
      }
    }
    public List<PieDataPoint> PieDataContribution
    {
      get
      {
        return sectorIndustryDataPointsContribution;
      }
    }
    public bool UseRealPrice
    {
      get { return useRealPrice; }
      set { useRealPrice = value; base.OnPropertyChanged("UseRealPrice"); }
    }
    public bool IncludeCash
    {
      get { return includeCash; }
      set { includeCash = value; base.OnPropertyChanged("IncludeCash"); }
    }
    public List<String> Accounts
    {
      get
      {
        if (null == portfolioTrades) return null;
        List<String> accounts = portfolioTrades.Accounts;
        accounts.Insert(0, Constants.CONST_ALL);
        return accounts;
      }
    }
    public String SelectedAccount
    {
      get { return selectedAccount; }
      set { selectedAccount = value; base.OnPropertyChanged("SelectedAccount"); }
    }
    public ICommand RefreshCommand
    {
      get
      {
        if (null == refreshCommand)
        {
          refreshCommand = new RelayCommand(param => this.Refresh(), param => this.CanRefresh);
        }
        return refreshCommand;
      }
    }
    public bool CanRefresh
    {
      get { return true; }
    }
    public void Refresh()
    {
      base.OnPropertyChanged("SelectedOperation");
    }
    public List<String> SectorIndustry
    {
      get { return selectedOperations; }
    }
    public String SelectedOperation
    {
      get { return selectedOperation; }
      set { selectedOperation = value; base.OnPropertyChanged("SelectedOperation"); }
    }
    public String TitleExposure
    {
      get 
      {
        StringBuilder sb = new StringBuilder();
        sb.Append(base.DisplayName).Append(" - ");
        sb.Append(SelectedOperation);
        sb.Append(" Breakdown ");
        if (Constants.CONST_ALL.Equals(selectedAccount)) sb.Append("All Accounts ");
        else sb.Append("Account ").Append(selectedAccount);
        sb.Append(" (Exposure)");
        if (includeCash)
        {
          sb.Append(" (").Append("Available Cash ").Append(Utility.FormatCurrency(cashBalance)).Append(")");
        }
        return sb.ToString();
      }
    }
    public String TitleContribution
    {
      get 
      {
        StringBuilder sb = new StringBuilder();
        sb.Append(base.DisplayName).Append(" - ");
        sb.Append(SelectedOperation);
        sb.Append(" Breakdown ");
        if (Constants.CONST_ALL.Equals(selectedAccount)) sb.Append("All Accounts ");
        else sb.Append("Account ").Append(selectedAccount);
        sb.Append(" (Contribution)");
        return sb.ToString();
      }
    }
  }
}
