/// <summary>
        /// Calculate a metric given a financial statement.
        /// </summary>
        /// <param name="statement"></param>
        /// <returns></returns>
        public FinancialMetric CalculateMetric(FinancialStatement statement)
        {
            FinancialMetric metric = new FinancialMetric
            {
                Source = statement.Source,
                Ticker = statement.Ticker,
                StartDate = statement.StartDate,
                EndDate = statement.EndDate
            };

            bool quarterly = statement.IsQuarterly;
            double divisor = statement.IsQuarterly ? (statement.NumQuarters) : 4;

            // caclulate quarterly nets and normalize for calcs
            metric.NetIncome = quarterly ? statement.IncomeStatement.NetIncome * 4 : statement.IncomeStatement.NetIncome;
            metric.CashFromOperations = (statement.CashFlow.CashFromOperatingActivities / divisor) * 4;
            metric.CapitalExpenditures = (statement.CashFlow.CapitalExpenditures / divisor) * 4;
            metric.Revenue = quarterly ? statement.IncomeStatement.TotalRevenue * 4 : statement.IncomeStatement.TotalRevenue;

            metric.FreeCashFlow = FinanceUtility.FreeCashFlow(metric.CashFromOperations, metric.CapitalExpenditures).Normalize();
            metric.CurrentReturnOnInvestmentCapital = FinanceUtility.CurrentReturnOnInvestmentCapital(metric.FreeCashFlow, statement.BalanceSheet.TotalEquity, statement.BalanceSheet.TotalLiabilities, statement.BalanceSheet.TotalCurrentLiabilities).Normalize();

            metric.ReceivablesPercentOfSales = FinanceUtility.ReceivablesPercentOfSales(metric.Revenue, statement.BalanceSheet.TotalReceivables).Normalize();
            metric.CurrentRatio = FinanceUtility.CurrentRatio(statement.BalanceSheet.TotalCurrentAssets, statement.BalanceSheet.TotalCurrentLiabilities).Normalize();

            metric.PlantPropertyValue = FinanceUtility.PlantPropertyValue(statement.BalanceSheet.PropertyPlantEquipment, statement.BalanceSheet.Depreciation).Normalize();
            metric.GoodwillPercentAssets = FinanceUtility.GoodwillPercentAssets(statement.BalanceSheet.Goodwill, statement.BalanceSheet.TotalAssets).Normalize();
            metric.IntangiblesPercentAssets = FinanceUtility.IntangiblePercentAssets(statement.BalanceSheet.Intangibles, statement.BalanceSheet.TotalAssets).Normalize();

            metric.ReturnOnAssets = FinanceUtility.ReturnOnAssets(metric.NetIncome, statement.BalanceSheet.TotalAssets).Normalize();

            metric.LiabilityToEquity = (statement.BalanceSheet.TotalLiabilities / statement.BalanceSheet.TotalEquity).Normalize();
            metric.DebtToEquity = (statement.BalanceSheet.TotalDebt / statement.BalanceSheet.TotalEquity).Normalize();

            metric.ReturnOnEquity = (statement.IncomeStatement.NetIncome / statement.BalanceSheet.TotalEquity).Normalize();

            metric.TangibleBookValue = statement.BalanceSheet.TotalEquity - statement.BalanceSheet.Goodwill - statement.BalanceSheet.Intangibles;

            metric.FreeCashFlowPerShare = (metric.FreeCashFlow / statement.BalanceSheet.CommonSharesOutstanding).Normalize();

            metric.ResearchAndDevelopmentPercentOfRevenue = (statement.IncomeStatement.ResearchAndDevelopmentExpense / statement.IncomeStatement.TotalRevenue).Normalize();
            metric.SalesPercentRevenue = (statement.IncomeStatement.SalesAndMarketingExpenses / statement.IncomeStatement.TotalRevenue).Normalize();

            metric.Ncav = (statement.BalanceSheet.TotalCurrentAssets - statement.BalanceSheet.TotalLiabilities).Normalize();

            // company value if we liquidated everything today
            metric.LiquidationValue = statement.BalanceSheet.TotalAssets - 0.2 * statement.BalanceSheet.PropertyPlantEquipment - 0.5 * statement.BalanceSheet.TotalInventory
                - 0.5 * statement.BalanceSheet.AccountsReceivable - statement.BalanceSheet.Intangibles - statement.BalanceSheet.TotalLiabilities;

            metric.EarningsPerShareDiluted = statement.IncomeStatement.EarningsPerShareDiluted;
            metric.CashAndShortTerm = statement.BalanceSheet.CashAndShortTerm;
            metric.CommonSharesOutstanding = statement.BalanceSheet.CommonSharesOutstanding;
            metric.TotalDebt = statement.BalanceSheet.TotalDebt;

            return metric;
        }
        private void AddToStatement(FactContext context, string elementName, string value)
        {
            double result = 0;
            if (!double.TryParse(value, out result))
                return; // NaN

            if (null == context)
                return; // no time period

            // look up financial statement, if there is one
            FinancialStatement statement;
            if (_statementCache.ContainsKey(context.HashKey))
                statement = _statementCache[context.HashKey];
            else
                statement = new FinancialStatement {
                    StartDate = context.StartDate,
                    EndDate = context.EndDate,
                    Ticker = this._filing.Ticker,
                    Source = StatementBase.SourceEdgar
                };

            // try to set the value on the statement
               if (SetStatementValue(statement, elementName, result))
               _statementCache[context.HashKey] = statement;
        }
        private static bool SetStatementValue(FinancialStatement statement, string elementName, double value)
        {
            try
            {
                // set the property value if it exists in the cache
                if (BalanceSheetElements.ContainsKey(elementName))
                {
                    BalanceSheetElements[elementName].SetValue(statement.BalanceSheet, value);
                    return true;
                }
                else if (CashFlowElements.ContainsKey(elementName))
                {
                    CashFlowElements[elementName].SetValue(statement.CashFlow, value);
                    return true;
                }
                else if (IncomeStatementElements.ContainsKey(elementName))
                {
                    IncomeStatementElements[elementName].SetValue(statement.IncomeStatement, value);
                    return true;
                }
            }
            catch (Exception ex)
            {
                log.Error("Unable to set edgar value from attribute.", ex);
                return false;
            }

            return false;
        }