Import TechBot
[reactos.git] / irc / TechBot / CHMLibrary / Index.cs
diff --git a/irc/TechBot/CHMLibrary/Index.cs b/irc/TechBot/CHMLibrary/Index.cs
new file mode 100644 (file)
index 0000000..76f7301
--- /dev/null
@@ -0,0 +1,322 @@
+using System;\r
+using System.Diagnostics;\r
+using System.Collections;\r
+using HtmlHelp.ChmDecoding;\r
+\r
+namespace HtmlHelp\r
+{\r
+       /// <summary>\r
+       /// Enumeration for specifying the index type\r
+       /// </summary>\r
+       public enum IndexType\r
+       {\r
+               /// <summary>\r
+               /// Keyword links should be used\r
+               /// </summary>\r
+               KeywordLinks = 0,\r
+               /// <summary>\r
+               /// Associative links should be used\r
+               /// </summary>\r
+               AssiciativeLinks = 1\r
+       }\r
+\r
+       /// <summary>\r
+       /// The class <c>Index</c> holds the (keyword links) KLinks and (associative links) ALinks of the htmlhelp \r
+       /// system. It implements methods for easy index-based searching.\r
+       /// </summary>\r
+       public class Index\r
+       {\r
+               private ArrayList _kLinks = new ArrayList();\r
+               private ArrayList _aLinks = new ArrayList();\r
+\r
+               /// <summary>\r
+               /// Standard constructor\r
+               /// </summary>\r
+               public Index()\r
+               {\r
+               }\r
+\r
+               /// <summary>\r
+               /// Constructor of the class\r
+               /// </summary>\r
+               /// <param name="kLinks">arraylist with keyword links</param>\r
+               /// <param name="aLinks">arraylist with associative links</param>\r
+               public Index(ArrayList kLinks, ArrayList aLinks)\r
+               {\r
+                       _kLinks= kLinks;\r
+                       _aLinks = aLinks;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Clears the current toc\r
+               /// </summary>\r
+               public void Clear()\r
+               {\r
+                       if(_aLinks != null)\r
+                               _aLinks.Clear();\r
+                       if(_kLinks != null)\r
+                               _kLinks.Clear();\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the number of index items for a specific type\r
+               /// </summary>\r
+               /// <param name="typeOfIndex">type of index</param>\r
+               /// <returns>Returns the number of index items for a specific type</returns>\r
+               public int Count(IndexType typeOfIndex)\r
+               {\r
+                       ArrayList _index = null;\r
+\r
+                       switch( typeOfIndex )\r
+                       {\r
+                               case IndexType.AssiciativeLinks: _index = _aLinks; break;\r
+                               case IndexType.KeywordLinks: _index = _kLinks; break;\r
+                       }\r
+\r
+                       if(_index != null)\r
+                               return _index.Count;\r
+\r
+                       return 0;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the internal index list of keyword links\r
+               /// </summary>\r
+               public ArrayList KLinks\r
+               {\r
+                       get \r
+                       {\r
+                               if(_kLinks==null)\r
+                                       _kLinks = new ArrayList();\r
+\r
+                               return _kLinks;\r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Gets the internal index list of associative links\r
+               /// </summary>\r
+               public ArrayList ALinks\r
+               {\r
+                       get \r
+                       {\r
+                               if(_aLinks==null)\r
+                                       _aLinks = new ArrayList();\r
+\r
+                               return _aLinks;\r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Merges the the index list <c>arrIndex</c> into the current one\r
+               /// </summary>\r
+               /// <param name="arrIndex">indexlist which should be merged with the current one</param>\r
+               /// <param name="typeOfIndex">type of index to merge</param>\r
+               public void MergeIndex( ArrayList arrIndex, IndexType typeOfIndex )\r
+               {\r
+                       ArrayList _index = null;\r
+\r
+                       switch(typeOfIndex)\r
+                       {\r
+                               case IndexType.AssiciativeLinks: _index = _aLinks;break;\r
+                               case IndexType.KeywordLinks: _index = _kLinks;break;\r
+                       }\r
+                       \r
+                       foreach(IndexItem curItem in arrIndex)\r
+                       {\r
+                               //IndexItem searchItem = ContainsIndex(_index, curItem.KeyWordPath);\r
+                               int insertIndex=0;\r
+                               IndexItem searchItem = BinSearch(0, _index.Count-1, _index, curItem.KeyWordPath, false, false, ref insertIndex);\r
+\r
+                               if(searchItem != null)\r
+                               {\r
+                                       // extend the keywords topics\r
+                                       foreach(IndexTopic curEntry in curItem.Topics)\r
+                                       {\r
+                                               searchItem.Topics.Add( curEntry );\r
+                                       }\r
+                               } \r
+                               else \r
+                               {\r
+                                       // add the item to the global collection\r
+                                       //_index.Add( curItem );\r
+\r
+                                       if(insertIndex > _index.Count)\r
+                                               _index.Add(curItem);\r
+                                       else\r
+                                       _index.Insert(insertIndex, curItem);\r
+                               }\r
+                       }                       \r
+               }\r
+\r
+               /// <summary>\r
+               /// Searches an index entry using recursive binary search algo (divide and conquer).\r
+               /// </summary>\r
+               /// <param name="nStart">start index for searching</param>\r
+               /// <param name="nEnd">end index for searching</param>\r
+               /// <param name="arrIndex">arraylist containing sorted IndexItem entries</param>\r
+               /// <param name="keywordPath">keyword path to search</param>\r
+               /// <param name="searchKeyword">true if the keywordPath will only contain the keyword not the complete path</param>\r
+               /// <param name="caseInsensitive">True if case should be ignored</param>\r
+               /// <param name="insertIndex">out reference. will receive the index where the item with the\r
+               /// keywordPath should be inserted if not found (receives -1 if the item was found)</param>\r
+               /// <returns>Returns an IndexItem instance if found, otherwise null \r
+               /// (use insertIndex for inserting the new item in a sorted order)</returns>\r
+               private IndexItem BinSearch(int nStart, int nEnd, ArrayList arrIndex, string keywordPath, \r
+                       bool searchKeyword, bool caseInsensitive, ref int insertIndex)\r
+               {\r
+                       if( arrIndex.Count <= 0 )\r
+                       {\r
+                               insertIndex=0;\r
+                               return null;\r
+                       }\r
+\r
+                       if(caseInsensitive)\r
+                               keywordPath = keywordPath.ToLower();\r
+\r
+                       if( (nEnd - nStart) > 1)\r
+                       {\r
+                               int nCheck = nStart + (nEnd-nStart)/2;\r
+\r
+                               IndexItem iC = arrIndex[nCheck] as IndexItem;\r
+\r
+                               string sCompare = iC.KeyWordPath;\r
+\r
+                               if(searchKeyword)\r
+                                       sCompare = iC.KeyWord;\r
+\r
+                               if(caseInsensitive)\r
+                                       sCompare = sCompare.ToLower();\r
+\r
+                               if( sCompare == keywordPath )\r
+                               {\r
+                                       insertIndex=-1;\r
+                                       return iC;\r
+                               }\r
+\r
+                               if( keywordPath.CompareTo(sCompare) < 0 )\r
+                               {\r
+                                       return BinSearch(nStart, nCheck-1, arrIndex, keywordPath, searchKeyword, caseInsensitive, ref insertIndex);\r
+                               }\r
+\r
+                               if( keywordPath.CompareTo(sCompare) > 0 )\r
+                               {\r
+                                       return BinSearch(nCheck+1, nEnd, arrIndex, keywordPath, searchKeyword, caseInsensitive, ref insertIndex);\r
+                               }\r
+                       }\r
+                       else if(nEnd-nStart == 1)\r
+                       {\r
+                               IndexItem i1 = arrIndex[nStart] as IndexItem;\r
+                               IndexItem i2 = arrIndex[nEnd] as IndexItem;\r
+\r
+                               string sCompare1 = i1.KeyWordPath;\r
+\r
+                               if(searchKeyword)\r
+                                       sCompare1 = i1.KeyWord;\r
+\r
+                               if(caseInsensitive)\r
+                                       sCompare1 = sCompare1.ToLower();\r
+\r
+                               string sCompare2 = i2.KeyWordPath;\r
+\r
+                               if(searchKeyword)\r
+                                       sCompare2 = i2.KeyWord;\r
+\r
+                               if(caseInsensitive)\r
+                                       sCompare2 = sCompare2.ToLower();\r
+\r
+                               if( sCompare1 == keywordPath)\r
+                               {\r
+                                       insertIndex = -1;\r
+                                       return i1;\r
+                               }\r
+\r
+                               if( sCompare2 == keywordPath)\r
+                               {\r
+                                       insertIndex = -1;\r
+                                       return i2;\r
+                               }\r
+\r
+                               if( sCompare1.CompareTo(keywordPath) > 0)\r
+                               {\r
+                                       insertIndex = nStart;\r
+                                       return null;\r
+                               } \r
+                               else if( sCompare2.CompareTo(keywordPath) > 0)\r
+                               {\r
+                                       insertIndex = nEnd;\r
+                                       return null;\r
+                               } \r
+                               else \r
+                               {\r
+                                       insertIndex = nEnd+1;\r
+                               }\r
+                       }\r
+\r
+                       IndexItem itm = arrIndex[nEnd] as IndexItem;\r
+\r
+                       string sCompareI = itm.KeyWordPath;\r
+\r
+                       if(searchKeyword)\r
+                               sCompareI = itm.KeyWord;\r
+\r
+                       if(caseInsensitive)\r
+                               sCompareI = sCompareI.ToLower();\r
+\r
+                       if( sCompareI.CompareTo(keywordPath) > 0)\r
+                       {\r
+                               insertIndex = nStart;\r
+                               return null;\r
+                       } \r
+                       else if( sCompareI.CompareTo(keywordPath) < 0)\r
+                       {\r
+                               insertIndex = nEnd+1;\r
+                               return null;\r
+                       }\r
+                       else\r
+                       {\r
+                               insertIndex = -1;\r
+                               return arrIndex[nEnd] as IndexItem;\r
+                       }\r
+               }\r
+\r
+               /// <summary>\r
+               /// Checks if a keyword exists in a index collection\r
+               /// </summary>\r
+               /// <param name="arrIndex">index to search (arraylist of IndexItems)</param>\r
+               /// <param name="keywordPath">keywordpath to search</param>\r
+               /// <returns>Returns the found IndexItem, otherwise null</returns>\r
+               private IndexItem ContainsIndex(ArrayList arrIndex, string keywordPath)\r
+               {\r
+                       foreach(IndexItem curItem in arrIndex)\r
+                       {\r
+                               if(curItem.KeyWordPath == keywordPath)\r
+                                       return curItem;\r
+                       }\r
+\r
+                       return null;\r
+               }\r
+\r
+               /// <summary>\r
+               /// Searches the alinks- or klinks-index for a specific keyword/associative\r
+               /// </summary>\r
+               /// <param name="search">keyword/associative to search</param>\r
+               /// <param name="typeOfIndex">type of index to search</param>\r
+               /// <returns>Returns an ArrayList which contains IndexTopic items or null if nothing was found</returns>\r
+               public IndexItem SearchIndex(string search, IndexType typeOfIndex)\r
+               {\r
+                       ArrayList _index = null;\r
+\r
+                       switch( typeOfIndex )\r
+                       {\r
+                               case IndexType.AssiciativeLinks: _index = _aLinks;break;\r
+                               case IndexType.KeywordLinks: _index = _kLinks;break;\r
+                       }\r
+\r
+                       int insertIdx=0;\r
+                       IndexItem foundItem = BinSearch(0, _index.Count, _index, search, true, true, ref insertIdx);\r
+\r
+                       return foundItem;\r
+               }\r
+       }\r
+}\r