using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MarketData;
using MarketData.MarketDataModel;
using MarketData.Utils;

namespace MarketData.Utils
{
  public class FeedParser
  {
    private FeedParser()
    {
    }
    public static TimeSeriesCollection ParseTimeSeries(String symbol, List<DateTime> reportDates, TimeSeriesElement.ElementType elementType,String strLine)
    {
      TimeSeriesCollection timeSeriesCollection = new TimeSeriesCollection();
      Dictionary<DateTime,DateTime> dates = new Dictionary<DateTime,DateTime>();
      try
      {
        if (null == reportDates || 0 == reportDates.Count) return null;
        String[] lineItems = CSVLineHelper.ParseLine(strLine);
        if (null == lineItems) return null;
        for (int index = 0; index < reportDates.Count;index++)
        {
          TimeSeriesElement timeSeriesElement = new TimeSeriesElement();
          timeSeriesElement.Type = elementType;
          timeSeriesElement.Symbol = symbol;
          timeSeriesElement.AsOf = reportDates[index];
          if (lineItems.Length - 1 < index + 1) continue;
          timeSeriesElement.Value = ParseValue(lineItems[index + 1]);
          if (double.IsNaN(timeSeriesElement.Value)) continue;
          if (strLine.Contains("USD Mil"))
          {
            timeSeriesElement.Value *= 1000000.00;
          }
          if (!dates.ContainsKey(timeSeriesElement.AsOf))
          {
            dates.Add(timeSeriesElement.AsOf, timeSeriesElement.AsOf);
            timeSeriesCollection.Add(timeSeriesElement);
          }
        }
        return timeSeriesCollection;
      }
      catch (Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,exception.ToString());
        return null;
      }
    }
//"Book Value Per Share USD,3.31,3.22,2.64,2.58,2.28,2.10,1.39,2.64,3.88,3.94,3.94"
    public static List<DateTime> ParsePeriodEndingDates(String periodEnding)
    {
      List<DateTime> periodEndingDates = new List<DateTime>();
      if (null == periodEnding || !periodEnding.StartsWith("Period Ending")) return null;
      periodEnding = periodEnding.Replace("Period Ending", "");
      int length = periodEnding.Length;
      int index = 0;
      while (index<length)
      {
        String strMonth = periodEnding.Substring(index, 3);
        char ch;
        index += 3;
        StringBuilder sb = new StringBuilder();
        while ((ch = periodEnding[index++]) != ',') sb.Append(ch);
        String strDay = sb.ToString().Trim();
        sb = new StringBuilder();
        for (int yIndex = 0; yIndex < 5; yIndex++) sb.Append(periodEnding[index++]);
        String strYear = sb.ToString().Trim();
        DateTime periodEndingDate=DateTime.ParseExact(strMonth+Utility.Pad(strDay,'0',2)+strYear, "MMMddyyyy", new System.Globalization.CultureInfo("en-US"));
        periodEndingDates.Add(periodEndingDate);
      }
      return periodEndingDates;
    }
    public static DateTime ParseValueDateTime(String strText)
    {
      try
      {
        if(strText.Contains("Est"))
        {
          strText=Utility.RemoveAfter(strText,'-');
          strText = strText.Trim();
          strText = strText + " "+DateTime.Now.Year.ToString();
          string[] items = strText.Split(' ');
          strText = items[0] + "-" + Utility.Pad(items[1], '0', 2) + "-" + items[2];
          return DateTime.ParseExact(strText, "MMM-dd-yyyy", new System.Globalization.CultureInfo("en-US"));
        }
        else
        {
          strText = strText.Replace(" ", "0");
          return DateTime.ParseExact(strText, "dd-MMM-yy", new System.Globalization.CultureInfo("en-US"));
        }
      }
      catch(Exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,"[ParseValueDateTime] Error parsing date '"+strText+"'");
        return DateTime.Parse("01-01-0001");
      }
    }
