--- /dev/null
+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