using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using TradeBlotter.Model;
using MarketData.MarketDataModel;
using MarketData.DataAccess;

namespace TradeBlotter.DataAccess
{
  public class TradeRepository
  {
    private readonly List<BlotterTradeModel> trades;
    private static TradeRepository instance=null;

    private TradeRepository()
    {
      Dictionary<String,String> companyNameCache=new Dictionary<String,String>();
      trades = new List<BlotterTradeModel>();
      PortfolioTrades portfolioTrades = PortfolioDA.GetTrades();
      if (null == portfolioTrades || 0 == portfolioTrades.Count) return;
      foreach (PortfolioTrade portfolioTrade in portfolioTrades)
      {
        BlotterTradeModel blotterTrade = BlotterTradeModel.CreateTrade();
        blotterTrade.TradeId = portfolioTrade.TradeId;
        blotterTrade.Symbol=portfolioTrade.Symbol;
        blotterTrade.TradeDate=portfolioTrade.TradeDate;
        blotterTrade.Shares=portfolioTrade.Shares;
        blotterTrade.BuySell=portfolioTrade.BuySell;
        blotterTrade.Price=portfolioTrade.Price;
        blotterTrade.Commission = portfolioTrade.Commission;
        blotterTrade.Account = portfolioTrade.Account;
        blotterTrade.Status = portfolioTrade.Status;
        if(companyNameCache.ContainsKey(portfolioTrade.Symbol))blotterTrade.CompanyName=companyNameCache[portfolioTrade.Symbol];
        else
        {
          String companyName=PricingDA.GetNameForSymbol(portfolioTrade.Symbol);
          if(null!=companyName)
          {
            companyNameCache.Add(portfolioTrade.Symbol,companyName);
            blotterTrade.CompanyName=companyNameCache[portfolioTrade.Symbol];
          }
        }
//        blotterTrade.CompanyName = PricingDA.GetNameForSymbol(portfolioTrade.Symbol);
        blotterTrade.SellPrice = portfolioTrade.SellPrice;
        blotterTrade.SellDate = portfolioTrade.SellDate;
        trades.Add(blotterTrade);
      }
    }
    public static TradeRepository GetInstance()
    {
      lock(typeof(TradeRepository))
      {
        if(null==instance)instance=new TradeRepository();
        return instance;
      }
    }
    public event EventHandler<TradeAddedEventArgs> TradeAdded;
    public bool AddTrade(BlotterTradeModel trade)
    {
      if (null == trade) throw new ArgumentNullException("trade");
      if (ContainsTrade(trade)) return false;
      int tradeId = PortfolioDA.AddTrade(trade);
      if (-1 == tradeId) return false;
      trade.TradeId = tradeId;
      trades.Add(trade);
      AdjustCash(trade);
      if (null != this.TradeAdded) this.TradeAdded(this, new TradeAddedEventArgs(trade));
      return true;
    }
    public bool UpdateTrade(BlotterTradeModel trade)
    {
      bool result = false;
      BlotterTradeModel blotterTradeModel = GetTrade(trade.TradeId);
      if (null == blotterTradeModel) return false;
      blotterTradeModel.CopyFrom(trade);
      result=PortfolioDA.UpdateTrade(trade);
      if (true == result) AdjustCash(trade);
      return result;
    }
    public bool ContainsTrade(BlotterTradeModel searchTrade)
    {
      var existingTrades=from trade in trades where trade.TradeId==searchTrade.TradeId select trade;
      return 0 == existingTrades.Count() ? false : true;
    }
    public BlotterTradeModel GetTrade(int tradeId)
    {
      var existingTrades = from trade in trades where trade.TradeId == tradeId select trade;
      if (0 == existingTrades.Count()) return null;
      return existingTrades.FirstOrDefault();
    }
    public void Remove(int tradeId)
    {
      var theTrades=from trade in trades where trade.TradeId==tradeId select trade;
      PortfolioDA.DeleteTrade(theTrades.ElementAt(0).TradeId);
      trades.Remove(theTrades.ElementAt(0));
    }
    public List<BlotterTradeModel> GetTrades()
    {
      return new List<BlotterTradeModel>(trades);
    }
// Accounting 
    private void AdjustCash(BlotterTradeModel trade)
    {
      CashTransaction cashTransaction = new CashTransaction();
      StringBuilder sb = new StringBuilder();
      cashTransaction.Account = trade.Account;
      if(trade.BuySell.Equals("B"))
      {
        cashTransaction.TransactionDate = trade.TradeDate;
        cashTransaction.Debit = trade.Shares * trade.Price;
        sb.Append("Buy").Append(" ").Append(trade.Shares.ToString());
        sb.Append(" of ").Append(trade.Symbol).Append(" @").Append(String.Format("{0:C}", trade.Price));
      }
      else
      {
        cashTransaction.TransactionDate = trade.SellDate;
        cashTransaction.Credit = trade.Shares * trade.SellPrice;
        sb.Append("Sell").Append(" ").Append(trade.Shares.ToString());
        sb.Append(" of ").Append(trade.Symbol).Append(" @").Append(String.Format("{0:C}", trade.SellPrice));
      }
      cashTransaction.Description = sb.ToString();
      CashDA.AddTransaction(cashTransaction);
      if (trade.Commission > 0)
      {
        cashTransaction = new CashTransaction();
        cashTransaction.Account = trade.Account;
        if(trade.BuySell.Equals("B"))cashTransaction.TransactionDate = trade.TradeDate;
        else cashTransaction.TransactionDate = trade.SellDate;
        cashTransaction.Debit = trade.Commission;
        sb=new StringBuilder();
        sb.Append("Commission: ").Append(trade.Symbol).Append(" ").Append(String.Format("{0:C}", trade.Commission));
        cashTransaction.Description = sb.ToString();
        CashDA.AddTransaction(cashTransaction);
      }
    }
  }
}
