using System;
using System.Collections.Generic;
using System.Net.Http.Headers;
using System.Text;
using MarketData.Utils;

namespace MarketData.MarketDataModel
{
  public class Fundamentals : List<Fundamental>
  {
    public Fundamentals()
    {
    }
  }
  public class Fundamental
  {
    private String symbol;
    private DateTime asOf;
    private DateTime nextEarningsDate;
    private double beta;
    private double low52;
    private double high52;
    private Int64 volume;
    private double marketCap;
    private double pe;
    private double eps;
    private double peg;
    private double returnOnAssets;
    private double returnOnEquity;
    private double totalCash;
    private double totalDebt;
    private double sharesOutstanding;
    private double revenue;
    private double revenuePerShare;
    private double qtrlyRevenueGrowth;
    private double grossProfit;
    private double ebitda;
    private double netIncomeAvailableToCommon;
    private double bookValuePerShare;
    private double operatingCashflow;
    private double leveragedFreeCashflow;
    private double equity;
    private double trailingPE;
    private double enterpriseValue;
    private double ebit;
    private double debtToEquity;
    private String source;

    public Fundamental()
    {
    }
    public String Symbol
    {
      get { return symbol; }
      set { symbol = value; }
    }
    public DateTime AsOf
    {
      get { return asOf; }
      set { asOf = value; }
    }
    public String Source
    {
      get { return source; }
      set { source = value; }
    }
    public DateTime NextEarningsDate
    {
      get { return nextEarningsDate; }
      set { nextEarningsDate = value; }
    }
    public double Beta
    {
      get { return beta; }
      set { beta = value; }
    }
    public double Low52
    {
      get { return low52; }
      set { low52 = value; }
    }
    public double High52
    {
      get { return high52; }
      set { high52 = value; }
    }
    public Int64 Volume
    {
      get { return volume; }
      set { volume = value; }
    }
    public double MarketCap
    {
      get { return marketCap; }
      set { marketCap = value; }
    }
    public double PE
    {
      get { return pe; }
      set { pe = value; }
    }
    public double EPS
    {
      get { return eps; }
      set { eps = value; }
    }
    public double PEG
    {
      get { return peg; }
      set { peg = value; }
    }
    public double ReturnOnAssets
    {
      get { return returnOnAssets; }
      set { returnOnAssets = value; }
    }
    public double ReturnOnEquity
    {
      get { return returnOnEquity; }
      set { returnOnEquity = value; }
    }
    public double TotalCash
    {
      get { return totalCash; }
      set { totalCash = value; }
    }
    public double TotalDebt
    {
      get { return totalDebt; }
      set { totalDebt = value; }
    }
    public double SharesOutstanding
    {
      get { return sharesOutstanding; }
      set { sharesOutstanding = value; }
    }
    public double Revenue
    {
      get { return revenue; }
      set { revenue = value; }
    }
    public double RevenuePerShare
    {
      get { return revenuePerShare; }
      set { revenuePerShare = value; }
    }
    public double QtrlyRevenueGrowth
    {
      get { return qtrlyRevenueGrowth; }
      set { qtrlyRevenueGrowth = value; }
    }
    public double GrossProfit
    {
      get { return grossProfit; }
      set { grossProfit=value; }
    }
    public double EBITDA
    {
      get { return ebitda; }
      set { ebitda = value; }
    }
    public double EBIT
    {
      get{return ebit;}
      set{ebit=value;}
    }
    public double EnterpriseValue
    {
      get{return enterpriseValue;}
      set{enterpriseValue=value;}
    }
    public double NetIncomeAvailableToCommon
    {
      get { return netIncomeAvailableToCommon; }
      set { netIncomeAvailableToCommon = value; }
    }
    public double BookValuePerShare
    {
      get { return bookValuePerShare; }
      set { bookValuePerShare = value; }
    }
    public double OperatingCashflow
    {
      get {return operatingCashflow; }
      set { operatingCashflow = value; }
    }
    public double LeveragedFreeCashflow
    {
      get { return leveragedFreeCashflow; }
      set { leveragedFreeCashflow = value; }
    }
    public double Equity             // on the fly as record is pulled from database
    {
      get { return equity; }
      set { equity = value; }
    }
    public double TrailingPE
    {
      get { return trailingPE; }
      set { trailingPE = value; }
    }
    public double DebtToEquity
    {
      get{return debtToEquity;}
      set{debtToEquity=value;}
    }
// If columns are added to this object must ensure that the columns are also added to the MergeFrom, IsZero, and GetLoad() methods so that the consistency checks can still function properly
// Do not include a comparison of the AsOf date.  The prior fundamental will always have an AsOf date that precedes the one that we fetch.
// In contrast, the AsOf date in the financial statements is the statement date and we use the AsOf date as a comparison there.
// The idea here is to ensure that we do not lose any fidelity of the fundamental data if elements are missing in the current fetch but were present in a previous fetch.
    public void MergeFrom(Fundamental previousFundamental)
    {
      if(null==previousFundamental)return;
      if(!Symbol.Equals(previousFundamental.Symbol))return;
      if(Utility.IsEpoch(NextEarningsDate))NextEarningsDate=previousFundamental.NextEarningsDate;
      if(Utility.IsZeroOrNaN(Beta))Beta=previousFundamental.Beta;
      if(Utility.IsZeroOrNaN(Low52))Low52=previousFundamental.Low52;
      if(Utility.IsZeroOrNaN(High52))High52=previousFundamental.High52;
      if(Int64.MinValue.Equals(Volume)||Int64.MaxValue.Equals(Volume))Volume=previousFundamental.Volume;
      if(Utility.IsZeroOrNaN(MarketCap))MarketCap=previousFundamental.MarketCap;
      if(Utility.IsZeroOrNaN(PE))PE=previousFundamental.PE;
      if(Utility.IsZeroOrNaN(EPS))EPS=previousFundamental.EPS;
      if(Utility.IsZeroOrNaN(PEG))PEG=previousFundamental.PEG;
      if(Utility.IsZeroOrNaN(ReturnOnAssets))ReturnOnAssets=previousFundamental.ReturnOnAssets;
      if(Utility.IsZeroOrNaN(ReturnOnEquity))ReturnOnEquity=previousFundamental.ReturnOnEquity;
      if(Utility.IsZeroOrNaN(TotalCash))TotalCash=previousFundamental.TotalCash;
      if(Utility.IsZeroOrNaN(TotalDebt))TotalDebt=previousFundamental.TotalDebt;
      if(Utility.IsZeroOrNaN(SharesOutstanding))SharesOutstanding=previousFundamental.SharesOutstanding;
      if(Utility.IsZeroOrNaN(Revenue))Revenue=previousFundamental.Revenue;
      if(Utility.IsZeroOrNaN(RevenuePerShare))RevenuePerShare=previousFundamental.RevenuePerShare;
      if(Utility.IsZeroOrNaN(QtrlyRevenueGrowth))QtrlyRevenueGrowth=previousFundamental.QtrlyRevenueGrowth;
      if(Utility.IsZeroOrNaN(GrossProfit))GrossProfit=previousFundamental.GrossProfit;
      if(Utility.IsZeroOrNaN(EBITDA))EBITDA=previousFundamental.EBITDA;
      if(Utility.IsZeroOrNaN(EBIT))EBIT=previousFundamental.EBIT;
      if(Utility.IsZeroOrNaN(EnterpriseValue))EnterpriseValue=previousFundamental.EnterpriseValue;
      if(Utility.IsZeroOrNaN(NetIncomeAvailableToCommon))NetIncomeAvailableToCommon=previousFundamental.NetIncomeAvailableToCommon;
      if(Utility.IsZeroOrNaN(BookValuePerShare))BookValuePerShare=previousFundamental.BookValuePerShare;
      if(Utility.IsZeroOrNaN(OperatingCashflow))OperatingCashflow=previousFundamental.OperatingCashflow;
      if(Utility.IsZeroOrNaN(LeveragedFreeCashflow))LeveragedFreeCashflow=previousFundamental.LeveragedFreeCashflow;
      if(Utility.IsZeroOrNaN(Equity))Equity=previousFundamental.Equity;
      if(Utility.IsZeroOrNaN(TrailingPE))TrailingPE=previousFundamental.TrailingPE;
      if(Utility.IsZeroOrNaN(DebtToEquity))DebtToEquity=previousFundamental.DebtToEquity;
    }
    public bool IsZero()
    {
      double missingItemCount=0.00;
      double totalItems=29.00;
      double percentMissing=0.00;
      if(Utility.IsZeroOrNaN(Beta))missingItemCount++;
      if(Utility.IsZeroOrNaN(Low52))missingItemCount++;
      if(Utility.IsZeroOrNaN(High52))missingItemCount++;
      if(Utility.IsZeroOrNaN((double)Volume))missingItemCount++;
      if(Utility.IsZeroOrNaN(MarketCap))missingItemCount++;
      if(Utility.IsZeroOrNaN(PE))missingItemCount++;
      if(Utility.IsZeroOrNaN(EPS))missingItemCount++;
      if(Utility.IsZeroOrNaN(PEG))missingItemCount++;
      if(Utility.IsZeroOrNaN(ReturnOnAssets))missingItemCount++;
      if(Utility.IsZeroOrNaN(ReturnOnEquity))missingItemCount++;
      if(Utility.IsZeroOrNaN(TotalCash))missingItemCount++;
      if(Utility.IsZeroOrNaN(TotalDebt))missingItemCount++;
      if(Utility.IsZeroOrNaN(SharesOutstanding))missingItemCount++;
      if(Utility.IsZeroOrNaN(Revenue))missingItemCount++;
      if(Utility.IsZeroOrNaN(SharesOutstanding))missingItemCount++;
      if(Utility.IsZeroOrNaN(Revenue))missingItemCount++;
      if(Utility.IsZeroOrNaN(RevenuePerShare))missingItemCount++;
      if(Utility.IsZeroOrNaN(QtrlyRevenueGrowth))missingItemCount++;
      if(Utility.IsZeroOrNaN(GrossProfit))missingItemCount++;
      if(Utility.IsZeroOrNaN(EBITDA))missingItemCount++;
      if(Utility.IsZeroOrNaN(NetIncomeAvailableToCommon))missingItemCount++;
      if(Utility.IsZeroOrNaN(BookValuePerShare))missingItemCount++;
      if(Utility.IsZeroOrNaN(OperatingCashflow))missingItemCount++;
      if(Utility.IsZeroOrNaN(LeveragedFreeCashflow))missingItemCount++;
      if(Utility.IsZeroOrNaN(Equity))missingItemCount++;
      if(Utility.IsZeroOrNaN(TrailingPE))missingItemCount++;
      if(Utility.IsZeroOrNaN(EnterpriseValue))missingItemCount++;
      if(Utility.IsZeroOrNaN(EBIT))missingItemCount++;
      if(Utility.IsZeroOrNaN(DebtToEquity))missingItemCount++;
      percentMissing=(missingItemCount/totalItems)*100.00;
      MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Fundamental load for {0} is {1}%",symbol,100.00-percentMissing));
      if(percentMissing>85.00)return true;
      return false;
    }

