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