using System;
using System.Text;
using MySql.Data.MySqlClient;
using MarketData.MarketDataModel;
using MarketData.Utils;

namespace MarketData.DataAccess
{
  public class CompositeDA
  {
    private CompositeDA()
    {
    }
    public static FeedStatistics GetFeedStatistics(FeedStatistic.FeedStatisticType feedStatisticType)
    {
      MySqlConnection sqlConnection = null;
      MySqlDataReader sqlDataReader = null;
      MySqlCommand sqlCommand = null;
      FeedStatistics feedStatistics = new FeedStatistics();
      String strQuery;

      try
      {
        StringBuilder sb = new StringBuilder();
        sqlConnection = SqlUtils.CreateMySqlConnection(MainDataSource.Instance.LocateDataSource("market_data"));
        switch (feedStatisticType)
        {
          case FeedStatistic.FeedStatisticType.ZACKS_RANK:
            sb.Append("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;select 'Zacks Rank' description,count(*) records,date from zacksrank group by 3 order by date desc");
            break;
          case FeedStatistic.FeedStatisticType.VALUATIONS:
            sb.Append("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;select 'Valuations' description, count(*), valuation_date from valuations group by 3 order by valuation_date desc");
            break;
          case FeedStatistic.FeedStatisticType.YIELD_CURVE:
            sb.Append("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;select 'Yield Curve' description,count(*), date from yieldcurve group by 3 order by date desc");
            break;
          case FeedStatistic.FeedStatisticType.SPLITS:
            sb.Append("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;select 'Splits' description,count(*), modified from splits group by 3 order by modified desc");
            break;
          case FeedStatistic.FeedStatisticType.SECURITY_MASTER:
//            sb.Append("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;select 'Security Master' description,count(*), date(create_date) from securitymaster group by 3 order by create_date desc");
            sb.Append("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;select 'Security Master' description,count(*), date(create_date) from securitymaster group by 3 order by 3 desc");
            break;
          case FeedStatistic.FeedStatisticType.SEC_FILINGS:
            sb.Append("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;select 'SEC Filings' description,count(*), filing_date from secfilings group by 3 order by filing_date desc");
            break;
          case FeedStatistic.FeedStatisticType.PRICES:
            sb.Append("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;select 'Prices' description,count(*), date from prices group by 3 order by date desc");
            break;
          case FeedStatistic.FeedStatisticType.OPTIONS:
            sb.Append("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;select 'Options' description,count(*), modified from options where modified is not null group by 3 order by modified desc");
            break;
          case FeedStatistic.FeedStatisticType.INSIDER_TRANSACTIONS:
            sb.Append("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;select 'Insider Transactions' description,count(*), filing_date from insidertransaction group by 3 order by filing_date desc");
            break;
          case FeedStatistic.FeedStatisticType.FUNDAMENTALS:
            sb.Append("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;select 'Fundamentals' description,count(*), asof from fundamentals group by 3 order by asof desc");
            break;
          case FeedStatistic.FeedStatisticType.INCOME_STATEMENT:
            sb.Append("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;select 'Income Statement' description,count(*), modified from incomestatement group by 3 order by modified desc");
            break;
          case FeedStatistic.FeedStatisticType.CASHFLOW_STATEMENT:
            sb.Append("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;select 'Cashflow Statement' description,count(*), modified from cashflowstatement group by 3 order by modified desc");
            break;
          case FeedStatistic.FeedStatisticType.BALANCE_SHEET:
            sb.Append("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;select 'Balance Sheet' description,count(*), modified from balancesheet group by 3 order by modified desc");
            break;
          case FeedStatistic.FeedStatisticType.HISTORICAL:
            sb.Append("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;select 'Historical' description,count(*), asof from historical group by 3 order by asof desc");
            break;
          case FeedStatistic.FeedStatisticType.HEADLINES:
            sb.Append("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;select 'Headlines' description,count(*), asof from headlines group by 3 having count(*) > 10 order by asof desc");
            break;
          case FeedStatistic.FeedStatisticType.ETF_HOLDINGS:
            sb.Append("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;select 'ETF Holdings' description,count(*), modified from etfholdings group by 3 order by modified desc");
            break;
          case FeedStatistic.FeedStatisticType.ECONOMIC_INDICATORS:
            sb.Append("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;select 'Economic Indicators' description,count(*), Date(modified) from economicindicators group by 3 order by Date(modified) desc");
            break;
          case FeedStatistic.FeedStatisticType.EARNINGS_ANNOUNCEMENTS:
            sb.Append("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;select 'Earnings Announcements' description,count(*), period_ending from earningsannouncements group by 3 order by period_ending desc");
            break;
          case FeedStatistic.FeedStatisticType.DIVIDEND_HISTORY:
            sb.Append("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;select 'Dividend History' description,count(*),  CAST(modified AS DATE) modified from dividendhistory group by 3 order by CAST(modified AS DATE) desc");
            break;
          case FeedStatistic.FeedStatisticType.CURRENCY_CONVERSION:
            sb.Append("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;select 'Currency Conversion' description,count(*), asof from currencyconversion group by 3 order by asof desc");
            break;
          case FeedStatistic.FeedStatisticType.ANALYST_RATINGS:
            sb.Append("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;select 'Analyst Ratings' description,count(*), date from analystratings group by 3 order by date desc");
            break;
          case FeedStatistic.FeedStatisticType.ANALYST_PRICE_TARGET:
            sb.Append("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;select 'Analyst Price Target' description,count(*), date from analystpricetarget group by 3 order by date desc");
            break;
          default:
            return null;
        }
        strQuery = sb.ToString();
        sqlCommand = new MySqlCommand(strQuery, sqlConnection);
        sqlCommand.CommandTimeout = SqlUtils.COMMAND_TIMEOUT;
        sqlDataReader = sqlCommand.ExecuteReader();
        while (sqlDataReader.Read())
        {
          FeedStatistic feedStatistic = new FeedStatistic();
          feedStatistic.Feed = sqlDataReader.GetString(0);
          feedStatistic.Records = sqlDataReader.GetInt32(1);
          feedStatistic.Date = sqlDataReader.GetDateTime(2);
          feedStatistics.Add(feedStatistic);
        }
        return feedStatistics;
      }
      catch (Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG, exception.ToString());
        return null;
      }
      finally
      {
        if (null != sqlCommand) { sqlCommand.Dispose(); }
        if (null != sqlDataReader) { sqlDataReader.Close(); sqlDataReader.Dispose(); }
        if (null != sqlConnection) { sqlConnection.Close(); sqlConnection.Dispose(); }
      }
    }
    public static TimeSeriesCollection GetDebtToEquity(String symbol)
    {
      TimeSeriesCollection timeSeriesCollection=new TimeSeriesCollection();
      MySqlConnection sqlConnection = null;
      MySqlDataReader sqlDataReader = null;
      MySqlCommand sqlCommand=null;
      String strQuery = null;
      double prevStockHoldersEquity=double.NaN;
      double prevTotalDebt=double.NaN;
      int recordCount=0;

      try
      {
        StringBuilder sb = new StringBuilder();
        sqlConnection = SqlUtils.CreateMySqlConnection(MainDataSource.Instance.LocateDataSource("market_data"));
        sb.Append("set @symbol='").Append(symbol).Append("';");
        sb.Append("select A.symbol,A.year,A.total_debt,B.total_stockholder_equity,A.total_debt/B.total_stockholder_equity debt_to_equity from  ");
        sb.Append("( ");
        sb.Append("select MIN(f.symbol) symbol,MIN(YEAR(f.asof))year,AVG(f.total_debt)total_debt from fundamentals f where symbol=").Append(SqlUtils.ToSqlString(symbol));
        sb.Append(" group by YEAR(f.asof) order by 2 asc ");
        sb.Append(")A ");
        sb.Append("left join ");
        sb.Append("( ");
        sb.Append("select MIN(bs.symbol)symbol,MIN(YEAR(bs.asof)) year,AVG(bs.total_stockholder_equity) total_stockholder_equity from balancesheet bs where symbol=").Append(SqlUtils.ToSqlString(symbol)).Append(" and period=0 ");
        sb.Append("group by YEAR(bs.asof) order by 2 asc ");
        sb.Append(")B ");
        sb.Append("on A.symbol=B.symbol and A.year=B.year order by 2 asc");

        strQuery = sb.ToString();
        sqlCommand = new MySqlCommand(strQuery, sqlConnection);
        sqlCommand.CommandTimeout = SqlUtils.COMMAND_TIMEOUT;
        sqlDataReader = sqlCommand.ExecuteReader();
        while(sqlDataReader.Read())
        {
          double totalDebt=double.NaN;
          double totalStockholderEquity=double.NaN;
          double debtToEquity=double.NaN;
          symbol=sqlDataReader.GetString(0);
          int year=sqlDataReader.GetInt32(1);
          if(!sqlDataReader.IsDBNull(2))totalDebt=sqlDataReader.GetDouble(2);
          if(!sqlDataReader.IsDBNull(3))totalStockholderEquity=sqlDataReader.GetDouble(3);
          if(!sqlDataReader.IsDBNull(4))debtToEquity=sqlDataReader.GetDouble(4);

          if(0==recordCount&&(double.IsNaN(totalDebt)||double.IsNaN(totalStockholderEquity)))continue;
          if(double.IsNaN(totalStockholderEquity))totalStockholderEquity=prevStockHoldersEquity;
          if(double.IsNaN(totalDebt))totalDebt=prevTotalDebt;

          TimeSeriesElement timeSeriesElement=new TimeSeriesElement();
          timeSeriesElement.Symbol=symbol;
          timeSeriesElement.AsOf=new DateTime(year,1,1);
          timeSeriesElement.Type=TimeSeriesElement.ElementType.OTHER;
          timeSeriesElement.OtherType="DebtToEquity";
          timeSeriesElement.Value=totalDebt/totalStockholderEquity;
          timeSeriesCollection.Add(timeSeriesElement);
          recordCount++;
          prevStockHoldersEquity=totalStockholderEquity;
          prevTotalDebt=totalDebt;
        }
        return timeSeriesCollection;
      }
      catch (Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,exception);
        return null;
      }
      finally
      {
        if(null!=sqlCommand)sqlCommand.Dispose();
        if (null != sqlDataReader) sqlDataReader.Close();
        if (null != sqlConnection) sqlConnection.Close();
      }
    }
    public static DividendLoadCollection GetDividendLoad(String symbol)
    {
      DividendLoadCollection dividendLoadCollection=new DividendLoadCollection();
      MySqlConnection sqlConnection = null;
      MySqlDataReader sqlDataReader = null;
      MySqlCommand sqlCommand=null;
      String strQuery = null;

      try
      {
        StringBuilder sb = new StringBuilder();
        sqlConnection = SqlUtils.CreateMySqlConnection(MainDataSource.Instance.LocateDataSource("market_data"));
        sb.Append("SET @symbol='").Append(symbol).Append("';");
        sb.Append("select A.symbol,A.year,A.eps,B.cash_amount,B.records,(B.cash_amount/A.eps)*100.00 as dividend_load_pct from ");
        sb.Append(" (select MIN(h.symbol) symbol,MIN(YEAR(h.asof)) year,min(h.value) eps from historical h ");
        sb.Append(" where h.symbol=@symbol and h.type='eps' ");
        sb.Append(" group by YEAR(h.asof))A ");
        sb.Append(" inner join ( ");
        sb.Append(" select MIN(symbol) symbol,sum(dh.cash_amount) cash_amount,count(*) records,YEAR(dh.payment_date) year from dividendhistory dh ");
        sb.Append(" where dh.symbol=@symbol group by 4 ");
        sb.Append(" )B ");
        sb.Append(" on A.symbol=B.symbol and A.year=B.year ");
        sb.Append(" order by 2 desc");

        strQuery = sb.ToString();
        sqlCommand = new MySqlCommand(strQuery, sqlConnection);
        sqlCommand.CommandTimeout = SqlUtils.COMMAND_TIMEOUT;
        sqlDataReader = sqlCommand.ExecuteReader();
        while(sqlDataReader.Read())
        {
          DividendLoadElement dividendLoadElement = new DividendLoadElement();
          if(!sqlDataReader.IsDBNull(0))dividendLoadElement.Symbol=sqlDataReader.GetString(0);
          if(!sqlDataReader.IsDBNull(1))dividendLoadElement.Year=sqlDataReader.GetInt32(1);
          if(!sqlDataReader.IsDBNull(2))dividendLoadElement.EPS=sqlDataReader.GetDouble(2);
          if(!sqlDataReader.IsDBNull(3))dividendLoadElement.CashAmount=sqlDataReader.GetDouble(3);
          if(!sqlDataReader.IsDBNull(4))dividendLoadElement.Payments=sqlDataReader.GetInt32(4);
          if(!sqlDataReader.IsDBNull(5))dividendLoadElement.DividendLoadPcnt=sqlDataReader.GetDouble(5);
          dividendLoadCollection.Add(dividendLoadElement);
        }
        return dividendLoadCollection;
      }
      catch (Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,exception);
        return null;
      }
      finally
      {
        if(null!=sqlCommand)sqlCommand.Dispose();
        if (null != sqlDataReader) sqlDataReader.Close();
        if (null != sqlConnection) sqlConnection.Close();
      }
    }
    public static CompanyProfiles GetCompanyProfiles(String watchListName)
    {
      CompanyProfiles companyProfiles=new CompanyProfiles();
      MySqlConnection sqlConnection = null;
      MySqlDataReader sqlDataReader = null;
      MySqlCommand sqlCommand=null;
      String strQuery = null;

      try
      {
        StringBuilder sb = new StringBuilder();
        sqlConnection = SqlUtils.CreateMySqlConnection(MainDataSource.Instance.LocateDataSource("market_data"));
        sb.Append("select wl.symbol,sm.sector,sm.industry,sm.security_type,sm.company,cp.description ");
        sb.Append("from portfolio_data.watchlist wl ");
        sb.Append("join portfolio_data.watchlists wls on wls.watch_list_id=wl.watch_list_id ");
        sb.Append("join market_data.securitymaster sm on sm.symbol=wl.symbol  ");
        sb.Append("left outer join market_data.companyprofile cp on cp.symbol=wl.symbol  ");
        sb.Append("where wls.watch_list_name='").Append(watchListName).Append("'");
        strQuery = sb.ToString();
        sqlCommand = new MySqlCommand(strQuery, sqlConnection);
        sqlCommand.CommandTimeout = SqlUtils.COMMAND_TIMEOUT;
        sqlDataReader = sqlCommand.ExecuteReader();
        while(sqlDataReader.Read())
        {
          CompanyProfile companyProfile = new CompanyProfile();
          companyProfile.Symbol=sqlDataReader.GetString(0);
          if (!sqlDataReader.IsDBNull(1)) companyProfile.Sector = sqlDataReader.GetString(1);
          if (!sqlDataReader.IsDBNull(2)) companyProfile.Industry = sqlDataReader.GetString(2);
          if (!sqlDataReader.IsDBNull(3)) companyProfile.SecurityType = sqlDataReader.GetString(3);
          if (!sqlDataReader.IsDBNull(4)) companyProfile.CompanyName = sqlDataReader.GetString(4).ToUpper();
          if (!sqlDataReader.IsDBNull(5)) companyProfile.Description = sqlDataReader.GetString(5);
          companyProfiles.Add(companyProfile);
        }
        return companyProfiles;
      }
      catch (Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,exception);
        return null;
      }
      finally
      {
        if(null!=sqlCommand)sqlCommand.Dispose();
        if (null != sqlDataReader) sqlDataReader.Close();
        if (null != sqlConnection) sqlConnection.Close();
      }
    }
    public static EarningsAnnouncementModel GetEarningsAnnouncement(String symbol)
    {
      MySqlConnection sqlConnection = null;
      MySqlDataReader sqlDataReader = null;
			MySqlCommand sqlCommand=null;
      EarningsAnnouncementModel earningsAnnouncementModel=null;
      String strQuery = null;

      try
      {
        StringBuilder sb = new StringBuilder();
        sqlConnection = SqlUtils.CreateMySqlConnection(MainDataSource.Instance.LocateDataSource("market_data"));
        sb.Append("select f.symbol,f.asof as last_updated,p.date as pricing_date,p.close,p.open,f.pe,f.peg,(f.pe/f.peg)/100.00 as anticipated_earnings_growth,");
        sb.Append("case when f.peg<1 then 'UNDERVALUED' when f.peg>1 then 'OVERVALUED' else 'EQUILIBRIUM' end as peg_valuation,f.next_earnings_date,");
        sb.Append("datediff(f.next_earnings_date,curdate())as daysfromtoday,s.company,a.high_target as upside,(a.high_target-p.close)/p.close as upside_pcnt,");
        sb.Append("a.low_target as downside,(a.low_target-p.close)/p.close as downside_pcnt,a.date as price_target_asof ");
        sb.Append(" from fundamentals f ");
        sb.Append(" left outer join securitymaster s on s.symbol=f.symbol ");
        sb.Append(" left outer join analystpricetarget a on a.symbol=s.symbol");
        sb.Append(" left outer join prices p on a.symbol=p.symbol ");
        sb.Append(" where f.symbol='").Append(symbol).Append("' and f.asof=(select max(asof) from fundamentals where symbol='").Append(symbol).Append("')");
        sb.Append(" and a.symbol='").Append(symbol).Append("' and a.date=(select max(date) from analystpricetarget where symbol='").Append(symbol).Append("')");
        sb.Append(" and p.symbol='").Append(symbol).Append("' and p.date=(select max(date) from prices where symbol='").Append(symbol).Append("')");
        strQuery = sb.ToString(); ;
        sqlCommand = new MySqlCommand(strQuery, sqlConnection);
        sqlCommand.CommandTimeout = SqlUtils.COMMAND_TIMEOUT;
        sqlDataReader = sqlCommand.ExecuteReader();
        if (!sqlDataReader.Read()) return null;
        earningsAnnouncementModel=new EarningsAnnouncementModel();
        if(!sqlDataReader.IsDBNull(0))earningsAnnouncementModel.Symbol = sqlDataReader.GetString(0).ToUpper();
        if(!sqlDataReader.IsDBNull(1))earningsAnnouncementModel.FundamentalDate = sqlDataReader.GetDateTime(1);
        if(!sqlDataReader.IsDBNull(2))earningsAnnouncementModel.PricingDate = sqlDataReader.GetDateTime(2);
        if(!sqlDataReader.IsDBNull(3))earningsAnnouncementModel.LastPrice = sqlDataReader.GetDouble(3);
        if(!sqlDataReader.IsDBNull(5))earningsAnnouncementModel.PE = sqlDataReader.GetDouble(5);
        if(!sqlDataReader.IsDBNull(6))earningsAnnouncementModel.PEG = sqlDataReader.GetDouble(6);
        if(!sqlDataReader.IsDBNull(7))earningsAnnouncementModel.AnticipatedEarningsGrowth = sqlDataReader.GetDouble(7);
        if(!sqlDataReader.IsDBNull(8))earningsAnnouncementModel.PEGValuation = sqlDataReader.GetString(8);
        if(!sqlDataReader.IsDBNull(9))earningsAnnouncementModel.NextEarningsDate = sqlDataReader.GetDateTime(9);
        if(!sqlDataReader.IsDBNull(10))earningsAnnouncementModel.DaysFromToday = sqlDataReader.GetInt32(10);
        if(!sqlDataReader.IsDBNull(11))earningsAnnouncementModel.CompanyName = sqlDataReader.GetString(11).ToUpper();
        if(!sqlDataReader.IsDBNull(12))earningsAnnouncementModel.Upside = sqlDataReader.GetDouble(12);   
        if(!sqlDataReader.IsDBNull(13))earningsAnnouncementModel.UpsidePcnt = sqlDataReader.GetDouble(13);
        if(!sqlDataReader.IsDBNull(14))earningsAnnouncementModel.Downside = sqlDataReader.GetDouble(14);   
        if(!sqlDataReader.IsDBNull(15))earningsAnnouncementModel.DownsidePcnt = sqlDataReader.GetDouble(15);
        if(!sqlDataReader.IsDBNull(16))earningsAnnouncementModel.PriceTargetDate = sqlDataReader.GetDateTime(16);
        if(Utility.IsEpoch(earningsAnnouncementModel.NextEarningsDate))return null;
        return earningsAnnouncementModel;
      }
      catch (Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,exception);
        return null;
      }
      finally
      {
				if(null!=sqlCommand)sqlCommand.Dispose();
        if (null != sqlDataReader) sqlDataReader.Close();
        if (null != sqlConnection) sqlConnection.Close();
      }
    }
  }
}
