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 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;
61 // High scores imply greater relevance.
62 private double score
= 0.0;
64 private ArrayList properties
= new ArrayList ();
65 private bool sorted
= true;
67 private enum SpecialType
{
75 SpecialType special
= SpecialType
.Unknown
;
78 private FileInfo fileInfo
= null;
79 private DirectoryInfo directoryInfo
= null;
81 //////////////////////////
89 [XmlAttribute ("Uri")]
90 public string UriAsString
{
92 return UriFu
.UriToSerializableString (uri
);
96 uri
= UriFu
.UriStringToUri (value);
101 public Uri ParentUri
{
102 get { return parent_uri; }
103 set { parent_uri = value; }
106 [XmlAttribute ("ParentUri")]
107 public string ParentUriAsString
{
109 if (parent_uri
== null)
112 return UriFu
.UriToSerializableString (parent_uri
);
119 parent_uri
= UriFu
.UriStringToUri (value);
123 // DEPRECATED: This is now stored as a property.
127 set { type = value; }
130 // DEPRECATED: This is now stored as a property.
132 public string MimeType
{
133 get { return mimeType; }
134 set { mimeType = value; }
138 public string Source
{
139 get { return source; }
140 set { source = value; }
144 public object SourceObject
{
145 get { return sourceObject; }
146 set { sourceObject = value; }
150 public double Score
{
151 get { return score; }
152 set { score = value; }
155 //////////////////////////
157 private void SpecialHandling ()
159 if (special
!= SpecialType
.Unknown
)
163 path
= uri
.LocalPath
;
164 if (File
.Exists (path
))
165 special
= SpecialType
.File
;
166 else if (Directory
.Exists (path
))
167 special
= SpecialType
.Directory
;
169 special
= SpecialType
.Invalid
;
172 if (special
== SpecialType
.Unknown
)
173 special
= SpecialType
.None
;
176 public bool IsValid
{
177 get { SpecialHandling (); return special != SpecialType.Invalid; }
181 get { SpecialHandling (); return special == SpecialType.File; }
184 public bool IsDirectory
{
185 get { SpecialHandling (); return special == SpecialType.Directory; }
188 public bool IsFileSystem
{
189 get { return IsFile || IsDirectory; }
193 get { SpecialHandling (); return path; }
196 public string PathQuoted
{
197 get { return Path.Replace (" ", "\\ "); }
200 public string FileName
{
201 get { return Path != null ? System.IO.Path.GetFileName (Path) : null; }
204 public string DirectoryName
{
205 get { return Path != null ? System.IO.Path.GetDirectoryName (Path) : null; }
209 public FileSystemInfo FileSystemInfo
{
212 return (FileSystemInfo
) FileInfo
;
213 else if (IsDirectory
)
214 return (FileSystemInfo
) DirectoryInfo
;
221 public FileInfo FileInfo
{
223 if (fileInfo
== null && IsFile
)
224 fileInfo
= new FileInfo (Path
);
230 public DirectoryInfo DirectoryInfo
{
232 if (directoryInfo
== null && IsDirectory
)
233 directoryInfo
= new DirectoryInfo (Path
);
234 return directoryInfo
;
238 //////////////////////////
241 [XmlArrayItem (ElementName
="Property", Type
=typeof (Property
))]
242 public ArrayList Properties
{
243 get { return properties; }
246 public void AddProperty (Property prop
)
248 if (sorted
&& properties
.Count
> 0) {
250 last_prop
= properties
[properties
.Count
- 1] as Property
;
251 if (last_prop
.CompareTo (prop
) > 0) // i.e. last_prop > prop
255 properties
.Add (prop
);
258 private bool FindProperty (string key
, out int first
, out int top
)
267 int range
= properties
.Count
- 1;
270 // O(log n + |range|)-time algorithm for 1-d range query
273 int mid
= first
+ (range
/2);
275 prop
= properties
[mid
] as Property
;
276 // Properties are sorted first by Key, then by Value
277 // We only need to compare the key of the middle element to the key in parameter
278 if (String
.Compare (key
, prop
.Key
) > 0) {
279 // minimum item in right subtree is smaller
289 // - either the previous item in the BST
290 // - or the next to the previous item in the BST
291 prop
= (Property
) properties
[first
];
294 if (first
>= properties
.Count
)
296 prop
= (Property
) properties
[first
];
301 // Since range will be small, do a linear scan from here.
302 // We could do another BST traversal at the cost of O(log-n),
303 // but its not worth it.
304 while (top
< properties
.Count
) {
305 prop
= properties
[top
] as Property
;
314 public string this [string key
] {
317 if (! FindProperty (key
, out first
, out top
))
320 if (top
- first
!= 1) {
321 Logger
.Log
.Warn ("Accessed multi-property key with Hit's indexer.");
326 prop
= properties
[first
] as Property
;
331 int first
= 0, top
= 0;
333 // If we've never heard of this property, add it.
334 if (! FindProperty (key
, out first
, out top
)) {
335 AddProperty (Property
.New (key
, value));
339 // If it has appeared once before, clobber the existing
340 // value. This emulates the previous (broken) semantics.
342 if (top
- first
== 1) {
343 properties
[first
] = Property
.New (key
, value);
347 // Otherwise throw an exception (which sort of sucks,
348 // but we don't really know what to do there)
349 throw new Exception (String
.Format ("Attempt to re-set multi-property '{0}' via the indexer", key
));
353 public string GetFirstProperty (string key
)
356 if (! FindProperty (key
, out first
, out top
))
359 prop
= properties
[first
] as Property
;
363 public string[] GetProperties (string key
)
366 if (! FindProperty (key
, out first
, out top
))
369 string[] values
= new string [top
- first
];
371 for (int i
= 0; first
+ i
< top
; i
++) {
372 Property prop
= properties
[first
+ i
] as Property
;
373 values
[i
] = prop
.Value
;
379 //////////////////////////
381 public override int GetHashCode ()
383 return (uri
!= null ? uri
.ToString().GetHashCode () : 0)
384 ^
(type
!= null ? type
.GetHashCode () : 0)
385 ^
(source
!= null ? source
.GetHashCode () : 0);
388 //////////////////////////
390 public int CompareTo (object obj
)
392 Hit otherHit
= (Hit
) obj
;
393 // Notice that we sort by time from most to least recent
394 return DateTime
.Compare (otherHit
.Timestamp
, this.Timestamp
);