/* * Copyright 2012 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import "ZXCalendarParsedResult.h" static NSRegularExpression *ZX_DATE_TIME = nil; static NSRegularExpression *ZX_RFC2445_DURATION = nil; const long ZX_RFC2445_DURATION_FIELD_UNITS[] = { 7 * 24 * 60 * 60 * 1000, // 1 week 24 * 60 * 60 * 1000, // 1 day 60 * 60 * 1000, // 1 hour 60 * 1000, // 1 minute 1000, // 1 second }; @implementation ZXCalendarParsedResult + (void)initialize { if ([self class] != [ZXCalendarParsedResult class]) return; ZX_DATE_TIME = [[NSRegularExpression alloc] initWithPattern:@"[0-9]{8}(T[0-9]{6}Z?)?" options:0 error:nil]; ZX_RFC2445_DURATION = [[NSRegularExpression alloc] initWithPattern:@"P(?:(\\d+)W)?(?:(\\d+)D)?(?:T(?:(\\d+)H)?(?:(\\d+)M)?(?:(\\d+)S)?)?" options:NSRegularExpressionCaseInsensitive error:nil]; } - (id)initWithSummary:(NSString *)summary startString:(NSString *)startString endString:(NSString *)endString durationString:(NSString *)durationString location:(NSString *)location organizer:(NSString *)organizer attendees:(NSArray *)attendees description:(NSString *)description latitude:(double)latitude longitude:(double)longitude { if (self = [super initWithType:kParsedResultTypeCalendar]) { _summary = summary; _start = [self parseDate:startString]; if (endString == nil) { long durationMS = [self parseDurationMS:durationString]; _end = durationMS < 0 ? nil : [NSDate dateWithTimeIntervalSince1970:[_start timeIntervalSince1970] + durationMS / 1000]; } else { _end = [self parseDate:endString]; } _startAllDay = startString.length == 8; _endAllDay = endString != nil && endString.length == 8; _location = location; _organizer = organizer; _attendees = attendees; _resultDescription = description; _latitude = latitude; _longitude = longitude; } return self; } + (id)calendarParsedResultWithSummary:(NSString *)summary startString:(NSString *)startString endString:(NSString *)endString durationString:(NSString *)durationString location:(NSString *)location organizer:(NSString *)organizer attendees:(NSArray *)attendees description:(NSString *)description latitude:(double)latitude longitude:(double)longitude { return [[self alloc] initWithSummary:summary startString:startString endString:endString durationString:durationString location:location organizer:organizer attendees:attendees description:description latitude:latitude longitude:longitude]; } - (NSString *)displayResult { NSMutableString *result = [NSMutableString stringWithCapacity:100]; [ZXParsedResult maybeAppend:self.summary result:result]; [ZXParsedResult maybeAppend:[self format:self.startAllDay date:self.start] result:result]; [ZXParsedResult maybeAppend:[self format:self.endAllDay date:self.end] result:result]; [ZXParsedResult maybeAppend:self.location result:result]; [ZXParsedResult maybeAppend:self.organizer result:result]; [ZXParsedResult maybeAppendArray:self.attendees result:result]; [ZXParsedResult maybeAppend:self.description result:result]; return result; } /** * Parses a string as a date. RFC 2445 allows the start and end fields to be of type DATE (e.g. 20081021) * or DATE-TIME (e.g. 20081021T123000 for local time, or 20081021T123000Z for UTC). */ - (NSDate *)parseDate:(NSString *)when { NSArray *matches = [ZX_DATE_TIME matchesInString:when options:0 range:NSMakeRange(0, when.length)]; if (matches.count == 0) { [NSException raise:NSInvalidArgumentException format:@"Invalid date"]; } if (when.length == 8) { // Show only year/month/day return [[self buildDateFormat] dateFromString:when]; } else { // The when string can be local time, or UTC if it ends with a Z if (when.length == 16 && [when characterAtIndex:15] == 'Z') { return [[self buildDateTimeFormat] dateFromString:[when substringToIndex:15]]; } else { return [[self buildDateTimeFormat] dateFromString:when]; } } } - (NSString *)format:(BOOL)allDay date:(NSDate *)date { if (date == nil) { return nil; } NSDateFormatter *format = [[NSDateFormatter alloc] init]; format.dateFormat = allDay ? @"MMM d, yyyy" : @"MMM d, yyyy hh:mm:ss a"; return [format stringFromDate:date]; } - (long)parseDurationMS:(NSString *)durationString { if (durationString == nil) { return -1; } NSArray *m = [ZX_RFC2445_DURATION matchesInString:durationString options:0 range:NSMakeRange(0, durationString.length)]; if (m.count == 0) { return -1; } long durationMS = 0; NSTextCheckingResult *match = m[0]; for (int i = 0; i < sizeof(ZX_RFC2445_DURATION_FIELD_UNITS) / sizeof(long); i++) { if ([match rangeAtIndex:i + 1].location != NSNotFound) { NSString *fieldValue = [durationString substringWithRange:[match rangeAtIndex:i + 1]]; if (fieldValue != nil) { durationMS += ZX_RFC2445_DURATION_FIELD_UNITS[i] * [fieldValue intValue]; } } } return durationMS; } - (NSDateFormatter *)buildDateFormat { NSDateFormatter *format = [[NSDateFormatter alloc] init]; format.dateFormat = @"yyyyMMdd"; format.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"]; return format; } - (NSDateFormatter *)buildDateTimeFormat { NSDateFormatter *format = [[NSDateFormatter alloc] init]; format.dateFormat = @"yyyyMMdd'T'HHmmss"; return format; } - (NSString *)description { return self.resultDescription; } @end