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

namespace MarketData.Generator
{
  public class ValuationGenerator
  {
    public delegate bool OnItemCompleteHandler(Valuation valuation);
    public delegate void OnErrorItemHandler(String symbol,String message);
    private ValuationGenerator()
    {
    }
    public static Valuations GenerateValuations(List<String> symbols,OnItemCompleteHandler onItemCompleteHandler=null,OnErrorItemHandler onErrorItemHandler=null)
    {
      try
      {
        Valuations valuations = new Valuations();
        valuations.ValuationDate = DateTime.Now;
        Prices pricesIndex90 = PricingDA.GetPrices("SPY",90);
        Prices pricesIndex720 = PricingDA.GetPrices("SPY", 720);
        for (int index = 0; index < symbols.Count; index++)
        {
          Valuation valuation=GenerateValuation(symbols[index],pricesIndex90,pricesIndex720,onItemCompleteHandler,onErrorItemHandler);
          if (null == valuation) continue;
          valuations.Add(valuation);
          if (null != onItemCompleteHandler)
          {
            if (!onItemCompleteHandler(valuation)) break;
          }
        }
        TLBRankGenerator.ApplyTLBRanks(valuations);
        AcquirersMultipeGenerator.ApplyRanks(valuations);
        return valuations;
      }
      catch (Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,exception.ToString());
        return null;
      }
    }
    public static Valuations GenerateValuations(OnItemCompleteHandler onItemCompleteHandler=null,OnErrorItemHandler onErrorItemHandler=null)
    {
      try
      {
        List<String> symbols = PricingDA.GetSymbols();
        Valuations valuations = new Valuations();
        valuations.ValuationDate = DateTime.Now;
        Prices pricesIndex90 = PricingDA.GetPrices("SPY",90);
        Prices pricesIndex720 = PricingDA.GetPrices("SPY", 720);
        for (int index = 0; index < symbols.Count; index++)
        {
          Valuation valuation=GenerateValuation(symbols[index],pricesIndex90,pricesIndex720,onItemCompleteHandler,onErrorItemHandler);
          if (null == valuation) continue;
          valuations.Add(valuation);
          if (null != onItemCompleteHandler)
          {
            if (!onItemCompleteHandler(valuation)) break;
          }
        }
        TLBRankGenerator.ApplyTLBRanks(valuations);
        AcquirersMultipeGenerator.ApplyRanks(valuations);
        return valuations;
      }
      catch (Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,exception.ToString());
        return null;
      }
    }
    public static Valuation GenerateValuation(String symbol,Prices pricesIndex90,Prices pricesIndex720,OnItemCompleteHandler onItemCompleteHandler=null,OnErrorItemHandler onErrorItemHandler=null)
    {
      try
      {
        Valuation valuation = new Valuation();
        symbol = symbol.ToUpper();
        String companyName = PricingDA.GetNameForSymbol(symbol);
        Price price = PricingDA.GetPrice(symbol);
        CompanyProfile companyProfile=CompanyProfileDA.GetCompanyProfile(symbol);
        Prices pricesSymbol90=PricingDA.GetPrices(symbol,90);
        Prices pricesSymbol720=PricingDA.GetPrices(symbol,720);
        if (null == price)
        {
          if (null != onErrorItemHandler) onErrorItemHandler(symbol, "No Prices.");
          return null;
        }
        IncomeStatement incomeStatement=IncomeStatementDA.GetIncomeStatement(symbol,IncomeStatement.PeriodType.Annual);
        CashflowStatement cashflowStatement=CashflowStatementDA.GetCashflowStatement(symbol,CashflowStatement.PeriodType.Annual);
        BalanceSheet balanceSheet = BalanceSheetDA.GetBalanceSheet(symbol,BalanceSheet.PeriodType.Annual);
        TimeSeriesCollection bookValuePerShareCollection = HistoricalDA.GetTimeSeries(symbol, TimeSeriesElement.ElementType.BVPS);
        TimeSeriesCollection epsCollection = HistoricalDA.GetTimeSeries(symbol, TimeSeriesElement.ElementType.EPS);
        TimeSeriesCollection roicCollection = HistoricalDA.GetTimeSeries(symbol, TimeSeriesElement.ElementType.ROIC);
        TimeSeriesCollection revenueCollection = HistoricalDA.GetTimeSeries(symbol, TimeSeriesElement.ElementType.Revenue);
        TimeSeriesCollection freeCashflowCollection = HistoricalDA.GetTimeSeries(symbol, TimeSeriesElement.ElementType.FreeCashflow);
        TimeSeriesCollection operatingCashflowCollection = HistoricalDA.GetTimeSeries(symbol, TimeSeriesElement.ElementType.OperatingCashflow);
        TimeSeriesCollection workingCapitalCollection = HistoricalDA.GetTimeSeries(symbol, TimeSeriesElement.ElementType.WorkingCapital);
        if (null == bookValuePerShareCollection || 0 == bookValuePerShareCollection.Count)
        {
          bookValuePerShareCollection=new TimeSeriesCollection();
          TimeSeriesElement timeSeriesElement=new TimeSeriesElement();
          timeSeriesElement.AsOf=DateTime.Now;
          timeSeriesElement.Value=0;
          bookValuePerShareCollection.Add(new TimeSeriesElement());
        }
        Fundamental fundamental = FundamentalDA.GetFundamental(symbol);
        if (null == fundamental)
        {
          if (null != onErrorItemHandler) onErrorItemHandler(symbol, "No Fundamental Data.");
          return null;
        }
        AnalystPriceTarget analystPriceTarget = AnalystPriceTargetDA.GetAnalystPriceTarget(symbol);
// These series are ordered by date with the latest date appearing at the lowest ordinal index.
        float[] bookValuesPerShareSeries = bookValuePerShareCollection.ToFloat();
        float[] epsSeries = epsCollection.ToFloat();
        float[] roicSeries = roicCollection.ToFloat();
        float[] revenueSeries = revenueCollection.ToFloat();
        float[] freeCashflowSeries = freeCashflowCollection.ToFloat();
        float[] operatingCashflowSeries = operatingCashflowCollection.ToFloat();
        float[] workingCapitalSeries = workingCapitalCollection.ToFloat();
        double averageGrowth = Numerics.AverageReturn(ref bookValuesPerShareSeries);
        double averageGrowth2Year = Numerics.AverageReturnTop(ref bookValuesPerShareSeries, 2);
        double averageGrowth4Year = Numerics.AverageReturnTop(ref bookValuesPerShareSeries, 4);
        double epsGrowth = Numerics.AverageReturn(ref epsSeries);
        double epsGrowth2Year = Numerics.AverageReturnTop(ref epsSeries, 2);
        double epsGrowth4Year = Numerics.AverageReturnTop(ref epsSeries, 4);
        double roic = Numerics.Mean(ref roicSeries);
        double revenueGrowth = Numerics.AverageReturn(ref revenueSeries);
        double revenueGrowth2Year = Numerics.AverageReturnTop(ref revenueSeries, 2);
        double revenueGrowth4Year = Numerics.AverageReturnTop(ref revenueSeries, 4);
        double freeCashflowGrowth = Numerics.AverageReturn(ref freeCashflowSeries);
        double averageOperatingCashflow = Numerics.Mean(ref operatingCashflowSeries);
        double averageWorkingCapital = Numerics.Mean(ref workingCapitalSeries);
        double latestPrice = price.Close;
// Shares Oustanding
        valuation.SharesOutstanding=fundamental.SharesOutstanding;
// Dividend Yield
        valuation.DividendYield=DividendHistoryGenerator.GetDividendYield(symbol);
// Benjamin Graham Formula.  EPS=Trailing Twelve month, 8.5=PE base for no growth company, g=reasonably expected 7-10 year growth rate
        double intrinsicValue =GrahamGenerator.IntrinsicValue(fundamental.EPS,epsGrowth); 
        valuation.FundamentalValue=GrahamGenerator.GrahamNumber(fundamental.EPS,fundamental.BookValuePerShare);
        if(0!=fundamental.SharesOutstanding&&!double.IsNaN(fundamental.SharesOutstanding)&&null!=balanceSheet&&!double.IsNaN(balanceSheet.NetCurrentAssetValue))valuation.NetCurrentAssetValuePerShare=balanceSheet.NetCurrentAssetValue/fundamental.SharesOutstanding;
        else valuation.NetCurrentAssetValuePerShare=double.NaN;
        valuation.DebtToEquity=fundamental.DebtToEquity;
// **************************************************************************************************************************************************
        valuation.MarketCap=fundamental.MarketCap;
        valuation.EnterpriseValue=fundamental.EnterpriseValue;
        valuation.EBIT=fundamental.EBIT;
// ******************************************************* T H E   L I T T L E   B O O K  *******************************************************
// Calculate the earnings yield to be used by TLB rankings (TLB=The Little Book) 
// earnings_yield=EBIT/EnterpriseValue
        if(!double.IsNaN(fundamental.EBIT)&&null!=balanceSheet&&!double.IsNaN(balanceSheet.NetFixedAssets))
        {
          valuation.LatestROC=fundamental.EBIT/balanceSheet.NetFixedAssets;
        }
        else valuation.LatestROC=double.NaN;
        if(!double.IsNaN(fundamental.EBIT)&&!double.IsNaN(fundamental.EnterpriseValue)&&fundamental.EnterpriseValue>0.00&&fundamental.EBIT>0.00)
        {
          valuation.EarningsYield=fundamental.EBIT/fundamental.EnterpriseValue;
        }
        else valuation.EarningsYield=double.NaN;
// ******************************************************** T H E  A C Q U I R E R S  M U L T I P L E  ********************************************
        if(null!=fundamental&&!double.IsNaN(fundamental.EnterpriseValue)&&null!=cashflowStatement&&!double.IsNaN(cashflowStatement.DepreciationAndAmortization)&&null!=incomeStatement&&!double.IsNaN(incomeStatement.TotalRevenue)&&!double.IsNaN(incomeStatement.CostOfRevenue)&&!double.IsNaN(incomeStatement.SGA))
        {
          valuation.OperatingEarnings=incomeStatement.TotalRevenue-(cashflowStatement.DepreciationAndAmortization+incomeStatement.CostOfRevenue+incomeStatement.SGA);
          valuation.AcquirersMultiple=fundamental.EnterpriseValue/valuation.OperatingEarnings;     
        }
        else
        {
          valuation.OperatingEarnings=double.NaN;
          valuation.AcquirersMultiple=double.NaN;
        }
// ******************************************************************** S E C  F O R M  1 3 D *********************************************************************************************
        SEC13Info sec13Info=SECFilingDA.GetSEC13Info(symbol);
        if(sec13Info.SEC13)
        {
          valuation.SEC13=true;
          valuation.SEC13FilingDate=sec13Info.MostRecentFilingDate;
        }
// *****************************************************************************************************************************************************************************************
        valuation.Company=companyName.Replace(",", "");
        valuation.Symbol=symbol;
        valuation.NextEarningsDate=fundamental.NextEarningsDate;
        valuation.Beta90 = BetaGenerator.Beta(symbol, PricingDA.GetLatestDate(symbol),3);
        valuation.Beta720 = BetaGenerator.Beta(symbol, PricingDA.GetLatestDate(symbol),24);
        if (null != roicSeries && roicSeries.Length > 0)
        {
          valuation.ROICDates = Utility.FormatDates(roicCollection[roicCollection.Count - 1].AsOf, roicCollection[0].AsOf);
          TimeSeriesElement[] roicTimeSeriesElement=(from roicItem in roicCollection select roicItem).OrderBy(roicItem => roicItem.AsOf).ToArray();
          double[] orderedROICValues=(from element in roicTimeSeriesElement select element.Value).ToArray();
          valuation.ROICSlope = Numerics.Slope(orderedROICValues);
          valuation.LatestROIC=roicCollection[0].Value;
        }
        if (null != revenueSeries && revenueSeries.Length > 0 && null != balanceSheet && !double.IsNaN(balanceSheet.LongTermDebt))
        {
          double latestRevenue = revenueSeries[0];
          valuation.LongTermDebt=balanceSheet.LongTermDebt;
          valuation.Revenue=latestRevenue;
          if (latestRevenue * 3 > balanceSheet.LongTermDebt) valuation.DebtLoad="Pass";
          else valuation.DebtLoad="Fail";
        }
        else
        {
          valuation.LongTermDebt=double.NaN;
          valuation.Revenue=double.NaN;
          valuation.DebtLoad="N/A";
        }
        valuation.AverageROIC=roic / 100.00;
        if (null != bookValuePerShareCollection && 0 != bookValuePerShareCollection.Count)
        {
          valuation.BVPS = bookValuePerShareCollection[0].Value;
          valuation.BVPSDates = Utility.FormatDates(bookValuePerShareCollection[bookValuePerShareCollection.Count - 1].AsOf, bookValuePerShareCollection[0].AsOf);
        }
        else valuation.BVPSDates = "N/A";
        valuation.AverageEquityGrowth=averageGrowth;
        valuation.AverageEquityGrowth2Y=averageGrowth2Year;
        valuation.AverageEquityGrowth4Y=averageGrowth4Year;
        if (null != epsCollection && epsCollection.Count > 0) valuation.EPSDates = Utility.FormatDates(epsCollection[epsCollection.Count - 1].AsOf, epsCollection[0].AsOf);
        else valuation.EPSDates="N/A";
        valuation.AverageEPSGrowth=epsGrowth;
        valuation.AverageEPSGrowth2Y=epsGrowth2Year;
        valuation.AverageEPSGrowth4Y=epsGrowth4Year;
        if (null != revenueCollection && revenueCollection.Count > 0) valuation.RevenueDates = Utility.FormatDates(revenueCollection[revenueCollection.Count - 1].AsOf, revenueCollection[0].AsOf);
        else valuation.RevenueDates="N/A";
        valuation.AverageRevenueGrowth=revenueGrowth;
        valuation.AverageRevenueGrowth2Y=revenueGrowth2Year;
        valuation.AverageRevenueGrowth4Y=revenueGrowth4Year;
        valuation.AverageFreeCashflowGrowth=freeCashflowGrowth;
        valuation.AverageOperatingCashflow=averageOperatingCashflow;
        valuation.OperatingCashflow=null!=operatingCashflowSeries&&operatingCashflowSeries.Length>0?operatingCashflowSeries[0]:double.NaN;
        valuation.AverageWorkingCapital=averageWorkingCapital;
        if(null!=companyProfile)
        {
          valuation.Industry=companyProfile.Industry;
          valuation.Sector=companyProfile.Sector;
        }
        valuation.EPS=fundamental.EPS;
        valuation.PE=latestPrice / fundamental.EPS;
        valuation.PEG = fundamental.PEG;
        if(!double.IsNaN(valuation.BVPS)&&!double.IsNaN(latestPrice))valuation.PBVPS=latestPrice/valuation.BVPS;
        if (!double.IsNaN(valuation.PE) && !double.IsNaN(valuation.PEG)) valuation.ImpliedEarningsGrowth = (valuation.PE / valuation.PEG) / 100.00;
        StickerPrice stickerPrice = new StickerPrice(symbol);
        valuation.BVPSItems = stickerPrice.BVPSItems;
        valuation.AverageBVPSGrowth = stickerPrice.AverageBVPSGrowth;
        valuation.LowPE=stickerPrice.LowPE;
        valuation.TrailingPE=stickerPrice.TrailingPE;
        valuation.AverageLowTrailing=stickerPrice.AverageLowTrailing;
        valuation.CurrentStockEstimatePrice=stickerPrice.CurrentStockEstimatePrice;
        valuation.PriceEstimate10Y=stickerPrice.PriceEstimate10y;
        valuation.TodaysPriceForRequiredReturn=stickerPrice.TodaysPriceForRequiredReturn;
        valuation.MOS=stickerPrice.MarginOfSafety;
        valuation.MOS80=stickerPrice.MarginOfSafety80Pcnt;
        valuation.IntrinsicValue=intrinsicValue;
        valuation.RGV=intrinsicValue/latestPrice;
        valuation.LatestPrice=latestPrice;
        if (null != analystPriceTarget)
        {
          valuation.MeanTargetPrice=analystPriceTarget.MeanTargetPrice;
          valuation.LowTargetPrice=analystPriceTarget.LowTargetPrice;
          valuation.HighTargetPrice=analystPriceTarget.HighTargetPrice;
        }
        else
        {
          valuation.MeanTargetPrice=double.NaN;
          valuation.LowTargetPrice=double.NaN;
          valuation.HighTargetPrice=double.NaN;
        }
        valuation.UpsidePcnt = double.IsNaN(valuation.HighTargetPrice)||0>=valuation.HighTargetPrice ? double.NaN : (valuation.HighTargetPrice - valuation.LatestPrice) / valuation.LatestPrice;
        valuation.DownsidePcnt=double.IsNaN(valuation.LowTargetPrice)||0>=valuation.LowTargetPrice?double.NaN:(valuation.LowTargetPrice-valuation.LatestPrice)/valuation.LatestPrice;
        valuation.Bargain=latestPrice < stickerPrice.MarginOfSafety ? true : false;
        valuation.Bargain80=latestPrice < stickerPrice.MarginOfSafety80Pcnt ? true : false;
        return valuation;
      }
      catch (Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,"Error calculating sticker for '" + symbol + "', exception was " + exception.ToString());
        return null;
      }
    }
    public static Valuation GenerateValuationWithOverride(String symbol,Prices pricesIndex90,Prices pricesIndex720,double bvpsGrowthOverride,OnItemCompleteHandler onItemCompleteHandler=null,OnErrorItemHandler onErrorItemHandler=null)
    {
      try
      {
        Valuation valuation = new Valuation();
        symbol = symbol.ToUpper();
        String companyName = PricingDA.GetNameForSymbol(symbol);
        Price price = PricingDA.GetPrice(symbol);
        CompanyProfile companyProfile=CompanyProfileDA.GetCompanyProfile(symbol);
        Prices pricesSymbol90=PricingDA.GetPrices(symbol,90);
        Prices pricesSymbol720=PricingDA.GetPrices(symbol,720);
        if (null == price)
        {
          if (null != onErrorItemHandler) onErrorItemHandler(symbol, "No Prices.");
          return null;
        }
        BalanceSheet balanceSheet = BalanceSheetDA.GetBalanceSheet(symbol,BalanceSheet.PeriodType.Annual);
        IncomeStatement incomeStatement=IncomeStatementDA.GetIncomeStatement(symbol,IncomeStatement.PeriodType.Annual);
        CashflowStatement cashflowStatement=CashflowStatementDA.GetCashflowStatement(symbol,CashflowStatement.PeriodType.Annual);
// These series are ordered by date with the latest date appearing at the lowest ordinal index
        TimeSeriesCollection bookValuePerShareCollection = HistoricalDA.GetTimeSeries(symbol, TimeSeriesElement.ElementType.BVPS);
        TimeSeriesCollection epsCollection = HistoricalDA.GetTimeSeries(symbol, TimeSeriesElement.ElementType.EPS);
        TimeSeriesCollection roicCollection = HistoricalDA.GetTimeSeries(symbol, TimeSeriesElement.ElementType.ROIC);
        TimeSeriesCollection revenueCollection = HistoricalDA.GetTimeSeries(symbol, TimeSeriesElement.ElementType.Revenue);
        TimeSeriesCollection freeCashflowCollection = HistoricalDA.GetTimeSeries(symbol, TimeSeriesElement.ElementType.FreeCashflow);
        TimeSeriesCollection operatingCashflowCollection = HistoricalDA.GetTimeSeries(symbol, TimeSeriesElement.ElementType.OperatingCashflow);
        TimeSeriesCollection workingCapitalCollection = HistoricalDA.GetTimeSeries(symbol, TimeSeriesElement.ElementType.WorkingCapital);
        if (null == bookValuePerShareCollection || 0 == bookValuePerShareCollection.Count)
        {
          bookValuePerShareCollection=new TimeSeriesCollection();
          TimeSeriesElement timeSeriesElement=new TimeSeriesElement();
          timeSeriesElement.AsOf=DateTime.Now;
          timeSeriesElement.Value=0;
          bookValuePerShareCollection.Add(new TimeSeriesElement());
        }
        Fundamental fundamental = FundamentalDA.GetFundamental(symbol);
        if (null == fundamental)
        {
          if (null != onErrorItemHandler) onErrorItemHandler(symbol, "No Fundamental Data.");
          return null;
        }
        AnalystPriceTarget analystPriceTarget = AnalystPriceTargetDA.GetAnalystPriceTarget(symbol);
        float[] bookValuesPerShareSeries = bookValuePerShareCollection.ToFloat();
        float[] epsSeries = epsCollection.ToFloat();
        float[] roicSeries = roicCollection.ToFloat();
        float[] revenueSeries = revenueCollection.ToFloat();
        float[] freeCashflowSeries = freeCashflowCollection.ToFloat();
        float[] operatingCashflowSeries = operatingCashflowCollection.ToFloat();
        float[] workingCapitalSeries = workingCapitalCollection.ToFloat();
        double averageGrowth = bvpsGrowthOverride;
        double averageGrowth2Year = bvpsGrowthOverride;
        double averageGrowth4Year = bvpsGrowthOverride;
        double epsGrowth = Numerics.AverageReturn(ref epsSeries);
        double epsGrowth2Year = Numerics.AverageReturnTop(ref epsSeries, 2);
        double epsGrowth4Year = Numerics.AverageReturnTop(ref epsSeries, 4);
        double roic = Numerics.Mean(ref roicSeries);
        double revenueGrowth = Numerics.AverageReturn(ref revenueSeries);
        double revenueGrowth2Year = Numerics.AverageReturnTop(ref revenueSeries, 2);
        double revenueGrowth4Year = Numerics.AverageReturnTop(ref revenueSeries, 4);
        double freeCashflowGrowth = Numerics.AverageReturn(ref freeCashflowSeries);
        double averageOperatingCashflow = Numerics.Mean(ref operatingCashflowSeries);
        double averageWorkingCapital = Numerics.Mean(ref workingCapitalSeries);
        double latestPrice = price.Close;
// Shares Oustanding
        valuation.SharesOutstanding=fundamental.SharesOutstanding;
// Dividend Yield
        valuation.DividendYield=DividendHistoryGenerator.GetDividendYield(symbol);
// Benjamin Graham Formula.  EPS=Trailing Twelve month, 8.5=PE base for no growth company, g=reasonably expected 7-10 year growth rate
        double intrinsicValue = GrahamGenerator.IntrinsicValue(fundamental.EPS,epsGrowth);  
        valuation.FundamentalValue=GrahamGenerator.GrahamNumber(fundamental.EPS,fundamental.BookValuePerShare);
        if(0!=fundamental.SharesOutstanding&&!double.IsNaN(fundamental.SharesOutstanding)&&null!=balanceSheet&&!double.IsNaN(balanceSheet.NetCurrentAssetValue))valuation.NetCurrentAssetValuePerShare=balanceSheet.NetCurrentAssetValue/fundamental.SharesOutstanding;
        else valuation.NetCurrentAssetValuePerShare=double.NaN;
        valuation.DebtToEquity=fundamental.DebtToEquity;
// **************************************************************************************************************************************************
        valuation.MarketCap=fundamental.MarketCap;
        valuation.EnterpriseValue=fundamental.EnterpriseValue;
        valuation.EBIT=fundamental.EBIT;
// ******************************************************* T H E   L I T T L E   B O O K  *******************************************************
// Calculate the earnings yield to be used by TLB rankings (TLB=The Little Book) 
// earnings_yield=EBIT/EnterpriseValue
        if(!double.IsNaN(fundamental.EBIT)&&!double.IsNaN(fundamental.EnterpriseValue)&&fundamental.EnterpriseValue>0.00&&fundamental.EBIT>0.00)
        {
          valuation.EarningsYield=fundamental.EBIT/fundamental.EnterpriseValue;
        }
        else valuation.EarningsYield=double.NaN;
// ******************************************************** T H E  A C Q U I R E R S  M U L T I P L E  ********************************************
        if(null!=fundamental&&!double.IsNaN(fundamental.EnterpriseValue)&&null!=cashflowStatement&&!double.IsNaN(cashflowStatement.DepreciationAndAmortization)&&null!=incomeStatement&&!double.IsNaN(incomeStatement.TotalRevenue)&&!double.IsNaN(incomeStatement.CostOfRevenue)&&!double.IsNaN(incomeStatement.SGA))
        {
          valuation.OperatingEarnings=incomeStatement.TotalRevenue-(cashflowStatement.DepreciationAndAmortization+incomeStatement.CostOfRevenue+incomeStatement.SGA);
          valuation.AcquirersMultiple=fundamental.EnterpriseValue/valuation.OperatingEarnings;     
        }
        else
        {
          valuation.OperatingEarnings=double.NaN;
          valuation.AcquirersMultiple=double.NaN;
        }
// ******************************************************************** S E C  F O R M  1 3 D *********************************************************************************************
        SEC13Info sec13Info=SECFilingDA.GetSEC13Info(symbol);
        if(sec13Info.SEC13)
        {
          valuation.SEC13=true;
          valuation.SEC13FilingDate=sec13Info.MostRecentFilingDate;
        }
// *****************************************************************************************************************************************************************************************

        if(null!=companyProfile)
        {
          valuation.Industry=companyProfile.Industry;
          valuation.Sector=companyProfile.Sector;
        }
        valuation.Company=companyName.Replace(",", "");
        valuation.Symbol=symbol;
        valuation.NextEarningsDate=fundamental.NextEarningsDate;
        valuation.Beta90 = BetaGenerator.Beta(symbol, PricingDA.GetLatestDate(symbol), 3);
        valuation.Beta720 = BetaGenerator.Beta(symbol, PricingDA.GetLatestDate(symbol), 24);
        if (null != roicSeries && roicSeries.Length > 0)
        {
          valuation.ROICDates = Utility.FormatDates(roicCollection[roicCollection.Count - 1].AsOf, roicCollection[0].AsOf);
          TimeSeriesElement[] roicTimeSeriesElement=(from roicItem in roicCollection select roicItem).OrderBy(roicItem => roicItem.AsOf).ToArray();
          double[] orderedROICValues=(from element in roicTimeSeriesElement select element.Value).ToArray();
          valuation.ROICSlope = Numerics.Slope(orderedROICValues);
          valuation.LatestROIC=roicCollection[0].Value;
        }
        if (null != revenueSeries && revenueSeries.Length > 0 && null != balanceSheet && !double.IsNaN(balanceSheet.LongTermDebt))
        {
          double latestRevenue = revenueSeries[0];
          valuation.LongTermDebt=balanceSheet.LongTermDebt;
          valuation.Revenue=latestRevenue;
          if (latestRevenue * 3 > balanceSheet.LongTermDebt) valuation.DebtLoad="Pass";
          else valuation.DebtLoad="Fail";
        }
        else
        {
          valuation.LongTermDebt=double.NaN;
          valuation.Revenue=double.NaN;
          valuation.DebtLoad="N/A";
        }
        valuation.AverageROIC=roic / 100.00;
        if (null != bookValuePerShareCollection && 0 != bookValuePerShareCollection.Count)
        {
          valuation.BVPS = bookValuePerShareCollection[0].Value;
          valuation.BVPSDates = Utility.FormatDates(bookValuePerShareCollection[bookValuePerShareCollection.Count - 1].AsOf, bookValuePerShareCollection[0].AsOf);
        }
        else valuation.BVPSDates = "N/A";
        valuation.AverageEquityGrowth=averageGrowth;
        valuation.AverageEquityGrowth2Y=averageGrowth2Year;
        valuation.AverageEquityGrowth4Y=averageGrowth4Year;
        if (null != epsCollection && epsCollection.Count > 0) valuation.EPSDates = Utility.FormatDates(epsCollection[epsCollection.Count - 1].AsOf, epsCollection[0].AsOf);
        else valuation.EPSDates="N/A";
        valuation.AverageEPSGrowth=epsGrowth;
        valuation.AverageEPSGrowth2Y=epsGrowth2Year;
        valuation.AverageEPSGrowth4Y=epsGrowth4Year;
        if (null != revenueCollection && revenueCollection.Count > 0) valuation.RevenueDates = Utility.FormatDates(revenueCollection[revenueCollection.Count - 1].AsOf, revenueCollection[0].AsOf);
        else valuation.RevenueDates="N/A";
        valuation.AverageRevenueGrowth=revenueGrowth;
//        if (null != fundamental) valuation.AverageRevenueGrowthQtr=fundamental.QtrlyRevenueGrowth / 100.00;
//        else valuation.AverageRevenueGrowthQtr=double.NaN;
        valuation.AverageRevenueGrowth2Y=revenueGrowth2Year;
        valuation.AverageRevenueGrowth4Y=revenueGrowth4Year;
        valuation.AverageFreeCashflowGrowth=freeCashflowGrowth;
        valuation.AverageOperatingCashflow=averageOperatingCashflow;
        valuation.OperatingCashflow=null!=operatingCashflowSeries&&operatingCashflowSeries.Length>0?operatingCashflowSeries[0]:double.NaN;
        valuation.AverageWorkingCapital=averageWorkingCapital;
        valuation.EPS=fundamental.EPS;
        valuation.PE=latestPrice / fundamental.EPS;
        valuation.PEG = fundamental.PEG;
        if(!double.IsNaN(valuation.BVPS)&&!double.IsNaN(latestPrice))valuation.PBVPS=latestPrice/valuation.BVPS;
        if (!double.IsNaN(valuation.PE) && !double.IsNaN(valuation.PEG)) valuation.ImpliedEarningsGrowth = (valuation.PE / valuation.PEG) / 100.00;
        StickerPrice stickerPrice = new StickerPrice(symbol,bvpsGrowthOverride);
        valuation.BVPSItems = stickerPrice.BVPSItems;
        valuation.AverageBVPSGrowth = stickerPrice.AverageBVPSGrowth;
        valuation.LowPE=stickerPrice.LowPE;
        valuation.TrailingPE=stickerPrice.TrailingPE;
        valuation.AverageLowTrailing=stickerPrice.AverageLowTrailing;
        valuation.CurrentStockEstimatePrice=stickerPrice.CurrentStockEstimatePrice;
        valuation.PriceEstimate10Y=stickerPrice.PriceEstimate10y;
        valuation.TodaysPriceForRequiredReturn=stickerPrice.TodaysPriceForRequiredReturn;
        valuation.MOS=stickerPrice.MarginOfSafety;
        valuation.MOS80=stickerPrice.MarginOfSafety80Pcnt;
        valuation.IntrinsicValue=intrinsicValue;
        valuation.RGV=intrinsicValue/latestPrice;
        valuation.LatestPrice=latestPrice;
        if (null != analystPriceTarget)
        {
          valuation.MeanTargetPrice=analystPriceTarget.MeanTargetPrice;
          valuation.LowTargetPrice=analystPriceTarget.LowTargetPrice;
          valuation.HighTargetPrice=analystPriceTarget.HighTargetPrice;
        }
        else
        {
          valuation.MeanTargetPrice=double.NaN;
          valuation.LowTargetPrice=double.NaN;
          valuation.HighTargetPrice=double.NaN;
        }
        valuation.UpsidePcnt = double.IsNaN(valuation.HighTargetPrice)||0>=valuation.HighTargetPrice ? double.NaN : (valuation.HighTargetPrice - valuation.LatestPrice) / valuation.LatestPrice;
        valuation.DownsidePcnt=double.IsNaN(valuation.LowTargetPrice)||0>=valuation.LowTargetPrice?double.NaN:(valuation.LowTargetPrice-valuation.LatestPrice)/valuation.LatestPrice;
        valuation.Bargain=latestPrice < stickerPrice.MarginOfSafety ? true : false;
        valuation.Bargain80=latestPrice < stickerPrice.MarginOfSafety80Pcnt ? true : false;
        return valuation;
      }
      catch (Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,"Error calculating sticker for '" + symbol + "', exception was " + exception.ToString());
        return null;
      }
    }
    public static String ToString(Valuation valuation)
    {
      StringBuilder sb = new StringBuilder();
      sb.Append(valuation.Company).Append(",");
      sb.Append(valuation.Symbol).Append(",");
      sb.Append(Utility.DateTimeToStringMMHDDHYYYY(valuation.NextEarningsDate)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.LongTermDebt)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.Revenue)).Append(",");
      sb.Append(valuation.DebtLoad).Append(",");
      sb.Append(Utility.FormatNumber(valuation.AverageROIC)).Append(",");
      sb.Append(valuation.BVPSDates).Append(",");
      sb.Append(Utility.FormatNumber(valuation.AverageEquityGrowth)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.AverageEquityGrowth2Y)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.AverageEquityGrowth4Y)).Append(",");
      sb.Append(valuation.EPSDates).Append(",");
      sb.Append(Utility.FormatNumber(valuation.AverageEPSGrowth)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.AverageEPSGrowth2Y)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.AverageEPSGrowth4Y)).Append(",");
      sb.Append(valuation.RevenueDates).Append(",");
      sb.Append(Utility.FormatNumber(valuation.AverageRevenueGrowth)).Append(",");
