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;
}
}
}