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