Compute lucene-style scores for our hits.
[beagle.git] / BeagleClient / Hit.cs
blob4f4d8bd9c387419384c2b317f548d880ca5bc7aa
1 //
2 // Hit.cs
3 //
4 // Copyright (C) 2004 Novell, Inc.
5 //
7 //
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.
28 using System;
29 using System.Collections;
30 using System.Diagnostics;
31 using System.IO;
32 using System.Xml;
33 using System.Xml.Serialization;
35 using Beagle.Util;
37 namespace Beagle {
39 public class Hit: Versioned, IComparable {
41 // A URI we can use to locate the source of this match.
42 private Uri uri = null;
44 // A URI of this Hit's container element
45 private Uri parent_uri = null;
47 // File, Web, MailMessage, IMLog, etc.
48 private string type = null;
50 // If applicable, otherwise set to null.
51 private string mimeType = null;
53 // IndexUser, IndexSystem, Google, Addressbook, iFolder, etc.
54 private string source = null;
56 // This is used to hold a copy of the Queryable in the
57 // server-side copy of the Hit. It is always null
58 // on the client-side.
59 private object sourceObject = null;
60 private string source_object_name = null;
62 // High scores imply greater relevance.
63 private double score = 0.0;
65 private ArrayList properties = new ArrayList ();
66 private bool sorted = true;
68 private enum SpecialType {
69 Unknown,
70 None,
71 Invalid,
72 File,
73 Directory
76 SpecialType special = SpecialType.Unknown;
78 private string path;
79 private FileInfo fileInfo = null;
80 private DirectoryInfo directoryInfo = null;
82 //////////////////////////
84 [XmlIgnore]
85 public Uri Uri {
86 get { return uri; }
87 set { uri = value; }
90 [XmlAttribute ("Uri")]
91 public string UriAsString {
92 get {
93 return UriFu.UriToSerializableString (uri);
96 set {
97 uri = UriFu.UriStringToUri (value);
101 [XmlIgnore]
102 public Uri ParentUri {
103 get { return parent_uri; }
104 set { parent_uri = value; }
107 [XmlAttribute ("ParentUri")]
108 public string ParentUriAsString {
109 get {
110 if (parent_uri == null)
111 return null;
113 return UriFu.UriToSerializableString (parent_uri);
116 set {
117 if (value == null)
118 parent_uri = null;
119 else
120 parent_uri = UriFu.UriStringToUri (value);
124 // DEPRECATED: This is now stored as a property.
125 [XmlAttribute]
126 public string Type {
127 get { return type; }
128 set { type = value; }
131 // DEPRECATED: This is now stored as a property.
132 [XmlAttribute]
133 public string MimeType {
134 get { return mimeType; }
135 set { mimeType = value; }
138 [XmlAttribute]
139 public string Source {
140 get { return source; }
141 set { source = value; }
144 [XmlIgnore]
145 public object SourceObject {
146 get { return sourceObject; }
147 set { sourceObject = value; }
150 [XmlAttribute]
151 public string SourceObjectName {
152 get { return source_object_name; }
153 set { source_object_name = value; }
156 [XmlAttribute]
157 public double Score {
158 get { return score; }
159 set { score = value; }
162 //////////////////////////
164 private void SpecialHandling ()
166 if (special != SpecialType.Unknown)
167 return;
169 if (uri.IsFile) {
170 path = uri.LocalPath;
171 if (File.Exists (path))
172 special = SpecialType.File;
173 else if (Directory.Exists (path))
174 special = SpecialType.Directory;
175 else
176 special = SpecialType.Invalid;
179 if (special == SpecialType.Unknown)
180 special = SpecialType.None;
183 public bool IsValid {
184 get { SpecialHandling (); return special != SpecialType.Invalid; }
187 public bool IsFile {
188 get { SpecialHandling (); return special == SpecialType.File; }
191 public bool IsDirectory {
192 get { SpecialHandling (); return special == SpecialType.Directory; }
195 public bool IsFileSystem {
196 get { return IsFile || IsDirectory; }
199 public string Path {
200 get { SpecialHandling (); return path; }
203 public string PathQuoted {
204 get { return Path.Replace (" ", "\\ "); }
207 public string FileName {
208 get { return Path != null ? System.IO.Path.GetFileName (Path) : null; }
211 public string DirectoryName {
212 get { return Path != null ? System.IO.Path.GetDirectoryName (Path) : null; }
215 [XmlIgnore]
216 public FileSystemInfo FileSystemInfo {
217 get {
218 if (IsFile)
219 return (FileSystemInfo) FileInfo;
220 else if (IsDirectory)
221 return (FileSystemInfo) DirectoryInfo;
222 else
223 return null;
227 [XmlIgnore]
228 public FileInfo FileInfo {
229 get {
230 if (fileInfo == null && IsFile)
231 fileInfo = new FileInfo (Path);
232 return fileInfo;
236 [XmlIgnore]
237 public DirectoryInfo DirectoryInfo {
238 get {
239 if (directoryInfo == null && IsDirectory)
240 directoryInfo = new DirectoryInfo (Path);
241 return directoryInfo;
245 //////////////////////////
247 [XmlArray]
248 [XmlArrayItem (ElementName="Property", Type=typeof (Property))]
249 public ArrayList Properties {
250 get { return properties; }
253 public void AddProperty (Property prop)
255 if (sorted && properties.Count > 0) {
256 Property last_prop;
257 last_prop = properties [properties.Count - 1] as Property;
258 if (last_prop.CompareTo (prop) > 0) // i.e. last_prop > prop
259 sorted = false;
262 properties.Add (prop);
265 private bool FindProperty (string key, out int first, out int top)
267 // FIXME: Should use binary search on sorted property list
268 if (! sorted) {
269 properties.Sort ();
270 sorted = true;
273 first = 0;
274 top = 0;
276 while (first < properties.Count) {
277 Property prop;
278 prop = properties [first] as Property;
279 if (prop.Key == key)
280 break;
281 ++first;
284 if (first >= properties.Count)
285 return false;
287 top = first + 1;
288 while (top < properties.Count) {
289 Property prop;
290 prop = properties [top] as Property;
291 if (prop.Key != key)
292 break;
293 ++top;
296 return true;
299 public string this [string key] {
300 get {
301 int first, top;
302 if (! FindProperty (key, out first, out top))
303 return null;
305 if (top - first != 1) {
306 Logger.Log.Debug ("Accessed multi-property key with Hit's indexer.");
307 return null;
310 Property prop;
311 prop = properties [first] as Property;
312 return prop.Value;
315 set {
316 int first = 0, top = 0;
318 // If we've never heard of this property, add it.
319 if (! FindProperty (key, out first, out top)) {
320 AddProperty (Property.New (key, value));
321 return;
324 // If it has appeared once before, clobber the existing
325 // value. This emulates the previous (broken) semantics.
327 if (top - first == 1) {
328 properties [first] = Property.New (key, value);
329 return;
332 // Otherwise throw an exception (which sort of sucks,
333 // but we don't really know what to do there)
334 throw new Exception (String.Format ("Attempt to re-set multi-property '{0}' via the indexer", key));
338 public string GetFirstProperty (string key)
340 int first, top;
341 if (! FindProperty (key, out first, out top))
342 return null;
343 Property prop;
344 prop = properties [first] as Property;
345 return prop.Value;
348 public string[] GetProperties (string key)
350 int first, top;
351 if (! FindProperty (key, out first, out top))
352 return null;
354 string[] values = new string [top - first];
356 for (int i = 0; first + i < top; i++) {
357 Property prop = properties [first + i] as Property;
358 values [i] = prop.Value;
361 return values;
364 //////////////////////////
366 public override int GetHashCode ()
368 return (uri != null ? uri.ToString().GetHashCode () : 0)
369 ^ (type != null ? type.GetHashCode () : 0)
370 ^ (source != null ? source.GetHashCode () : 0);
373 //////////////////////////
375 public int CompareTo (object obj)
377 Hit otherHit = (Hit) obj;
378 // Notice that we sort by time from most to least recent
379 return DateTime.Compare (otherHit.Timestamp, this.Timestamp);