- Change dispatcher lock release to be more like documented in Windows Internals...
[reactos.git] / irc / TechBot / CHMLibrary / Index.cs
1 using System;
2 using System.Diagnostics;
3 using System.Collections;
4 using HtmlHelp.ChmDecoding;
5
6 namespace HtmlHelp
7 {
8 /// <summary>
9 /// Enumeration for specifying the index type
10 /// </summary>
11 public enum IndexType
12 {
13 /// <summary>
14 /// Keyword links should be used
15 /// </summary>
16 KeywordLinks = 0,
17 /// <summary>
18 /// Associative links should be used
19 /// </summary>
20 AssiciativeLinks = 1
21 }
22
23 /// <summary>
24 /// The class <c>Index</c> holds the (keyword links) KLinks and (associative links) ALinks of the htmlhelp
25 /// system. It implements methods for easy index-based searching.
26 /// </summary>
27 public class Index
28 {
29 private ArrayList _kLinks = new ArrayList();
30 private ArrayList _aLinks = new ArrayList();
31
32 /// <summary>
33 /// Standard constructor
34 /// </summary>
35 public Index()
36 {
37 }
38
39 /// <summary>
40 /// Constructor of the class
41 /// </summary>
42 /// <param name="kLinks">arraylist with keyword links</param>
43 /// <param name="aLinks">arraylist with associative links</param>
44 public Index(ArrayList kLinks, ArrayList aLinks)
45 {
46 _kLinks= kLinks;
47 _aLinks = aLinks;
48 }
49
50 /// <summary>
51 /// Clears the current toc
52 /// </summary>
53 public void Clear()
54 {
55 if(_aLinks != null)
56 _aLinks.Clear();
57 if(_kLinks != null)
58 _kLinks.Clear();
59 }
60
61 /// <summary>
62 /// Gets the number of index items for a specific type
63 /// </summary>
64 /// <param name="typeOfIndex">type of index</param>
65 /// <returns>Returns the number of index items for a specific type</returns>
66 public int Count(IndexType typeOfIndex)
67 {
68 ArrayList _index = null;
69
70 switch( typeOfIndex )
71 {
72 case IndexType.AssiciativeLinks: _index = _aLinks; break;
73 case IndexType.KeywordLinks: _index = _kLinks; break;
74 }
75
76 if(_index != null)
77 return _index.Count;
78
79 return 0;
80 }
81
82 /// <summary>
83 /// Gets the internal index list of keyword links
84 /// </summary>
85 public ArrayList KLinks
86 {
87 get
88 {
89 if(_kLinks==null)
90 _kLinks = new ArrayList();
91
92 return _kLinks;
93 }
94 }
95
96 /// <summary>
97 /// Gets the internal index list of associative links
98 /// </summary>
99 public ArrayList ALinks
100 {
101 get
102 {
103 if(_aLinks==null)
104 _aLinks = new ArrayList();
105
106 return _aLinks;
107 }
108 }
109
110 /// <summary>
111 /// Merges the the index list <c>arrIndex</c> into the current one
112 /// </summary>
113 /// <param name="arrIndex">indexlist which should be merged with the current one</param>
114 /// <param name="typeOfIndex">type of index to merge</param>
115 public void MergeIndex( ArrayList arrIndex, IndexType typeOfIndex )
116 {
117 ArrayList _index = null;
118
119 switch(typeOfIndex)
120 {
121 case IndexType.AssiciativeLinks: _index = _aLinks;break;
122 case IndexType.KeywordLinks: _index = _kLinks;break;
123 }
124
125 foreach(IndexItem curItem in arrIndex)
126 {
127 //IndexItem searchItem = ContainsIndex(_index, curItem.KeyWordPath);
128 int insertIndex=0;
129 IndexItem searchItem = BinSearch(0, _index.Count-1, _index, curItem.KeyWordPath, false, false, ref insertIndex);
130
131 if(searchItem != null)
132 {
133 // extend the keywords topics
134 foreach(IndexTopic curEntry in curItem.Topics)
135 {
136 searchItem.Topics.Add( curEntry );
137 }
138 }
139 else
140 {
141 // add the item to the global collection
142 //_index.Add( curItem );
143
144 if(insertIndex > _index.Count)
145 _index.Add(curItem);
146 else
147 _index.Insert(insertIndex, curItem);
148 }
149 }
150 }
151
152 /// <summary>
153 /// Searches an index entry using recursive binary search algo (divide and conquer).
154 /// </summary>
155 /// <param name="nStart">start index for searching</param>
156 /// <param name="nEnd">end index for searching</param>
157 /// <param name="arrIndex">arraylist containing sorted IndexItem entries</param>
158 /// <param name="keywordPath">keyword path to search</param>
159 /// <param name="searchKeyword">true if the keywordPath will only contain the keyword not the complete path</param>
160 /// <param name="caseInsensitive">True if case should be ignored</param>
161 /// <param name="insertIndex">out reference. will receive the index where the item with the
162 /// keywordPath should be inserted if not found (receives -1 if the item was found)</param>
163 /// <returns>Returns an IndexItem instance if found, otherwise null
164 /// (use insertIndex for inserting the new item in a sorted order)</returns>
165 private IndexItem BinSearch(int nStart, int nEnd, ArrayList arrIndex, string keywordPath,
166 bool searchKeyword, bool caseInsensitive, ref int insertIndex)
167 {
168 if( arrIndex.Count <= 0 )
169 {
170 insertIndex=0;
171 return null;
172 }
173
174 if(caseInsensitive)
175 keywordPath = keywordPath.ToLower();
176
177 if( (nEnd - nStart) > 1)
178 {
179 int nCheck = nStart + (nEnd-nStart)/2;
180
181 IndexItem iC = arrIndex[nCheck] as IndexItem;
182
183 string sCompare = iC.KeyWordPath;
184
185 if(searchKeyword)
186 sCompare = iC.KeyWord;
187
188 if(caseInsensitive)
189 sCompare = sCompare.ToLower();
190
191 if( sCompare == keywordPath )
192 {
193 insertIndex=-1;
194 return iC;
195 }
196
197 if( keywordPath.CompareTo(sCompare) < 0 )
198 {
199 return BinSearch(nStart, nCheck-1, arrIndex, keywordPath, searchKeyword, caseInsensitive, ref insertIndex);
200 }
201
202 if( keywordPath.CompareTo(sCompare) > 0 )
203 {
204 return BinSearch(nCheck+1, nEnd, arrIndex, keywordPath, searchKeyword, caseInsensitive, ref insertIndex);
205 }
206 }
207 else if(nEnd-nStart == 1)
208 {
209 IndexItem i1 = arrIndex[nStart] as IndexItem;
210 IndexItem i2 = arrIndex[nEnd] as IndexItem;
211
212 string sCompare1 = i1.KeyWordPath;
213
214 if(searchKeyword)
215 sCompare1 = i1.KeyWord;
216
217 if(caseInsensitive)
218 sCompare1 = sCompare1.ToLower();
219
220 string sCompare2 = i2.KeyWordPath;
221
222 if(searchKeyword)
223 sCompare2 = i2.KeyWord;
224
225 if(caseInsensitive)
226 sCompare2 = sCompare2.ToLower();
227
228 if( sCompare1 == keywordPath)
229 {
230 insertIndex = -1;
231 return i1;
232 }
233
234 if( sCompare2 == keywordPath)
235 {
236 insertIndex = -1;
237 return i2;
238 }
239
240 if( sCompare1.CompareTo(keywordPath) > 0)
241 {
242 insertIndex = nStart;
243 return null;
244 }
245 else if( sCompare2.CompareTo(keywordPath) > 0)
246 {
247 insertIndex = nEnd;
248 return null;
249 }
250 else
251 {
252 insertIndex = nEnd+1;
253 }
254 }
255
256 IndexItem itm = arrIndex[nEnd] as IndexItem;
257
258 string sCompareI = itm.KeyWordPath;
259
260 if(searchKeyword)
261 sCompareI = itm.KeyWord;
262
263 if(caseInsensitive)
264 sCompareI = sCompareI.ToLower();
265
266 if( sCompareI.CompareTo(keywordPath) > 0)
267 {
268 insertIndex = nStart;
269 return null;
270 }
271 else if( sCompareI.CompareTo(keywordPath) < 0)
272 {
273 insertIndex = nEnd+1;
274 return null;
275 }
276 else
277 {
278 insertIndex = -1;
279 return arrIndex[nEnd] as IndexItem;
280 }
281 }
282
283 /// <summary>
284 /// Checks if a keyword exists in a index collection
285 /// </summary>
286 /// <param name="arrIndex">index to search (arraylist of IndexItems)</param>
287 /// <param name="keywordPath">keywordpath to search</param>
288 /// <returns>Returns the found IndexItem, otherwise null</returns>
289 private IndexItem ContainsIndex(ArrayList arrIndex, string keywordPath)
290 {
291 foreach(IndexItem curItem in arrIndex)
292 {
293 if(curItem.KeyWordPath == keywordPath)
294 return curItem;
295 }
296
297 return null;
298 }
299
300 /// <summary>
301 /// Searches the alinks- or klinks-index for a specific keyword/associative
302 /// </summary>
303 /// <param name="search">keyword/associative to search</param>
304 /// <param name="typeOfIndex">type of index to search</param>
305 /// <returns>Returns an ArrayList which contains IndexTopic items or null if nothing was found</returns>
306 public IndexItem SearchIndex(string search, IndexType typeOfIndex)
307 {
308 ArrayList _index = null;
309
310 switch( typeOfIndex )
311 {
312 case IndexType.AssiciativeLinks: _index = _aLinks;break;
313 case IndexType.KeywordLinks: _index = _kLinks;break;
314 }
315
316 int insertIdx=0;
317 IndexItem foundItem = BinSearch(0, _index.Count, _index, search, true, true, ref insertIdx);
318
319 return foundItem;
320 }
321 }
322 }