4 // Copyright (C) 2004 Novell, Inc.
8 // Permission is hereby granted, free of charge, to any person obtaining a
9 // copy of this software and associated documentation files (the "Software"),
10 // to deal in the Software without restriction, including without limitation
11 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 // and/or sell copies of the Software, and to permit persons to whom the
13 // Software is furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 // DEALINGS IN THE SOFTWARE.
29 using System
.Collections
;
30 using System
.Diagnostics
;
33 using System
.Xml
.Serialization
;
39 public class Hit
: Versioned
, IComparable
{
41 // A unique ID. id <= 0 means 'undefined'.
44 // A URI we can use to locate the source of this match.
45 private Uri uri
= null;
47 // A URI of this Hit's container element
48 private Uri parent_uri
= null;
50 // File, Web, MailMessage, IMLog, etc.
51 private string type
= null;
53 // If applicable, otherwise set to null.
54 private string mimeType
= null;
56 // IndexUser, IndexSystem, Google, Addressbook, iFolder, etc.
57 private string source
= null;
59 // This is used to hold a copy of the Queryable in the
60 // server-side copy of the Hit. It is always null
61 // on the client-side.
62 private object sourceObject
= null;
63 private string source_object_name
= null;
65 // High scores imply greater relevance.
66 private double scoreRaw
= 0.0;
67 private double scoreMultiplier
= 1.0;
69 private ArrayList properties
= new ArrayList ();
70 private bool sorted
= true;
72 private enum SpecialType
{
80 SpecialType special
= SpecialType
.Unknown
;
83 private FileInfo fileInfo
= null;
84 private DirectoryInfo directoryInfo
= null;
86 //////////////////////////
100 [XmlAttribute ("Uri")]
101 public string UriAsString
{
103 return UriFu
.UriToSerializableString (uri
);
107 uri
= UriFu
.UriStringToUri (value);
112 public Uri ParentUri
{
113 get { return parent_uri; }
114 set { parent_uri = value; }
117 [XmlAttribute ("ParentUri")]
118 public string ParentUriAsString
{
120 if (parent_uri
== null)
123 return UriFu
.UriToSerializableString (parent_uri
);
130 parent_uri
= UriFu
.UriStringToUri (value);
137 set { type = value; }
141 public string MimeType
{
142 get { return mimeType; }
143 set { mimeType = value; }
147 public string Source
{
148 get { return source; }
149 set { source = value; }
153 public object SourceObject
{
154 get { return sourceObject; }
155 set { sourceObject = value; }
159 public string SourceObjectName
{
160 get { return source_object_name; }
161 set { source_object_name = value; }
164 public double Score
{
165 get { return scoreRaw * scoreMultiplier; }
169 public double ScoreRaw
{
170 get { return scoreRaw; }
171 set { scoreRaw = value; }
175 public double ScoreMultiplier
{
176 get { return scoreMultiplier; }
178 scoreMultiplier
= value;
179 if (scoreMultiplier
< 0) {
180 Logger
.Log
.Warn ("Invalid ScoreMultiplier={0} for {1}", scoreMultiplier
, Uri
);
182 } else if (scoreMultiplier
> 1) {
183 Logger
.Log
.Warn ("Invalid ScoreMultiplier={0} for {1}", scoreMultiplier
, Uri
);
190 //////////////////////////
192 private void SpecialHandling ()
194 if (special
!= SpecialType
.Unknown
)
198 path
= uri
.LocalPath
;
199 if (File
.Exists (path
))
200 special
= SpecialType
.File
;
201 else if (Directory
.Exists (path
))
202 special
= SpecialType
.Directory
;
204 special
= SpecialType
.Invalid
;
207 if (special
== SpecialType
.Unknown
)
208 special
= SpecialType
.None
;
211 public bool IsValid
{
212 get { SpecialHandling (); return special != SpecialType.Invalid; }
216 get { SpecialHandling (); return special == SpecialType.File; }
219 public bool IsDirectory
{
220 get { SpecialHandling (); return special == SpecialType.Directory; }
223 public bool IsFileSystem
{
224 get { return IsFile || IsDirectory; }
228 get { SpecialHandling (); return path; }
231 public string PathQuoted
{
232 get { return Path.Replace (" ", "\\ "); }
235 public string FileName
{
236 get { return Path != null ? System.IO.Path.GetFileName (Path) : null; }
239 public string DirectoryName
{
240 get { return Path != null ? System.IO.Path.GetDirectoryName (Path) : null; }
244 public FileSystemInfo FileSystemInfo
{
247 return (FileSystemInfo
) FileInfo
;
248 else if (IsDirectory
)
249 return (FileSystemInfo
) DirectoryInfo
;
256 public FileInfo FileInfo
{
258 if (fileInfo
== null && IsFile
)
259 fileInfo
= new FileInfo (Path
);
265 public DirectoryInfo DirectoryInfo
{
267 if (directoryInfo
== null && IsDirectory
)
268 directoryInfo
= new DirectoryInfo (Path
);
269 return directoryInfo
;
273 //////////////////////////
276 [XmlArrayItem (ElementName
="Property", Type
=typeof (Property
))]
277 public ArrayList Properties
{
278 get { return properties; }
281 public void AddProperty (Property prop
)
283 if (sorted
&& properties
.Count
> 0) {
285 last_prop
= properties
[properties
.Count
- 1] as Property
;
286 if (last_prop
.CompareTo (prop
) > 0) // i.e. last_prop > prop
290 properties
.Add (prop
);
293 private bool FindProperty (string key
, out int first
, out int top
)
295 // FIXME: Should use binary search on sorted property list
304 while (first
< properties
.Count
) {
306 prop
= properties
[first
] as Property
;
312 if (first
>= properties
.Count
)
316 while (top
< properties
.Count
) {
318 prop
= properties
[top
] as Property
;
327 public string this [string key
] {
330 if (! FindProperty (key
, out first
, out top
))
333 if (top
- first
!= 1) {
334 Logger
.Log
.Debug ("Accessed multi-property key with Hit's indexer.");
339 prop
= properties
[first
] as Property
;
344 int first
= 0, top
= 0;
346 // If we've never heard of this property, add it.
347 if (! FindProperty (key
, out first
, out top
)) {
348 AddProperty (Property
.New (key
, value));
352 // If it has appeared once before, clobber the existing
353 // value. This emulates the previous (broken) semantics.
355 if (top
- first
== 1) {
356 properties
[first
] = Property
.New (key
, value);
360 // Otherwise throw an exception (which sort of sucks,
361 // but we don't really know what to do there)
362 throw new Exception (String
.Format ("Attempt to re-set multi-property '{0}' via the indexer", key
));
366 public string[] GetProperties (string key
)
369 if (! FindProperty (key
, out first
, out top
))
372 string[] values
= new string [top
- first
];
374 for (int i
= 0; first
+ i
< top
; i
++) {
375 Property prop
= properties
[first
+ i
] as Property
;
376 values
[i
] = prop
.Value
;
382 //////////////////////////
384 public override int GetHashCode ()
386 return (uri
!= null ? uri
.ToString().GetHashCode () : 0)
387 ^
(type
!= null ? type
.GetHashCode () : 0)
388 ^
(source
!= null ? source
.GetHashCode () : 0);
391 //////////////////////////
393 public int CompareTo (object obj
)
395 Hit otherHit
= (Hit
) obj
;
396 // Notice that we sort from high to low.
397 return otherHit
.Score
.CompareTo (this.Score
);