1// ADRecord.m (this is -*- ObjC -*-)
2//
3// \author: Bj�rn Giesler <giesler@ira.uka.de>
4//
5// Address Book Framework for GNUstep
6//
7
8#import "ADAddressBook.h"
9#import "ADGlobals.h"
10#import "ADConverter.h"
11#import "ADMultiValue.h"
12#import "ADRecord.h"
13
14@implementation ADRecord
15- init
16{
17  _dict = nil;
18  _book = nil;
19  _readOnly = NO;
20
21  if([self isKindOfClass: [ADPerson class]])
22    [self setValue: @"Person" forProperty: @"Type"];
23  else if([self isKindOfClass: [ADGroup class]])
24    [self setValue: @"Group" forProperty: @"Type"];
25
26  return [super init];
27}
28
29- (void) dealloc
30{
31  [_dict release];
32  [_book release];
33  [super dealloc];
34}
35
36- (id) valueForProperty: (NSString *) property
37{
38  return [_dict objectForKey: property];
39}
40
41- (BOOL) setValue: (id) value
42      forProperty: (NSString *) property
43{
44  NSMutableDictionary *newDict;
45
46  if(_readOnly)
47    {
48      NSLog(@"Trying to set value %@ for property %@ in read-only record %@\n",
49	    value, property, [self uniqueId]);
50      return NO;
51    }
52
53  newDict = [NSMutableDictionary dictionaryWithDictionary: _dict];
54
55  if(!value || [value isEqual: @""])
56    [newDict removeObjectForKey: property];
57  else
58    [newDict setObject: value forKey: property];
59
60  [_dict release];
61  _dict = [[NSDictionary alloc] initWithDictionary: newDict];
62
63  if([property isEqualToString: ADModificationDateProperty])
64    return NO;
65
66  [self setValue: [NSDate date] forProperty: ADModificationDateProperty];
67
68  if(![property isEqualToString: ADUIDProperty])
69    [[NSNotificationCenter defaultCenter]
70      postNotificationName: ADRecordChangedNotification
71      object: self
72      userInfo: [NSDictionary dictionaryWithObjectsAndKeys:
73				value, ADChangedValueKey,
74			      property, ADChangedPropertyKey,
75			      nil]];
76
77  return YES;
78}
79
80- (BOOL) removeValueForProperty: (NSString*) property
81{
82  NSMutableDictionary *newDict;
83
84  if(_readOnly)
85    {
86      NSLog(@"Trying to remove value for property %@ in read-only record %@\n",
87	    property, [self uniqueId]);
88      return NO;
89    }
90
91  newDict = [NSMutableDictionary dictionaryWithDictionary: _dict];
92  [newDict removeObjectForKey: property];
93  [_dict release];
94  _dict = [[NSDictionary alloc] initWithDictionary: newDict];
95
96  if(![property isEqualToString: ADUIDProperty])
97    [[NSNotificationCenter defaultCenter]
98      postNotificationName: ADRecordChangedNotification
99      object: self
100      userInfo: [NSDictionary dictionaryWithObjectsAndKeys:
101				property, ADChangedPropertyKey,
102			      nil]];
103  return YES;
104}
105
106- (ADAddressBook*) addressBook
107{
108  return _book;
109}
110
111- (void) setAddressBook: (ADAddressBook*) book
112{
113  if(_book)
114    [NSException raise: ADAddressBookConsistencyError
115		 format: @"Cannot set address book on record '%@'"
116		 @" (already has one)", [self uniqueId]];
117  if(!book)
118    [NSException raise: ADAddressBookConsistencyError
119		 format: @"Cannot set nil address book on record '%@'",
120		 [self uniqueId]];
121  _book = [book retain];
122}
123
124- (id) copyWithZone: (NSZone*) z
125{
126  ADRecord* obj = NSCopyObject(self, 0, z);
127  obj->_readOnly = _readOnly;
128
129  // delete UID if it has one
130  if([_dict objectForKey: ADUIDProperty])
131    {
132      NSMutableDictionary *d =
133	[NSMutableDictionary
134	  dictionaryWithDictionary: [_dict copy]];
135      [d removeObjectForKey: ADUIDProperty];
136      obj->_dict = [[NSDictionary alloc] initWithDictionary: d];
137    }
138  else
139    obj->_dict = [_dict copy];
140
141  obj->_book = nil;
142
143  return obj;
144}
145@end
146
147@implementation ADRecord(ADRecord_Convenience)
148- (NSString*) uniqueId
149{
150  return [self valueForProperty: ADUIDProperty];
151}
152@end
153
154@implementation ADRecord(AddressesExtensions)
155- (BOOL) readOnly
156{
157  return _readOnly;
158}
159
160- (void) setReadOnly
161{
162  _readOnly = YES;
163}
164
165- (id) initWithRepresentation: (NSString*) str
166			 type: (NSString*) type
167{
168  id<ADInputConverting> converter; id obj;
169  Class c;
170
171  c = [self class];
172  [self release];
173
174  converter = [[ADConverterManager sharedManager]
175		inputConverterForType: type];
176  if(!converter) return nil;
177
178  if(![converter useString: str])
179    return nil;
180
181  obj = [converter nextRecord];
182  if(!obj) return nil;
183
184  if(![[obj class] isSubclassOfClass: c])
185    {
186      NSLog(@"It's of %@, not %@\n", [c className], [obj className]);
187      return nil;
188    }
189
190  return [obj retain];
191}
192
193- (NSString*) representationWithType: (NSString*) type
194{
195  id<ADOutputConverting> converter;
196
197  [self release];
198
199  converter = [[ADConverterManager sharedManager]
200		outputConverterForType: type];
201  [converter storeRecord: self];
202  return [converter string];
203}
204
205- (NSDictionary*) contentDictionary
206{
207  NSMutableDictionary *dict;
208  NSEnumerator *e;
209  NSString *key;
210
211  dict = [NSMutableDictionary dictionaryWithCapacity: [_dict count]];
212  e = [[_dict allKeys] objectEnumerator];
213  while((key = [e nextObject]))
214    {
215      NSObject *obj = [_dict objectForKey: key];
216      if([obj isKindOfClass: [ADMultiValue class]])
217	[dict setObject: [(ADMultiValue*)obj contentArray] forKey: key];
218      else if([obj isKindOfClass: [NSString class]] ||
219	      [obj isKindOfClass: [NSData class]] ||
220	      [obj isKindOfClass: [NSDate class]] ||
221	      [obj isKindOfClass: [NSArray class]] ||
222	      [obj isKindOfClass: [NSDictionary class]])
223	[dict setObject: obj forKey: key];
224      else
225	NSLog(@"Value for \"%@\" in record \"%@\" has invalid class %@\n",
226	      key, [self uniqueId], [obj className]);
227    }
228
229  return dict;
230}
231@end
232