    public double GetLoad()
    {
      double missingItemCount=0.00;
      double totalItems=29.00;
      double percentMissing=0.00;
      if(Utility.IsZeroOrNaN(Beta))missingItemCount++;
      if(Utility.IsZeroOrNaN(Low52))missingItemCount++;
      if(Utility.IsZeroOrNaN(High52))missingItemCount++;
      if(Utility.IsZeroOrNaN((double)Volume))missingItemCount++;
      if(Utility.IsZeroOrNaN(MarketCap))missingItemCount++;
      if(Utility.IsZeroOrNaN(PE))missingItemCount++;
      if(Utility.IsZeroOrNaN(EPS))missingItemCount++;
      if(Utility.IsZeroOrNaN(PEG))missingItemCount++;
      if(Utility.IsZeroOrNaN(ReturnOnAssets))missingItemCount++;
      if(Utility.IsZeroOrNaN(ReturnOnEquity))missingItemCount++;
      if(Utility.IsZeroOrNaN(TotalCash))missingItemCount++;
      if(Utility.IsZeroOrNaN(TotalDebt))missingItemCount++;
      if(Utility.IsZeroOrNaN(SharesOutstanding))missingItemCount++;
      if(Utility.IsZeroOrNaN(Revenue))missingItemCount++;
      if(Utility.IsZeroOrNaN(SharesOutstanding))missingItemCount++;
      if(Utility.IsZeroOrNaN(Revenue))missingItemCount++;
      if(Utility.IsZeroOrNaN(RevenuePerShare))missingItemCount++;
      if(Utility.IsZeroOrNaN(QtrlyRevenueGrowth))missingItemCount++;
      if(Utility.IsZeroOrNaN(GrossProfit))missingItemCount++;
      if(Utility.IsZeroOrNaN(EBITDA))missingItemCount++;
      if(Utility.IsZeroOrNaN(NetIncomeAvailableToCommon))missingItemCount++;
      if(Utility.IsZeroOrNaN(BookValuePerShare))missingItemCount++;
      if(Utility.IsZeroOrNaN(OperatingCashflow))missingItemCount++;
      if(Utility.IsZeroOrNaN(LeveragedFreeCashflow))missingItemCount++;
      if(Utility.IsZeroOrNaN(Equity))missingItemCount++;
      if(Utility.IsZeroOrNaN(TrailingPE))missingItemCount++;
      if(Utility.IsZeroOrNaN(EnterpriseValue))missingItemCount++;
      if(Utility.IsZeroOrNaN(EBIT))missingItemCount++;
      if(Utility.IsZeroOrNaN(DebtToEquity))missingItemCount++;
      percentMissing=(missingItemCount/totalItems)*100.00;
      return 100.00-percentMissing;
    }