// "Middleby Corp. Fri, Aug 2, 2013"
    public static DateTime ParseValueDateTimeMonthFormatFromMarketWatch(String strItem)
    {
      strItem = Utility.RemoveControlChars(strItem.Trim());
      String[] strItems = strItem.Split(' ');
      if (strItems.Length < 3) return DateTime.Parse("01-01-0001"); ;
      String strDate = strItems[strItems.Length - 3] + " " + strItems[strItems.Length - 2] + " " + strItems[strItems.Length - 1];
      return ParseValueDateTimeMonthFormat(strDate);
    }
    public static double ParseValueFromMarketWatch(String identifier,String strItem)
    {
      try
      {
        strItem = Utility.RemoveControlChars(strItem.Trim());
        identifier = identifier.ToLower();
        strItem = strItem.ToLower();
        if (!strItem.StartsWith(identifier)) return double.NaN;
        String strValue = strItem.Substring(strItem.IndexOf(':') + 1).Trim();
        return double.Parse(strValue);
      }
      catch (Exception)
      {
        return double.NaN;
      }
    }
    public static long ParseLongValueFromMarketWatch(String identifier, String strItem)
    {
      try
      {
        strItem = Utility.RemoveControlChars(strItem.Trim());
        identifier = identifier.ToLower();
        strItem = strItem.ToLower();
        if (!strItem.StartsWith(identifier)) return 0;
        String strValue = strItem.Substring(strItem.IndexOf(':') + 1).Trim();
        strValue = strValue.Replace(",", "");
        return long.Parse(strValue);
      }
      catch (Exception)
      {
        return 0;
      }
    }
    //"Aug 23, 2013"
    public static DateTime ParseValueDateTimeMonthFormat(String strText)
    {
      try
      {
        if(null==strText)return Utility.Epoch;
        String[] strArray = strText.Split(' ');
        if (3 != strArray.Length) return DateTime.Parse("01-01-0001");
        strArray[1] = strArray[1].Replace(",", "");
        return ParseValueDateTime(Utility.Pad(strArray[1],'0',2)+"-"+strArray[0]+"-"+strArray[2].Substring(2,2));
      }
      catch (Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,"[ParseValueDateTimeMonthFormat] Error parsing date '" + strText + "', "+exception.ToString());
        return DateTime.Parse("01-01-0001");
      }
    }
    // "Apr. 04"
    // "1:00pm"
    public static DateTime ParseValueDateTimeMonth(String strText)
    {
      try
      {
        if(null==strText)return DateTime.Parse("01-01-0001");

        if(strText.EndsWith("am") || strText.EndsWith("pm"))
        {
          return DateTime.Now;
        }
        else if(strText.Contains("."))
        {
          strText=strText.Replace(".",null);            
          String[] subItems=strText.Split(' ');
          DateTime currentDate = DateTime.Now;
          StringBuilder sb=new StringBuilder();
          sb.Append(subItems[0]).Append(" ");
          sb.Append(subItems[1]).Append(",").Append(" ");
          sb.Append(currentDate.Year.ToString());
          DateTime resultingDate = ParseValueDateTimeMonthFormat(sb.ToString());
          if(resultingDate>currentDate)resultingDate = new DateTime(resultingDate.Year-1,resultingDate.Month, resultingDate.Day);
          return resultingDate;
        }
        else
        {
          return Utility.ParseDate(strText);
        }
      }
      catch (Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG, "[ParseValueDateTimeMonth] Error parsing date '" + strText + "', " + exception.ToString());
        return DateTime.Parse("01-01-0001");
      }
    }


    // Sep. 25, 2022 at 4:31 p.m. ET
    public static DateTime ParseValueDateTimeMonthFormatTZ(String strText)
    {
      try
      {
        if(null==strText)return Utility.Epoch;
        String[] strArray = strText.Split(' ');
        if (3 > strArray.Length) return DateTime.Parse("01-01-0001");
        strArray[1] = strArray[1].Replace(",", null);
        strArray[0] = strArray[0].Replace(".", null);
        return ParseValueDateTime(Utility.Pad(strArray[1],'0',2)+"-"+strArray[0]+"-"+strArray[2].Substring(2,2));
      }
      catch (Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,"[ParseValueDateTimeMonthFormat] Error parsing date '" + strText + "', "+exception.ToString());
        return DateTime.Parse("01-01-0001");
      }
    }

    public static DateTime? ParseRelativeDate(String strDate)
    {
      try
      {
        DateTime today=DateTime.Now;
        if(strDate.Contains("day"))
        {
          DateGenerator dateGenerator=new DateGenerator();
          String[] items=strDate.Split(' ');
          DateTime relativeDate=dateGenerator.GenerateHistoricalDate(today,int.Parse(items[0])+1);
          return relativeDate;
        }
        else if(strDate.Contains("hour"))
        {
          String[] items=strDate.Split(' ');
          TimeSpan timeSpan=new TimeSpan(int.Parse(items[0]),0,0);
          DateTime relativeDate=today.Subtract(timeSpan);
          return relativeDate;
        }
        else if(strDate.Contains("minute"))
        {
          String[] items=strDate.Split(' ');
          TimeSpan timeSpan=new TimeSpan(0,int.Parse(items[0]),0);
          DateTime relativeDate=today.Subtract(timeSpan);
          return relativeDate;
        }
        return ParseValueDateTimeMonthFormat(strDate);
      }
      catch(Exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Unable to parse date '{0}'",strDate));
        return null;
      }
    }
    public static double ParseValue(String strText)
    {
      double value = double.NaN;
      double multiplier = 1.00;
      try
      {
        if (null == strText || 0 == strText.Length) return double.NaN;
        strText=strText.Trim();
        if(strText.StartsWith("--"))return double.NaN;
        if(strText.Equals("N/A"))return double.NaN;
        strText=strText.Replace("%", "");
        strText = strText.Replace("$", "");
        if (strText.Contains("("))
        {
          strText=strText.Replace("(", "");
          strText=strText.Replace(")", "");
          multiplier = -1.00;
        }
        if (strText.Equals("-")) return double.NaN;
        if (strText[strText.Length - 1].Equals('T'))
        {
          strText = strText.Replace("T", "");
          value = double.Parse(strText);
          value *= 1000000000000;
        }
        if (strText[strText.Length - 1].Equals('B'))
        {
          strText = strText.Replace("B", "");
          value = double.Parse(strText);
          value *= 1000000000;
        }
        else if (strText[strText.Length - 1].Equals('M'))
        {
          strText = strText.Replace("M", "");
          value = double.Parse(strText);
          value *= 1000000;
        }
        else if (strText[strText.Length - 1].Equals('K')||strText[strText.Length - 1].Equals('k'))
        {
          strText = strText.Replace("K", "");
          strText = strText.Replace("k", "");
          value = double.Parse(strText);
          value *= 1000;
        }
        else value = double.Parse(strText);
        value *= multiplier;
        return value;
      }
      catch (Exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,"[ParseValue] Error parsing '"+strText+"'");
        return double.NaN;
      }
    }

    public static long ParseValueLong(String strText)
    {
      long value;
      try
      {
        if(null==strText)return 0;
        strText=strText.Replace("%","");
        strText = strText.Replace(",", "");
        if (strText.Equals("-")) return 0;
        if (strText[strText.Length - 1].Equals('B'))
        {
          strText = strText.Replace("B", "");
          value = Int64.Parse(strText);
          value *= 1000000000;
        }
        else if (strText[strText.Length - 1].Equals('M'))
        {
          strText = strText.Replace("M", "");
          value = Int64.Parse(strText);
          value *= 1000000;
        }
        else if (strText[strText.Length - 1].Equals('K'))
        {
          strText = strText.Replace("K", "");
          value = Int64.Parse(strText);
          value *= 1000;
        }
        else value = Int64.Parse(strText);
        return value;
      }
      catch (Exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,"[ParseValueLong] Error parsing '" + strText + "'");
        return 0;
      }
    }
  }
}
