using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MarketDataLib.Utility
{
  public class Sections
  {
    private Sections()
    {
    }
// returns the length of string containing the section.
// Given: "kaskHSkahsKAHSLDFDLFG<article>......</article>ALaks;LKSA;ks;a;SKL;ks;aKS;"
// will return <article>.....</article>
    public static String GetItemsInSection(String strInput,String sectionName,ref int searchIndex)
    {
      String startSection="<"+sectionName;
      String endSection="</"+sectionName;

      int startIndex=strInput.IndexOf(startSection,searchIndex);
      if(-1==startIndex){searchIndex=-1;return null;}
      int endIndex=strInput.IndexOf(endSection,startIndex);
      if(-1==endIndex){searchIndex=-1;return null;}
      searchIndex=endIndex+endSection.Length;
      String strContainingString=strInput.Substring(startIndex,(endIndex-startIndex)+endSection.Length+1);
      if(String.IsNullOrEmpty(strContainingString))return null;
      return strContainingString;
    }

    public static List<String> GetAllItemsInSections(String strInput, String sectionName)
    {
      int searchIndex = 0;
      List<String> sectionItems = new List<string>();

      while (true)
      {
        String itemsInSection = GetItemsInSection(strInput, sectionName, ref searchIndex);
        if(null==itemsInSection)break;
        sectionItems.Add(itemsInSection);
        searchIndex++;
      }
      return sectionItems;
    }
    public static List<String> GetSections(String strInput)
    {
      try
      {
        List<String> sections=new List<String>();
        int index=0;
        String strLiteral=null;

        if(null==strInput)return null;
        while(index<strInput.Length)
        {
          char ch=strInput[index];
          if(ch=='>')
          {
            strLiteral=ScanSection(strInput,ref index);
            if(null!=strLiteral&&!":??".Equals(strLiteral))
            {
              if (strLiteral.Contains("&amp;")) strLiteral = strLiteral.Replace("&amp;", "&");
              if(strLiteral.Contains("&quot;")) strLiteral=strLiteral.Replace("&quot;","'");
              if(strLiteral.Contains("&#039;")) strLiteral=strLiteral.Replace("&#039;","'");
              if(strLiteral.Contains("&mdash;")) strLiteral=strLiteral.Replace("&mdash;","-");
							if(strLiteral.Contains("&nbsp;")) strLiteral=strLiteral.Replace("&nbsp;"," ");
              sections.Add(strLiteral);
            }
          }
          index++;
        }
        return sections;
      }
      catch(Exception)
      {
        return null;
      }
    }
    
    public static List<String> FlattenSection(List<String> section)
    {
      List<String> flattened = new List<String>();

      foreach(String item in section)
      {
        if("".Equals(item))continue;
        flattened.Add(item);
      }
      return flattened;
    }

    public static bool FindInSections(List<String> sections,String startsWith,int startingIndex,ref int indexOfItem,bool findExact=true)
    {
      for(int index=startingIndex;index<sections.Count;index++)
      {
        if(!findExact &&sections[index].StartsWith(startsWith))
        {
          indexOfItem=index;
          return true;
        }
        else if(sections[index].Equals(startsWith))
        {
          indexOfItem=index;
          return true;
        }
      }
      return false;
    }
    public static bool FindInSectionsReverse(List<String> sections,String startsWith,int startingIndex,ref int indexOfItem,bool findExact=true)
    {
      for(int index=startingIndex;index>=0;index--)
      {
        if(!findExact &&sections[index].StartsWith(startsWith))
        {
          indexOfItem=index;
          return true;
        }
        else if(sections[index].Equals(startsWith))
        {
          indexOfItem=index;
          return true;
        }
      }
      return false;
    }
    public static String ScanSectionsFindStartWithReturnIndexAfter(List<String> sections, String startsWith, int indexAfter)
    {
      if (null == sections || 0 == sections.Count) return null;
      for (int index = 0; index < sections.Count; index++)
      {
        String sectionItem = sections[index];
        if (null == sectionItem || "".Equals(sectionItem)||!sectionItem.StartsWith(startsWith)) continue;
        return sections[index + indexAfter];
      }
      return null;
    }
    public static List<String> LocateItems(String strInput,String item,int startIndex,int iterator)
    {
      List<String> items=new List<String>();
      try
      {
        if(null==item||null==strInput)return null;
        int startPos=strInput.IndexOf(item);
        if(-1==startPos)return null;
        strInput=strInput.Substring(startPos-1);
        List<String> sections=Sections.GetSections(strInput);
        if(0==sections.Count||sections.Count<=startIndex)return null;
        if(!item.Contains(sections[0])||"".Equals(sections[0]))return null;
        for(;startIndex<sections.Count;startIndex+=iterator)
        {
          String strItem=sections[startIndex];
          if("".Equals(strItem)||"-".Equals(strItem))return items;
          items.Add(strItem);
        }
        return items;
      }
      catch(Exception)
      {
        return null;
      }
    }
    public static List<String> GetItemSections(String strInput,String item)
    {
      int startIndex=0;

      List<String> items=new List<String>();
      try
      {
        if(null==item||null==strInput)return null;
        int startPos=strInput.IndexOf(item);
        if(-1==startPos)return null;
        strInput=strInput.Substring(startPos-1);
        List<String> sections=Sections.GetSections(strInput);
        if(0==sections.Count||sections.Count<=startIndex)return null;
        return sections;
      }
      catch(Exception)
      {
        return null;
      }
    }

    public static List<String> LocateItems(String strInput,String item)
    {
      int startIndex=0;

      List<String> items=new List<String>();
      try
      {
        if(null==item||null==strInput)return null;
        int startPos=strInput.IndexOf(item);
        if(-1==startPos)return null;
        strInput=strInput.Substring(startPos-1);
        List<String> sections=Sections.GetSections(strInput);
        if(0==sections.Count||sections.Count<=startIndex)return null;
        if(!item.Contains(sections[0])||"".Equals(sections[0]))return null;
        for(;startIndex<sections.Count;startIndex++)
        {
          String strItem=sections[startIndex];
          if(item.Contains(strItem))continue;
          if("".Equals(strItem)||"-".Equals(strItem))continue;
          if(strItem.All(Char.IsLetter)||strItem.Contains(" "))break;
          items.Add(strItem);
        }
        return items;
      }
      catch(Exception)
      {
        return null;
      }
    }


    public static List<int> LocateAllOccurrences(List<String> sections, String item)
    {
      List<int> itemIndices = new List<int>();

      try
      {
        if(null==item)return null;
        if(null==sections||0==sections.Count)return null;
        for(int startIndex=0;startIndex<sections.Count;startIndex++)
        {
          String sectionItem=sections[startIndex];
          if(sectionItem.Contains(item))
          {
            itemIndices.Add(startIndex);
            continue;
          }
        }
        return itemIndices;
      }
      catch(Exception)
      {
        return null;
      }
    }

    public static List<int> LocateAllOccurrences(String strInput,String item)
    {
      try
      {
        List<String> sections=Sections.GetSections(strInput);
        return LocateAllOccurrences(sections, item);
      }
      catch(Exception)
      {
        return null;
      }
    }

    public static String LocateItem(String strInput,String item,int maxDepth)
    {
      int startIndex=0;
      String strItem=null;
      try
      {
        int depth=0;
        if(null==item||null==strInput)return null;
        int startPos=strInput.IndexOf(item);
        if(-1==startPos)return null;
        strInput=strInput.Substring(startPos-1);
        List<String> sections=Sections.GetSections(strInput);
        if(null==sections||0==sections.Count)return null;
        if(!item.Contains(sections[0])||"".Equals(sections[0]))return null;
        startIndex++;
        for(;startIndex<sections.Count;startIndex++)
        {
          String sectionItem=sections[startIndex];
          if("".Equals(sectionItem)||"-".Equals(sectionItem)||sectionItem.StartsWith("("))
          {
            depth++;
            if(depth>maxDepth)return null;
            continue;
          }
          strItem=sectionItem;
          break;
        }
        return strItem;
      }
      catch(Exception)
      {
        return null;
      }
    }
    public static String LocateItem(String strInput,String item)
    {
      int startIndex=0;
      String strItem=null;
      try
      {
        if(null==item||null==strInput)return null;
        int startPos=strInput.IndexOf(item);
        if(-1==startPos)return null;
        strInput=strInput.Substring(startPos-1);
        List<String> sections=Sections.GetSections(strInput);
        if(null==sections||0==sections.Count)return null;
        if(!item.Contains(sections[0])||"".Equals(sections[0]))return null;
        for(;startIndex<sections.Count;startIndex++)
        {
          String sectionItem=sections[startIndex];
          if(item.Contains(sectionItem))continue;
          if("".Equals(sectionItem)||"-".Equals(sectionItem)||"--".Equals(sectionItem)||sectionItem.StartsWith("("))continue;
          if((sectionItem.All(Char.IsLetter)||sectionItem.Contains(" ")))break;
          strItem=sectionItem;
          break;
        }
        return strItem;
      }
      catch(Exception)
      {
        return null;
      }
    }
    public static String LocateItemAcceptAnyText(String strInput,String item)
    {
      int startIndex=0;
      String strItem=null;
      try
      {
        if(null==item||null==strInput)return null;
        int startPos=strInput.IndexOf(item);
        if(-1==startPos)return null;
        strInput=strInput.Substring(startPos-1);
        List<String> sections=Sections.GetSections(strInput);
        if(null==sections||0==sections.Count)return null;
        if(!item.Contains(sections[0])||"".Equals(sections[0]))return null;
        for(;startIndex<sections.Count;startIndex++)
        {
          String sectionItem=sections[startIndex];
          if(item.Contains(sectionItem))continue;
          if("".Equals(sectionItem)||"-".Equals(sectionItem)||sectionItem.StartsWith("("))continue;
          strItem=sectionItem;
          break;
        }
        return strItem;
      }
      catch(Exception)
      {
        return null;
      }
    }
    public static String LocateItemAcceptAnyTextMinDepth(String strInput,String item,int minIndex)
    {
      int startIndex=0;
      String strItem=null;
      try
      {
        if(null==item||null==strInput)return null;
        int startPos=strInput.IndexOf(item);
        if(-1==startPos)return null;
        strInput=strInput.Substring(startPos-1);
        List<String> sections=Sections.GetSections(strInput);
        if(null==sections||0==sections.Count)return null;
        if(!item.Contains(sections[0])||"".Equals(sections[0]))return null;
        for(;startIndex<sections.Count;startIndex++)
        {
          String sectionItem=sections[startIndex];
          if(item.Contains(sectionItem))continue;
          if("".Equals(sectionItem)||"-".Equals(sectionItem)||sectionItem.StartsWith("("))continue;
          if(startIndex<minIndex)continue;
           strItem=sectionItem;
          break;
        }
        if(strItem.Equals("-"))strItem=null;
        return strItem;
      }
      catch(Exception)
      {
        return null;
      }
    }
    public static String LocateItemMinDepth(String strInput,String item,int minIndex)
    {
      int startIndex=0;
      String strItem=null;
      try
      {
        if(null==item||null==strInput)return null;
        int startPos=strInput.IndexOf(item);
        if(-1==startPos)return null;
        strInput=strInput.Substring(startPos-1);
        List<String> sections=Sections.GetSections(strInput);
        if(null==sections||0==sections.Count)return null;
        if(!item.Contains(sections[0])||"".Equals(sections[0]))return null;
        for(;startIndex<sections.Count;startIndex++)
        {
          String sectionItem=sections[startIndex];
          if(item.Contains(sectionItem))continue;
          if("".Equals(sectionItem)||"-".Equals(sectionItem)||sectionItem.StartsWith("("))continue;
          if(startIndex<minIndex)continue;
          if((sectionItem.All(Char.IsLetter)||sectionItem.Contains(" ")))break;
          strItem=sectionItem;
          break;
        }
        return strItem;
      }
      catch(Exception)
      {
        return null;
      }
    }
    public static String LocateItemAtDepth(String strInput,String item,int depth)
    {
      String strItem=null;
      try
      {
        if(null==item||null==strInput) return null;
        int startPos=strInput.IndexOf(item);
        if(-1==startPos) return null;
        strInput=strInput.Substring(startPos-1);
        List<String> sections=Sections.GetSections(strInput);
        strItem=Sections.ScanSectionsFindStartWithReturnIndexAfter(sections,item,depth);
        if(null==strItem||strItem.Equals("-"))return null;
        return strItem;
      }
      catch(Exception)
      {
        return null;
      }
    }
    public static String LocateFirstItem(String strInput,String item)
    {
      int startIndex=0;
      String strItem=null;
      try
      {
        if(null==item||null==strInput)return null;
        int startPos=strInput.IndexOf(item);
        if(-1==startPos)return null;
        strInput=strInput.Substring(startPos-1);
        List<String> sections=Sections.GetSections(strInput);
        if(null==sections||0==sections.Count)return null;
        if(!item.Contains(sections[0])||"".Equals(sections[0]))return null;
        for(;startIndex<sections.Count;startIndex++)
        {
          String sectionItem=sections[startIndex];
          if(item.Contains(sectionItem))continue;
          if("".Equals(sectionItem))continue;
          strItem=sectionItem;
          break;
        }
        return strItem;
      }
      catch(Exception)
      {
        return null;
      }
    }

    private static String GetItem(String strInput, String item)
    {
      if (null == strInput) return null;
      int startIndex = strInput.IndexOf(item);
      if (-1 == startIndex) return null;
      strInput = strInput.Substring(startIndex);
      String strItem = MarketData.Utils.Utility.BetweenString(strInput, ">", "<");
      return strItem;
    }

    public static String GetFirstNonEmptyItemInSection(List<String> sections, int startingIndex)
    {
      if(startingIndex>=sections.Count)return null;
      for(int index=startingIndex;index < sections.Count;index++)
      {
        String sectionItem = sections[index].Trim();
        if(String.IsNullOrEmpty(sectionItem))continue;
        return sectionItem;
      }
      return null;
    }

    private static String ScanSection(String strInput, ref int index)
    {
      try
      {
        StringBuilder sb=new StringBuilder();
        index++;
        while(index<strInput.Length)
        {
          char ch=strInput[index++];
          if('<'.Equals(ch))
            return sb.ToString().Trim();
          sb.Append(ch);
        }
        return null;
      }
      catch(Exception)
      {
        return null;
      }
    }
  }
}