    public static String Header
    {
      get
      {
        StringBuilder sb=new StringBuilder();
        sb.Append("Symbol").Append(",");
        sb.Append("AsOf").Append(",");
        sb.Append("Source,");
        sb.Append("NextEarningsDate").Append(",");
        sb.Append("Beta").Append(",");
        sb.Append("Low52").Append(",");
        sb.Append("High52").Append(",");
        sb.Append("Volume").Append(",");
        sb.Append("MarketCap").Append(",");
        sb.Append("PE").Append(",");
        sb.Append("EPS").Append(",");
        sb.Append("PEG").Append(",");
        sb.Append("Return On Assets").Append(",");
        sb.Append("Return On Equity").Append(",");
        sb.Append("Total Cash").Append(",");
        sb.Append("Total Debt").Append(",");
        sb.Append("Shares Outstanding").Append(",");
        sb.Append("Revenue").Append(",");
        sb.Append("RevenuePerShare").Append(",");
        sb.Append("QtrlyRevenueGrowth").Append(",");
        sb.Append("GrossProfit").Append(",");
        sb.Append("EBITDA").Append(",");
        sb.Append("NetIncomeAvailableToCommon").Append(",");
        sb.Append("BookValuePerShare").Append(",");
        sb.Append("OperatingCashflow").Append(",");
        sb.Append("LeveragedFreeCashflow").Append(",");
        sb.Append("Equity").Append(",");
        sb.Append("Trailing PE,");
        sb.Append("EBIT,");
        sb.Append("EnterpriseValue,");
        sb.Append("DebtToEquity");
        return sb.ToString();
      }
    }
    public override String ToString()
    {
      StringBuilder sb = new StringBuilder();
      sb.Append(Symbol).Append(",");
      sb.Append(Utility.DateTimeToStringMMSDDSYYYY(AsOf)).Append(",");
      sb.Append(null == Source ? "" : Source).Append(",");
      sb.Append(Utility.DateTimeToStringMMSDDSYYYY(NextEarningsDate)).Append(",");
      sb.Append(String.Format("{0:0.00}",Beta )).Append(",");
      sb.Append(String.Format("{0:0.00}",Low52)).Append(",");
      sb.Append(String.Format("{0:0.00}",High52)).Append(",");
      sb.Append(String.Format("{0:0.00}", Volume)).Append(",");
      sb.Append(String.Format("{0:0.00}", MarketCap)).Append(",");
      sb.Append(String.Format("{0:0.00}", PE)).Append(",");
      sb.Append(String.Format("{0:0.00}", EPS)).Append(",");
      sb.Append(String.Format("{0:0.00}", PEG)).Append(",");
      sb.Append(String.Format("{0:0.00}", ReturnOnAssets)).Append(",");
      sb.Append(String.Format("{0:0.00}", ReturnOnEquity)).Append(",");
      sb.Append(String.Format("{0:0.00}", TotalCash)).Append(",");
      sb.Append(String.Format("{0:0.00}", TotalDebt)).Append(",");
      sb.Append(String.Format("{0:0.00}", SharesOutstanding)).Append(",");
      sb.Append(String.Format("{0:0.00}", Revenue)).Append(",");
      sb.Append(String.Format("{0:0.00}", RevenuePerShare)).Append(",");
      sb.Append(String.Format("{0:0.00}", QtrlyRevenueGrowth)).Append(",");
      sb.Append(String.Format("{0:0.00}", GrossProfit)).Append(",");
      sb.Append(String.Format("{0:0.00}", EBITDA)).Append(",");
      sb.Append(String.Format("{0:0.00}", NetIncomeAvailableToCommon)).Append(",");
      sb.Append(String.Format("{0:0.00}", BookValuePerShare)).Append(",");
      sb.Append(String.Format("{0:0.00}", OperatingCashflow)).Append(",");
      sb.Append(String.Format("{0:0.00}", LeveragedFreeCashflow)).Append(",");
      sb.Append(String.Format("{0:0.00}", Equity)).Append(",");
      sb.Append(String.Format("{0:0.00}", TrailingPE)).Append(",");
      sb.Append(String.Format("{0:0.00}", EBIT)).Append(",");
      sb.Append(String.Format("{0}", EnterpriseValue)).Append(",");
      sb.Append(String.Format("{0:0.00}", DebtToEquity));
      return sb.ToString();
    }
  }
}