//      sb.Append(valuation.AverageRevenueGrowthQtr).Append(",");
      sb.Append(Utility.FormatNumber(valuation.AverageRevenueGrowth2Y)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.AverageRevenueGrowth4Y)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.AverageFreeCashflowGrowth)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.AverageOperatingCashflow)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.AverageWorkingCapital)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.BVPS)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.EPS)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.PE)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.PEG)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.ImpliedEarningsGrowth)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.LowPE)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.TrailingPE)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.AverageLowTrailing)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.CurrentStockEstimatePrice)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.PriceEstimate10Y)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.TodaysPriceForRequiredReturn)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.MOS)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.MOS80)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.IntrinsicValue)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.RGV)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.LatestPrice)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.UpsidePcnt)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.DownsidePcnt)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.MeanTargetPrice)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.LowTargetPrice)).Append(",");
      sb.Append(Utility.FormatNumber(valuation.HighTargetPrice)).Append(",");
      sb.Append(valuation.Bargain ? true : false).Append(",");
      sb.Append(valuation.Bargain80 ? true : false).Append(",");
      sb.Append(Utility.FormatNumber(valuation.DividendYield));
      return sb.ToString();
    }
    public static String Heading()
    {
      StringBuilder sb = new StringBuilder();
      sb.Append("Company,Symbol,NextEarningDate,LongTermDebt,Revenue,DebtLoad,ROIC(Avg%),BVPSDates,AvgEquityGrowth(AvgBVPS%),AvgEquityGrowth_2Y(AvgBVPS%),AvgEquityGrowth_4Y(AvgBVPS%),EPSDates,EPSGrowth(Avg%),EPSGrowth_2Y(Avg%),EPSGrowth_4Y(Avg%),RevenueDates,RevenueGrowth(Avg%),RevenueGrowth_QTR(Avg%),RevenueGrowth_2Y(Avg%),RevenueGrowth_4Y(Avg%),FreeCashflowGrowth(Avg%),OperatingCashflow(Avg),WorkingCapital(Avg),BVPS,EPS,PE,PEG,ImpliedEarningsGrowth,LowPE,TrailingPE,AverageLowTrailing,CurrentStockEstimatePrice,PriceEstimate10y,TodaysPriceForRequiredReturn,MOS,MOS(80%),IntrinsicValue,RGV(sb>1),LatestPrice,UpsidePcnt,DownsidePcnt,MeanTargetPrice,LowTargetPrice,HighPrice,Bargain(MOS),Bargain(MOS80%),DividendYield");
      return sb.ToString();
    }
  }
}
