using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using MarketData.Numerical;
using MarketData.Utils;

namespace MarketData.MarketDataModel
{
  public class TimeSeriesCollection : List<TimeSeriesElement>
  {
    public TimeSeriesCollection()
    {
    }
    public TimeSeriesCollection(List<TimeSeriesElement> elements)
    {
      if (null == elements) return;
      foreach (TimeSeriesElement element in elements) Add(element);
    }
// Returns the intersection of both sets on the common dates 
    public static AlignDatesResult AlignDates(TimeSeriesCollection tsA,TimeSeriesCollection tsB)
    {
      List<DateTime> tsADates=(from ts in tsA select ts.AsOf).ToList();
      List<DateTime> tsBDates=(from ts in tsB select ts.AsOf).ToList();

      List<DateTime> tsIntersect=tsADates.Intersect(tsBDates).Distinct().ToList();
      tsA=new TimeSeriesCollection((from ts in tsA where tsIntersect.Any(x=>x.Equals(ts.AsOf)) select ts).ToList());
      tsB=new TimeSeriesCollection((from ts in tsB where tsIntersect.Any(x=>x.Equals(ts.AsOf)) select ts).ToList());
      return new AlignDatesResult(tsA,tsB);
    }

    public float[] ToFloat()
    {
      float[] values = new float[Count];
      for (int index = 0; index < Count; index++) values[index] = (float)this[index].Value;
      return values;
    }
    public bool ContainsNegativeValues()
    {
      int count= (from TimeSeriesElement element in this where element.Value < 0 select element).Count();
      return count > 0 ? true : false;
    }
    public TimeSeriesCollection RemoveNegativeValues()
    {
      return new TimeSeriesCollection((from TimeSeriesElement element in this where element.Value >= 0 select element).ToList());
    }
    public override String ToString()
    {
      StringBuilder sb=new StringBuilder();
      if(0==this.Count)return null;
      sb.Append(TimeSeriesElement.StringForType(this[0].Type));
      sb.Append(",");
      for(int index=0;index<this.Count;index++)
      {
        TimeSeriesElement timeSeriesElement=this[index];
        String strValue=Utility.AddQuotes(Utility.FormatNumber(timeSeriesElement.Value,2,true));
        String strAsOf=timeSeriesElement.AsOf.ToShortDateString();
        String strItem=String.Format("{0}({1})",strAsOf,strValue);
        sb.Append(strItem);
        if(index<this.Count-1)sb.Append(",");
      }
      return sb.ToString();
    }
  }
  public class TimeSeriesElement
  {
    public enum ElementType { INVALID, OTHER,BVPS, EPS, OperatingCashflow,FreeCashflow,Revenue,QuarterlyRevenue,Inventory,QuarterlyInventory,ROIC,OperatingIncome,WorkingCapital,ROA,NetIncomeAvailableToCommonShareholders,TaxRate,InterestExpense,COGS,AccountsReceivable,SGA};
    private String symbol;
    private DateTime asof;
    private ElementType elementType;
    private double value;
    private String otherType;
    private DateTime modified;

    public TimeSeriesElement()
    {
    }
    public String Symbol
    {
      get { return symbol; }
      set { symbol = value; }
    }
    public DateTime AsOf
    {
      get { return asof; }
      set { asof = value; }
    }
    public double Value
    {
      get { return value; }
      set { this.value = value; }
    }
    public String OtherType
    {
      get{return otherType;}
      set{otherType=value;}
    }
    public TimeSeriesElement.ElementType Type
    {
      get { return elementType; }
      set { elementType = value; }
    }
    public DateTime Modified
    {
      get{ return modified;}
      set{modified=value;}
    }
    public static String StringForType(TimeSeriesElement.ElementType type)
    {
      switch (type)
      {
        case ElementType.INVALID :
          return "???";
        case ElementType.BVPS:
          return "bvps";
        case ElementType.EPS:
          return "eps";
        case ElementType.OperatingCashflow :
          return "operating_cashflow";
        case ElementType.FreeCashflow:
          return "free_cashflow";
        case ElementType.Revenue:
          return "revenue";
        case ElementType.QuarterlyRevenue:
          return "quarterly_revenue";
        case ElementType.OperatingIncome:
          return "operating_income";
        case ElementType.ROIC:
          return "roic";
        case ElementType.WorkingCapital:
          return "working_capital";
        case ElementType.ROA:
          return "roa";
        case ElementType.TaxRate :
          return "tax_rate";
        case ElementType.InterestExpense:
          return "interest_expense";
        case ElementType.NetIncomeAvailableToCommonShareholders:
          return "net_income_available_to_common_shareholders";
        case ElementType.COGS:
          return "cogs";
        case ElementType.Inventory :
          return "inventory";
        case ElementType.SGA :
          return "sg&a";
        case ElementType.AccountsReceivable :
          return "accounts receivable";
        default:
          return "???";
      }
    }
  }
  public class AlignDatesResult
  {
    public AlignDatesResult()
    {
    }
    public AlignDatesResult(TimeSeriesCollection collectionA,TimeSeriesCollection collectionB)
    {
      CollectionA=collectionA;
      CollectionB=collectionB;
    }
    public TimeSeriesCollection CollectionA{get;set;}
    public TimeSeriesCollection CollectionB{get;set;}
  }
}
