Checking in improvements to the effect availability heuristic.
[MenuTunes.git] / MTeSerialNumber.m
1 #import "MTeSerialNumber.h"
2 #import "validate.h"
3
4
5 @interface MTeSerialNumber (Private)
6 - (short)validate;
7 - (eSellerate_String)eSellerateStringForString:(NSString *)string;
8 @end
9
10 @implementation MTeSerialNumber
11
12 /*************************************************************************/
13 #pragma mark -
14 #pragma mark INITIALIZATION METHODS
15 /*************************************************************************/
16
17 - (id)initWithSerialNumber:(NSString *)serial
18                       name:(NSString *)name
19                      extra:(NSString *)extra
20                  publisher:(NSString *)publisher
21 {
22     if ( (self = [super init]) ) {
23         _serialNumber = serial;
24         _nameBasedKey = name;
25         _extraDataKey = nil;       //extra data is currently unused.
26         _publisherKey = publisher;
27         _deadSerials  = nil;
28     }
29     return self;
30 }
31
32 - (id)initWithDictionary:(NSDictionary *)dict
33 {
34     return [self initWithSerialNumber:[dict objectForKey:@"Key"]
35                                  name:[dict objectForKey:@"Owner"]
36                                 extra:[dict objectForKey:@"Extra"]
37                             publisher:[dict objectForKey:@"Publisher"]];
38 }
39
40 - (id)initWithContentsOfFile:(NSString *)path
41                        extra:(NSString *)extra
42                    publisher:(NSString *)publisher
43 {
44     NSDictionary *fileDict = [[[NSDictionary alloc] initWithContentsOfFile:path] autorelease];
45     
46     if ( fileDict ) {
47         NSMutableDictionary *dict = [[[NSMutableDictionary alloc] initWithCapacity:4] autorelease];
48
49         [dict setObject:[fileDict objectForKey:@"Key"] forKey:@"Key"];
50         [dict setObject:[fileDict objectForKey:@"Owner"] forKey:@"Owner"];
51         [dict setObject:extra forKey:@"Extra"];
52         [dict setObject:publisher forKey:@"Publisher"];
53
54         return [self initWithDictionary:dict];
55     } else {
56         return nil;
57     }
58 }
59
60
61 /*************************************************************************/
62 #pragma mark -
63 #pragma mark ACCESSOR METHODS
64 /*************************************************************************/
65
66 - (NSString *)serialNumber
67 {
68     return _serialNumber;
69 }
70
71 - (void)setSerialNumber:(NSString *)newSerial
72 {
73     [_serialNumber autorelease];
74     _serialNumber = [newSerial copy];
75 }
76
77 - (NSString *)nameBasedKey
78 {
79     return _nameBasedKey;
80 }
81
82 - (void)setNameBasedKey:(NSString *)newName
83 {
84     [_nameBasedKey autorelease];
85     _nameBasedKey = [newName copy];
86 }
87
88 - (NSString *)extraDataKey
89 {
90     return _extraDataKey;
91 }
92
93 - (void)setExtraDataKey:(NSString *)newData
94 {
95     [_extraDataKey autorelease];
96     _extraDataKey = [newData copy];
97 }
98
99 - (NSString *)publisherKey
100 {
101     return _publisherKey;
102 }
103
104 - (void)setPublisherKey:(NSString *)newPublisher
105 {
106     [_publisherKey autorelease];
107     _publisherKey = [newPublisher copy];
108 }
109
110 - (NSArray *)deadSerials
111 {
112     return _deadSerials;
113 }
114
115 - (void)setDeadSerials:(NSArray *)newList
116 {
117     [_deadSerials autorelease];
118     _deadSerials = [newList copy];
119 }
120
121
122 /*************************************************************************/
123 #pragma mark -
124 #pragma mark INSTANCE METHODS
125 /*************************************************************************/
126
127 - (MTeSerialNumberValidationResult)isValid
128 {
129     if ( _serialNumber ) {
130
131         BOOL dead = NO;
132         
133         if ( [_deadSerials count] )  {
134             NSEnumerator *deadEnum = [_deadSerials objectEnumerator];
135             id            aDeadSerial;
136             
137             while ( (aDeadSerial = [deadEnum nextObject]) ) {
138                 if ( [aDeadSerial isEqualToString:_serialNumber] ) {
139                     dead = YES;
140                 }
141             }
142         }
143
144         if ( dead ) {
145             return ITeSerialNumberIsDead;
146         } else {
147             return ( ( [self validate] > 0 ) ? ITeSerialNumberIsValid : ITeSerialNumberIsInvalid );
148         }
149     } else {
150         return nil;
151     }
152 }
153
154 - (MTeSerialNumberExpirationResult)isExpired;
155 {
156     return ( ! [self secondsRemaining] > 0 );
157 }
158
159 - (NSDate *)storedDate
160 {
161     NSCalendarDate *refDate = [NSCalendarDate dateWithYear:2000 month:1 day:1
162                                                       hour:0 minute:0 second:0
163                                                   timeZone:[NSTimeZone systemTimeZone]];
164
165     NSTimeInterval secondsFromRefToExp = ([self validate] * 86400);
166
167     return [[[NSDate alloc] initWithTimeInterval:secondsFromRefToExp
168                                        sinceDate:refDate] autorelease];
169 }
170
171 - (NSTimeInterval)secondsRemaining
172 {
173     return [[self storedDate] timeIntervalSinceDate:[NSDate date]];
174 }
175
176 - (NSDictionary *)infoDictionary
177 {
178     NSString *prefix        = [[_serialNumber componentsSeparatedByString:@"-"] objectAtIndex:0];
179     NSString *appIdentifier = nil;
180     NSString *version       = nil;
181     NSString *typeCode      = nil;
182     NSString *quantity      = nil;
183     
184     if ( ( [prefix length] == 10 ) || ( [prefix length] == 7 ) ) {
185         appIdentifier = [_serialNumber substringWithRange:NSMakeRange(0,2)];
186         version       = [_serialNumber substringWithRange:NSMakeRange(2,3)];
187         typeCode      = [_serialNumber substringWithRange:NSMakeRange(5,2)];
188     } else {
189         return nil;
190     }
191
192     if ( [prefix length] == 10 ) {
193         quantity = [_serialNumber substringWithRange:NSMakeRange(7,3)];
194     }
195
196     return [NSDictionary dictionaryWithObjectsAndKeys:
197         appIdentifier, @"appIdentifier",
198         version,       @"version",
199         typeCode,      @"typeCode",
200         quantity,      @"quantity",   nil];
201 }
202
203
204 /*************************************************************************/
205 #pragma mark -
206 #pragma mark PRIVATE IMPLEMENTATIONS
207 /*************************************************************************/
208
209 - (short)validate
210 {
211     eSellerate_String pSerial    = [self eSellerateStringForString:_serialNumber];
212     eSellerate_String pName      = [self eSellerateStringForString:_nameBasedKey];
213     eSellerate_String pExtraData = [self eSellerateStringForString:_extraDataKey];
214     eSellerate_String pPublisher = [self eSellerateStringForString:_publisherKey];
215     
216     return eSellerate_ValidateSerialNumber(pSerial,
217                                            pName,
218                                            pExtraData,
219                                            pPublisher);
220 }
221
222 - (eSellerate_String)eSellerateStringForString:(NSString *)string
223 {
224     if ( string ) {
225         NSMutableData *buffer = [[[NSMutableData alloc] initWithCapacity:256] autorelease];
226         
227         CFStringGetPascalString( (CFStringRef)string,
228                                  [buffer mutableBytes],
229                                  256,
230                                  CFStringGetSystemEncoding());
231                                  
232         return (eSellerate_String)[buffer bytes];
233     } else {
234         return nil;
235     }
236 }
237
238
239 @end