Merge "[Context] Add related feature & Add Context dll to wearable"
[platform/core/csapi/tizenfx.git] / src / Tizen.Pims.Contacts / Tizen.Pims.Contacts / ContactsDatabase.cs
1 /*
2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3 *
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 using System;
18 using System.Collections.Generic;
19 using System.Diagnostics.CodeAnalysis;
20 using System.Runtime.InteropServices;
21
22 namespace Tizen.Pims.Contacts
23 {
24
25     /// <summary>
26     /// ContactsDatabase provides methods to manage contacts information from/to the database.
27     /// </summary>
28     /// <remarks>
29     /// This class allows user to access/create/update db operations for contacts information.
30     /// </remarks>
31     public class ContactsDatabase
32     {
33         private Object thisLock = new Object();
34         private Interop.Database.ContactsDBStatusChangedCallback _contactsDBStatusChangedCallback;
35         private EventHandler<DBStatusChangedEventArgs> _dbStatusChanged;
36         private Dictionary<string, EventHandler<DBChangedEventArgs>> _eventHandlerMap = new Dictionary<string, EventHandler<DBChangedEventArgs>>();
37         private Dictionary<string, Interop.Database.ContactsDBChangedCallback> _callbackMap = new Dictionary<string, Interop.Database.ContactsDBChangedCallback>();
38
39         internal ContactsDatabase()
40         {
41             /*To be created in ContactsManager only.*/
42         }
43
44         /// <summary>
45         /// Enumeration for contacts database status.
46         /// </summary>
47         public enum DBStatus
48         {
49             /// <summary>
50             /// Normal
51             /// </summary>
52             Normal,
53             /// <summary>
54             /// Changing collation.
55             /// </summary>
56             ChangingCollation
57         }
58
59         /// <summary>
60         /// Enumeration for Contacts search range.
61         /// </summary>
62         [Flags]
63         public enum SearchRanges
64         {
65             /// <summary>
66             /// None
67             /// </summary>
68             None = 0,
69             /// <summary>
70             /// Search record from name
71             /// </summary>
72             Name = 0x00000001,
73             /// <summary>
74             /// Search record from number
75             /// </summary>
76             Number = 0x00000002,
77             /// <summary>
78             /// Search record from data
79             /// </summary>
80             Data = 0x00000004,
81             /// <summary>
82             /// Search record from email. Now, support only PersonEmail view
83             /// </summary>
84             Email = 0x00000008,
85         }
86
87         /// <summary>
88         /// Occurs when contacts database status is changed.
89         /// </summary>
90         public event EventHandler<DBStatusChangedEventArgs> DBStatusChanged
91         {
92             add
93             {
94                 lock (thisLock)
95                 {
96                     if (_contactsDBStatusChangedCallback == null)
97                     {
98                         _contactsDBStatusChangedCallback = (DBStatus status, IntPtr userData) =>
99                         {
100                             DBStatusChangedEventArgs args = new DBStatusChangedEventArgs(status);
101                             _dbStatusChanged?.Invoke(this, args);
102                         };
103                     }
104
105                     if (_dbStatusChanged == null)
106                     {
107                         int error = Interop.Database.AddStatusChangedCb(_contactsDBStatusChangedCallback, IntPtr.Zero);
108                         if ((int)ContactsError.None != error)
109                         {
110                             Log.Error(Globals.LogTag, "Add StatusChanged Failed with error " + error);
111                         }
112                     }
113
114                     _dbStatusChanged += value;
115                 }
116
117             }
118
119             remove
120             {
121                 lock (thisLock)
122                 {
123                     _dbStatusChanged -= value;
124
125                     if (_dbStatusChanged == null)
126                     {
127                         int error = Interop.Database.RemoveStatusChangedCb(_contactsDBStatusChangedCallback, IntPtr.Zero);
128                         if ((int)ContactsError.None != error)
129                         {
130                             Log.Error(Globals.LogTag, "Remove StatusChanged Failed with error " + error);
131                         }
132                     }
133                 }
134             }
135
136         }
137
138         /// <summary>
139         /// The current contacts database version.
140         /// </summary>
141         /// <value>The current contacts database version.</value>
142         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
143         public int Version
144         {
145             get
146             {
147                 int version = -1;
148                 int error = Interop.Database.GetVersion(out version);
149                 if ((int)ContactsError.None != error)
150                 {
151                     Log.Error(Globals.LogTag, "Version Failed with error " + error);
152                 }
153                 return version;
154             }
155         }
156
157         /// <summary>
158         /// The last successful changed contacts database version on the current connection.
159         /// </summary>
160         /// <value>The last successful changed contacts database version on the current connection.</value>
161         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
162         public int LastChangeVersion
163         {
164             get
165             {
166                 int version = -1;
167                 int error = Interop.Database.GetLastChangeVersion(out version);
168                 if ((int)ContactsError.None != error)
169                 {
170                     Log.Error(Globals.LogTag, "LastChangeVersion Failed with error " + error);
171                 }
172                 return version;
173             }
174         }
175
176         /// <summary>
177         /// The contacts database status.
178         /// </summary>
179         /// <value>The contacts database status.</value>
180         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
181         public DBStatus Status
182         {
183             get
184             {
185                 DBStatus status = DBStatus.Normal;
186                 int error = Interop.Database.GetStatus(out status);
187                 if ((int)ContactsError.None != error)
188                 {
189                     Log.Error(Globals.LogTag, "GetStatus Failed with error " + error);
190                 }
191                 return status;
192             }
193         }
194
195         /// <summary>
196         /// Inserts a record into the contacts database.
197         /// </summary>
198         /// <param name="record">The record to insert</param>
199         /// <returns>The ID of inserted record</returns>
200         /// <privilege>http://tizen.org/privilege/contact.write</privilege>
201         /// <privilege>http://tizen.org/privilege/callhistory.write</privilege>
202         /// <exception cref="InvalidOperationException">Thrown when method failed due to invalid operation</exception>
203         /// <exception cref="NotSupportedException">Thrown when an invoked method is not supported</exception>
204         /// <exception cref="ArgumentException">Thrown when one of the arguments provided to a method is not valid</exception>
205         /// <exception cref="OutOfMemoryException">Thrown when failed due to out of memory</exception>
206         /// <exception cref="UnauthorizedAccessException">Thrown when application does not have proper privileges</exception>
207         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
208         public int Insert(ContactsRecord record)
209         {
210             int id = -1;
211             int error = Interop.Database.Insert(record._recordHandle, out id);
212             if ((int)ContactsError.None != error)
213             {
214                 Log.Error(Globals.LogTag, "Insert Failed with error " + error);
215                 throw ContactsErrorFactory.CheckAndCreateException(error);
216             }
217             return id;
218         }
219
220         /// <summary>
221         /// Inserts multiple records into the contacts database as a batch operation.
222         /// </summary>
223         /// <param name="list">The record list</param>
224         /// <returns>The inserted record ID array</returns>
225         /// <privilege>http://tizen.org/privilege/contact.write</privilege>
226         /// <privilege>http://tizen.org/privilege/callhistory.write</privilege>
227         /// <exception cref="InvalidOperationException">Thrown when method failed due to invalid operation</exception>
228         /// <exception cref="NotSupportedException">Thrown when an invoked method is not supported</exception>
229         /// <exception cref="ArgumentException">Thrown when one of the arguments provided to a method is not valid</exception>
230         /// <exception cref="OutOfMemoryException">Thrown when failed due to out of memory</exception>
231         /// <exception cref="UnauthorizedAccessException">Thrown when application does not have proper privileges</exception>
232         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
233         public int[] Insert(ContactsList list)
234         {
235             IntPtr ids;
236             int count;
237             int error = Interop.Database.InsertRecords(list._listHandle, out ids, out count);
238             if ((int)ContactsError.None != error)
239             {
240                 Log.Error(Globals.LogTag, "Insert Failed with error " + error);
241                 throw ContactsErrorFactory.CheckAndCreateException(error);
242             }
243
244             int[] idArr = new int[count];
245             Marshal.Copy(ids, idArr, 0, count);
246
247             return idArr;
248         }
249
250         /// <summary>
251         /// Gets a record from the contacts database.
252         /// </summary>
253         /// <param name="viewUri">The view URI of a record</param>
254         /// <param name="recordId">The record ID</param>
255         /// <returns>The record associated with the record ID</returns>
256         /// <privilege>http://tizen.org/privilege/contact.read</privilege>
257         /// <privilege>http://tizen.org/privilege/callhistory.read</privilege>
258         /// <exception cref="InvalidOperationException">Thrown when method failed due to invalid operation</exception>
259         /// <exception cref="NotSupportedException">Thrown when an invoked method is not supported</exception>
260         /// <exception cref="ArgumentException">Thrown when one of the arguments provided to a method is not valid</exception>
261         /// <exception cref="OutOfMemoryException">Thrown when failed due to out of memory</exception>
262         /// <exception cref="UnauthorizedAccessException">Thrown when application does not have proper privileges</exception>
263         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
264         [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings")]
265         public ContactsRecord Get(string viewUri, int recordId)
266         {
267             IntPtr handle;
268             int error = Interop.Database.Get(viewUri, recordId, out handle);
269             if ((int)ContactsError.None != error)
270             {
271                 Log.Error(Globals.LogTag, "Get Failed with error " + error);
272                 throw ContactsErrorFactory.CheckAndCreateException(error);
273             }
274             return new ContactsRecord(handle);
275         }
276
277         /// <summary>
278         /// Updates a record in the contacts database.
279         /// </summary>
280         /// <param name="record">The record to update</param>
281         /// <privilege>http://tizen.org/privilege/contact.write</privilege>
282         /// <privilege>http://tizen.org/privilege/callhistory.write</privilege>
283         /// <exception cref="InvalidOperationException">Thrown when method failed due to invalid operation</exception>
284         /// <exception cref="NotSupportedException">Thrown when an invoked method is not supported</exception>
285         /// <exception cref="ArgumentException">Thrown when one of the arguments provided to a method is not valid</exception>
286         /// <exception cref="OutOfMemoryException">Thrown when failed due to out of memory</exception>
287         /// <exception cref="UnauthorizedAccessException">Thrown when application does not have proper privileges</exception>
288         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
289         public void Update(ContactsRecord record)
290         {
291             int error = Interop.Database.Update(record._recordHandle);
292             if ((int)ContactsError.None != error)
293             {
294                 Log.Error(Globals.LogTag, "Update Failed with error " + error);
295                 throw ContactsErrorFactory.CheckAndCreateException(error);
296             }
297         }
298
299         /// <summary>
300         /// Updates multiple records in the contacts database as a batch operation.
301         /// </summary>
302         /// <param name="list">The record list</param>
303         /// <privilege>http://tizen.org/privilege/contact.write</privilege>
304         /// <privilege>http://tizen.org/privilege/callhistory.write</privilege>
305         /// <exception cref="InvalidOperationException">Thrown when method failed due to invalid operation</exception>
306         /// <exception cref="NotSupportedException">Thrown when an invoked method is not supported</exception>
307         /// <exception cref="ArgumentException">Thrown when one of the arguments provided to a method is not valid</exception>
308         /// <exception cref="OutOfMemoryException">Thrown when failed due to out of memory</exception>
309         /// <exception cref="UnauthorizedAccessException">Thrown when application does not have proper privileges</exception>
310         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
311         public void Update(ContactsList list)
312         {
313             int error = Interop.Database.UpdateRecords(list._listHandle);
314             if ((int)ContactsError.None != error)
315             {
316                 Log.Error(Globals.LogTag, "Update Failed with error " + error);
317                 throw ContactsErrorFactory.CheckAndCreateException(error);
318             }
319         }
320
321         /// <summary>
322         /// Deletes a record from the contacts database with related child records.
323         /// </summary>
324         /// <param name="viewUri">The view URI of a record</param>
325         /// <param name="recordId">The record ID to delete</param>
326         /// <privilege>http://tizen.org/privilege/contact.write</privilege>
327         /// <privilege>http://tizen.org/privilege/callhistory.write</privilege>
328         /// <exception cref="InvalidOperationException">Thrown when method failed due to invalid operation</exception>
329         /// <exception cref="NotSupportedException">Thrown when an invoked method is not supported</exception>
330         /// <exception cref="ArgumentException">Thrown when one of the arguments provided to a method is not valid</exception>
331         /// <exception cref="OutOfMemoryException">Thrown when failed due to out of memory</exception>
332         /// <exception cref="UnauthorizedAccessException">Thrown when application does not have proper privileges</exception>
333         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
334         [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings")]
335         public void Delete(string viewUri, int recordId)
336         {
337             int error = Interop.Database.Delete(viewUri, recordId);
338             if ((int)ContactsError.None != error)
339             {
340                 Log.Error(Globals.LogTag, "Delete Failed with error " + error);
341                 throw ContactsErrorFactory.CheckAndCreateException(error);
342             }
343         }
344
345         /// <summary>
346         /// Deletes multiple records with related child records from the contacts database as a batch operation.
347         /// </summary>
348         /// <param name="viewUri">The view URI of the records to delete</param>
349         /// <param name="idArray">The record IDs to delete</param>
350         /// <privilege>http://tizen.org/privilege/contact.write</privilege>
351         /// <privilege>http://tizen.org/privilege/callhistory.write</privilege>
352         /// <exception cref="InvalidOperationException">Thrown when method failed due to invalid operation</exception>
353         /// <exception cref="NotSupportedException">Thrown when an invoked method is not supported</exception>
354         /// <exception cref="ArgumentException">Thrown when one of the arguments provided to a method is not valid</exception>
355         /// <exception cref="OutOfMemoryException">Thrown when failed due to out of memory</exception>
356         /// <exception cref="UnauthorizedAccessException">Thrown when application does not have proper privileges</exception>
357         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
358         [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings")]
359         public void Delete(string viewUri, int[] idArray)
360         {
361             int error = Interop.Database.DeleteRecords(viewUri, idArray, idArray.Length);
362             if ((int)ContactsError.None != error)
363             {
364                 Log.Error(Globals.LogTag, "Delete Failed with error " + error);
365                 throw ContactsErrorFactory.CheckAndCreateException(error);
366             }
367         }
368
369         /// <summary>
370         /// Replaces a record in the contacts database.
371         /// </summary>
372         /// <param name="record">The record to replace</param>
373         /// <param name="recordId">the record ID to be replaced</param>
374         /// <privilege>http://tizen.org/privilege/contact.write</privilege>
375         /// <privilege>http://tizen.org/privilege/callhistory.write</privilege>
376         /// <exception cref="InvalidOperationException">Thrown when method failed due to invalid operation</exception>
377         /// <exception cref="NotSupportedException">Thrown when an invoked method is not supported</exception>
378         /// <exception cref="ArgumentException">Thrown when one of the arguments provided to a method is not valid</exception>
379         /// <exception cref="OutOfMemoryException">Thrown when failed due to out of memory</exception>
380         /// <exception cref="UnauthorizedAccessException">Thrown when application does not have proper privileges</exception>
381         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
382         public void Replace(ContactsRecord record, int recordId)
383         {
384             int error = Interop.Database.Replace(record._recordHandle, recordId);
385             if ((int)ContactsError.None != error)
386             {
387                 Log.Error(Globals.LogTag, "Replace Failed with error " + error);
388                 throw ContactsErrorFactory.CheckAndCreateException(error);
389             }
390         }
391
392         /// <summary>
393         /// Replaces multiple records in the contacts database as a batch operation.
394         /// </summary>
395         /// <param name="list">The record list to replace</param>
396         /// <param name="idArray">The record IDs to be replaced</param>
397         /// <privilege>http://tizen.org/privilege/contact.write</privilege>
398         /// <privilege>http://tizen.org/privilege/callhistory.write</privilege>
399         /// <exception cref="InvalidOperationException">Thrown when method failed due to invalid operation</exception>
400         /// <exception cref="NotSupportedException">Thrown when an invoked method is not supported</exception>
401         /// <exception cref="ArgumentException">Thrown when one of the arguments provided to a method is not valid</exception>
402         /// <exception cref="OutOfMemoryException">Thrown when failed due to out of memory</exception>
403         /// <exception cref="UnauthorizedAccessException">Thrown when application does not have proper privileges</exception>
404         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
405         public void Replace(ContactsList list, int[] idArray)
406         {
407             int error = Interop.Database.ReplaceRecords(list._listHandle, idArray, idArray.Length);
408             if ((int)ContactsError.None != error)
409             {
410                 Log.Error(Globals.LogTag, "Replace Failed with error " + error);
411                 throw ContactsErrorFactory.CheckAndCreateException(error);
412             }
413         }
414
415         /// <summary>
416         /// Retrieves all records as a list.
417         /// </summary>
418         /// <param name="viewUri">The view URI to get records</param>
419         /// <param name="offset">The index from which results</param>
420         /// <param name="limit">The number to limit results(value 0 is used for all records)</param>
421         /// <returns>
422         /// The record list
423         /// </returns>
424         /// <privilege>http://tizen.org/privilege/contact.read</privilege>
425         /// <privilege>http://tizen.org/privilege/callhistory.read</privilege>
426         /// <exception cref="InvalidOperationException">Thrown when method failed due to invalid operation</exception>
427         /// <exception cref="NotSupportedException">Thrown when an invoked method is not supported</exception>
428         /// <exception cref="ArgumentException">Thrown when one of the arguments provided to a method is not valid</exception>
429         /// <exception cref="OutOfMemoryException">Thrown when failed due to out of memory</exception>
430         /// <exception cref="UnauthorizedAccessException">Thrown when application does not have proper privileges</exception>
431         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
432         [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings")]
433         public ContactsList GetAll(string viewUri, int offset, int limit)
434         {
435             IntPtr handle;
436             int error = Interop.Database.GetRecords(viewUri, offset, limit, out handle);
437             if ((int)ContactsError.None != error)
438             {
439                 Log.Error(Globals.LogTag, "GetAll Failed with error " + error);
440                 throw ContactsErrorFactory.CheckAndCreateException(error);
441             }
442             return new ContactsList(handle);
443         }
444
445         /// <summary>
446         /// Retrieves records using a query.
447         /// </summary>
448         /// <param name="query">The query to filter the results</param>
449         /// <param name="offset">The index from which to get results</param>
450         /// <param name="limit">The number to limit results(value 0 is used for get all records)</param>
451         /// <returns>
452         /// The record list
453         /// </returns>
454         /// <privilege>http://tizen.org/privilege/contact.read</privilege>
455         /// <privilege>http://tizen.org/privilege/callhistory.read</privilege>
456         /// <exception cref="InvalidOperationException">Thrown when method failed due to invalid operation</exception>
457         /// <exception cref="NotSupportedException">Thrown when an invoked method is not supported</exception>
458         /// <exception cref="ArgumentException">Thrown when one of the arguments provided to a method is not valid</exception>
459         /// <exception cref="OutOfMemoryException">Thrown when failed due to out of memory</exception>
460         /// <exception cref="UnauthorizedAccessException">Thrown when application does not have proper privileges</exception>
461         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
462         public ContactsList GetRecordsWithQuery(ContactsQuery query, int offset, int limit)
463         {
464             IntPtr handle;
465             int error = Interop.Database.GetRecords(query._queryHandle, offset, limit, out handle);
466             if ((int)ContactsError.None != error)
467             {
468                 Log.Error(Globals.LogTag, "GetAllWithQuery Failed with error " + error);
469                 throw ContactsErrorFactory.CheckAndCreateException(error);
470             }
471             return new ContactsList(handle);
472         }
473
474         /// <summary>
475         /// Retrieves records changes since the given database version.
476         /// </summary>
477         /// <param name="viewUri">The view URI to get records</param>
478         /// <param name="addressBookId">The address book ID to filter</param>
479         /// <param name="contactsDBVersion">The contacts database version</param>
480         /// <param name="currentDBVersion">The current contacts database version</param>
481         /// <returns>
482         /// The record list
483         /// </returns>
484         /// <privilege>http://tizen.org/privilege/contact.read</privilege>
485         /// <exception cref="InvalidOperationException">Thrown when method failed due to invalid operation</exception>
486         /// <exception cref="NotSupportedException">Thrown when an invoked method is not supported</exception>
487         /// <exception cref="ArgumentException">Thrown when one of the arguments provided to a method is not valid</exception>
488         /// <exception cref="OutOfMemoryException">Thrown when failed due to out of memory</exception>
489         /// <exception cref="UnauthorizedAccessException">Thrown when application does not have proper privileges</exception>
490         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
491         [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings")]
492         public ContactsList GetChangesByVersion(string viewUri, int addressBookId, int contactsDBVersion, out int currentDBVersion)
493         {
494             IntPtr recordList;
495             int error = Interop.Database.GetChangesByVersion(viewUri, addressBookId, contactsDBVersion, out recordList,out currentDBVersion);
496             if ((int)ContactsError.None != error)
497             {
498                 Log.Error(Globals.LogTag, "GetChangesByVersion Failed with error " + error);
499                 throw ContactsErrorFactory.CheckAndCreateException(error);
500             }
501             return new ContactsList(recordList);
502         }
503
504         /// <summary>
505         /// Finds records based on a given keyword.
506         /// </summary>
507         /// <remarks>
508         /// This API works only for the Views below.
509         /// Person, PersonContact, PersonGroupRelation, PersonGroupAssigned and PersonGroupNotAssigned.
510         /// </remarks>
511         /// <param name="viewUri">The view URI to find records</param>
512         /// <param name="keyword">The keyword</param>
513         /// <param name="offset">The index from which to get results</param>
514         /// <param name="limit">The number to limit results(value 0 is used for get all records)</param>
515         /// <returns>The record list</returns>
516         /// <privilege>http://tizen.org/privilege/contact.read</privilege>
517         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
518         [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings")]
519         public ContactsList Search(string viewUri, string keyword, int offset, int limit)
520         {
521             IntPtr recordList;
522             int error = Interop.Database.Search(viewUri, keyword, offset, limit, out recordList);
523             if ((int)ContactsError.None != error)
524             {
525                 Log.Error(Globals.LogTag, "Search Failed with error " + error);
526                 throw ContactsErrorFactory.CheckAndCreateException(error);
527             }
528             return new ContactsList(recordList);
529         }
530
531         /// <summary>
532         /// Finds records based on given query and keyword.
533         /// </summary>
534         /// <remarks>
535         /// This API works only for the Views below.
536         /// Person, PersonContact, PersonGroupRelation, PersonGroupAssigned and PersonGroupNotAssigned.
537         /// </remarks>
538         /// <param name="query">The query to filter</param>
539         /// <param name="keyword">The keyword</param>
540         /// <param name="offset">The index from which to get results</param>
541         /// <param name="limit">The number to limit results(value 0 used for get all records)</param>
542         /// <returns>The record list</returns>
543         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
544         public ContactsList Search(ContactsQuery query, string keyword, int offset, int limit)
545         {
546             IntPtr recordList;
547             int error = Interop.Database.Search(query._queryHandle, keyword, offset, limit, out recordList);
548             if ((int)ContactsError.None != error)
549             {
550                 Log.Error(Globals.LogTag, "Search Failed with error " + error);
551                 throw ContactsErrorFactory.CheckAndCreateException(error);
552             }
553             return new ContactsList(recordList);
554         }
555
556         /// <summary>
557         /// Finds records based on a keyword and range.
558         /// </summary>
559         /// <remarks>
560         /// This API works only for the Views below.
561         /// Person, PersonContact, PersonGroupRelation, PersonGroupAssigned, PersonGroupNotAssigned, PersonNumber and PersonEmail
562         /// </remarks>
563         /// <param name="viewUri">The view URI</param>
564         /// <param name="keyword">The keyword</param>
565         /// <param name="offset">The index from which to get results</param>
566         /// <param name="limit">The number to limit results(value 0 is used for get all records)</param>
567         /// <param name="range">The search range, it should be a element of SearchRange or bitwise OR operation of them</param>
568         /// <returns>The record list</returns>
569         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
570         [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings")]
571         public ContactsList Search(string viewUri, string keyword, int offset, int limit, int range)
572         {
573             IntPtr recordList;
574             int error = Interop.Database.Search(viewUri, keyword, offset, limit, range, out recordList);
575             if ((int)ContactsError.None != error)
576             {
577                 Log.Error(Globals.LogTag, "Search Failed with error " + error);
578                 throw ContactsErrorFactory.CheckAndCreateException(error);
579             }
580             return new ContactsList(recordList);
581         }
582
583         /// <summary>
584         /// Finds records based on a given keyword for snippet
585         /// </summary>
586         /// <remarks>
587         /// This API works only for the Views below.
588         /// Person, PersonContact, PersonGroupRelation, PersonGroupAssigned and PersonGroupNotAssigned.
589         /// Because start match and end match are needed to be composed with keyword, this API performance is lower than Search(string viewUri, string keyword, int offset, int limit).
590         /// </remarks>
591         /// <param name="viewUri">The view URI to find records</param>
592         /// <param name="keyword">The keyword</param>
593         /// <param name="offset">The index from which to get results</param>
594         /// <param name="limit">The number to limit results(value 0 used for get all records)</param>
595         /// <param name="startMatch">The text which is inserted into the fragment before the keyword(If NULL, default is "[")</param>
596         /// <param name="endMatch">The text which is inserted into the fragment after the keyword(If NULL, default is "]")</param>
597         /// <param name="tokenNumber">The one side extra number of tokens near keyword(If negative value, full sentence is printed. e.g. if token number is 3 with 'abc' keyword, "my name is [abc]de and my home")</param>
598         /// <returns>The record list</returns>
599         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
600         [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings")]
601         public ContactsList Search(string viewUri, string keyword, int offset, int limit, string startMatch, string endMatch, int tokenNumber)
602         {
603             IntPtr recordList;
604             int error = Interop.Database.Search(viewUri, keyword, offset, limit, startMatch, endMatch, tokenNumber, out recordList);
605             if ((int)ContactsError.None != error)
606             {
607                 Log.Error(Globals.LogTag, "Search Failed with error " + error);
608                 throw ContactsErrorFactory.CheckAndCreateException(error);
609             }
610             return new ContactsList(recordList);
611         }
612
613         /// <summary>
614         /// Finds records based on given query and keyword for snippet.
615         /// </summary>
616         /// <remarks>
617         /// This API works only for the Views below.
618         /// Person, PersonContact, PersonGroupRelation, PersonGroupAssigned and PersonGroupNotAssigned.
619         /// Because start match and end match are needed to be composed with keyword, this API performance is lower than Search(ContactsQuery query, string keyword, int offset, int limit).
620         /// </remarks>
621         /// <param name="query">The query to filter</param>
622         /// <param name="keyword">The keyword</param>
623         /// <param name="offset">The index from which to get results</param>
624         /// <param name="limit">The number to limit results(value 0 used for get all records)</param>
625         /// <param name="startMatch">The text which is inserted into the fragment before the keyword(If NULL, default is "[")</param>
626         /// <param name="endMatch">The text which is inserted into the fragment after the keyword(If NULL, default is "]")</param>
627         /// <param name="tokenNumber">The one side extra number of tokens near keyword(If negative value, full sentence is printed. e.g. if token number is 3 with 'abc' keyword, "my name is [abc]de and my home")</param>
628         /// <returns>The record list</returns>
629         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
630         public ContactsList Search(ContactsQuery query, string keyword, int offset, int limit, string startMatch, string endMatch, int tokenNumber)
631         {
632             IntPtr recordList;
633             int error = Interop.Database.Search(query._queryHandle, keyword, offset, limit, startMatch, endMatch, tokenNumber, out recordList);
634             if ((int)ContactsError.None != error)
635             {
636                 Log.Error(Globals.LogTag, "Search Failed with error " + error);
637                 throw ContactsErrorFactory.CheckAndCreateException(error);
638             }
639             return new ContactsList(recordList);
640         }
641
642         /// <summary>
643         /// Finds records based on a keyword and range for snippet.
644         /// </summary>
645         /// <remarks>
646         /// This API works only for the Views below.
647         /// Person, PersonContact, PersonGroupRelation, PersonGroupAssigned, PersonGroupNotAssigned, PersonNumber and PersonEmail
648         /// Because start match and end match are needed to be composed with keyword, this API performance is lower than Search(string viewUri, string keyword, int offset, int limit, int range).
649         /// </remarks>
650         /// <param name="viewUri">The view URI</param>
651         /// <param name="keyword">The keyword</param>
652         /// <param name="offset">The index from which to get results</param>
653         /// <param name="limit">The number to limit results(value 0 is used for get all records)</param>
654         /// <param name="range">The search range, it should be a element of SearchRange or bitwise OR operation of them</param>
655         /// <param name="startMatch">The text which is inserted into the fragment before the keyword(If NULL, default is "[")</param>
656         /// <param name="endMatch">The text which is inserted into the fragment after the keyword(If NULL, default is "]")</param>
657         /// <param name="tokenNumber">The one side extra number of tokens near keyword(If negative value, full sentence is printed. e.g. if token number is 3 with 'abc' keyword, "my name is [abc]de and my home")</param>
658         /// <returns>The record list</returns>
659         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
660         [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings")]
661         public ContactsList Search(string viewUri, string keyword, int offset, int limit, int range, string startMatch, string endMatch, int tokenNumber)
662         {
663             IntPtr recordList;
664             int error = Interop.Database.Search(viewUri, keyword, offset, limit, range, startMatch, endMatch, tokenNumber, out recordList);
665             if ((int)ContactsError.None != error)
666             {
667                 Log.Error(Globals.LogTag, "Search Failed with error " + error);
668                 throw ContactsErrorFactory.CheckAndCreateException(error);
669             }
670             return new ContactsList(recordList);
671         }
672
673         /// <summary>
674         /// Gets the number of records in a specific view
675         /// </summary>
676         /// <param name="viewUri">The view URI</param>
677         /// <returns>The count of records</returns>
678         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
679         [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings")]
680         public int GetCount(string viewUri)
681         {
682             int count = -1;
683             int error = Interop.Database.GetCount(viewUri, out count);
684             if ((int)ContactsError.None != error)
685             {
686                 Log.Error(Globals.LogTag, "GetCount Failed with error " + error);
687                 throw ContactsErrorFactory.CheckAndCreateException(error);
688             }
689             return count;
690         }
691
692         /// <summary>
693         /// Gets the number of records matching a query.
694         /// </summary>
695         /// <param name="query">The query used for filtering the results</param>
696         /// <returns>The count of records</returns>
697         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
698         public int GetCount(ContactsQuery query)
699         {
700             int count = -1;
701             int error = Interop.Database.GetCount(query._queryHandle, out count);
702             if ((int)ContactsError.None != error)
703             {
704                 Log.Error(Globals.LogTag, "GetCount Failed with error " + error);
705                 throw ContactsErrorFactory.CheckAndCreateException(error);
706             }
707             return count;
708         }
709
710         /// <summary>
711         /// Registers a EventHandler to be invoked when a record changes.
712         /// </summary>
713         /// <param name="viewUri">The view URI of records whose changes are monitored</param>
714         /// <param name="DBChanged">The EventHandler to register</param>
715         [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings")]
716         public void AddDBChangedEventHandler(string viewUri, EventHandler<DBChangedEventArgs> DBChanged)
717         {
718             if (!_callbackMap.ContainsKey(viewUri))
719             {
720                 _callbackMap[viewUri] = (string uri, IntPtr userData) =>
721                 {
722                     DBChangedEventArgs args = new DBChangedEventArgs(uri);
723                     _eventHandlerMap[uri]?.Invoke(this, args);
724                 };
725
726                 int error = Interop.Database.AddChangedCb(viewUri, _callbackMap[viewUri], IntPtr.Zero);
727                 if ((int)ContactsError.None != error)
728                 {
729                     Log.Error(Globals.LogTag, "AddDBChangedEventHandler Failed with error " + error);
730                     throw ContactsErrorFactory.CheckAndCreateException(error);
731                 }
732             }
733
734             EventHandler<DBChangedEventArgs> handler = null;
735             if (!_eventHandlerMap.TryGetValue(viewUri, out handler))  
736                 _eventHandlerMap.Add(viewUri, null);
737
738             _eventHandlerMap[viewUri] = handler + DBChanged;
739         }
740
741         /// <summary>
742         /// Deregisters a EventHandler.
743         /// </summary>
744         /// <param name="viewUri">The view URI of records whose changes are monitored</param>
745         /// <param name="DBChanged">The EventHandler to deregister</param>
746         [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings")]
747         public void RemoveDBChangedEventHandler(string viewUri, EventHandler<DBChangedEventArgs> DBChanged)
748         {
749             EventHandler<DBChangedEventArgs> handler = null;
750             if (!_eventHandlerMap.TryGetValue(viewUri, out handler))
751                 _eventHandlerMap.Add(viewUri, null);
752             else
753                 _eventHandlerMap[viewUri] = handler - DBChanged;
754
755             if (_eventHandlerMap[viewUri] == null)
756             {
757                 int error = Interop.Database.RemoveChangedCb(viewUri, _callbackMap[viewUri], IntPtr.Zero);
758                 if ((int)ContactsError.None != error)
759                 {
760                     Log.Error(Globals.LogTag, "RemoveDBChangedEventHandler Failed with error " + error);
761                     throw ContactsErrorFactory.CheckAndCreateException(error);
762                 }
763                 _callbackMap.Remove(viewUri);
764             }
765         }
766     }
767 }