// // DesktopFileAnalyticsLogger.m // Pennyworth // // Created by Chris Karr on 12/5/08. // Copyright 2008 Northwestern University. All rights reserved. // #import "DesktopFileAnalyticsLogger.h" #import "AppDelegate.h" #define ANALYTICS_DATE @"Analytics Date" #define ANALYTICS_FOLDER @"Pennyworth Analytics" #define EVENT_ELEMENT @"event" #define NAME @"name" #define DATE @"date" #define COMPONENT @"component" @implementation DesktopFileAnalyticsLogger - (void) awakeFromNib { events = [[NSMutableArray alloc] init]; if ([[NSUserDefaults standardUserDefaults] valueForKey:ENABLE_ANALYTICS] != nil) [[NSTimer scheduledTimerWithTimeInterval:3600 target:self selector:@selector(writeEvents:) userInfo:nil repeats:YES] retain]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(writeOnSave:) name:TERMINATE_NOTIFICATION object:nil]; [super awakeFromNib]; } - (void) processEvent:(NSNotification *) theNote { NSDate * now = [NSDate date]; NSDictionary * event = [NSMutableDictionary dictionaryWithDictionary:[theNote object]]; [event setValue:now forKey:ANALYTICS_DATE]; [events addObject:event]; // NSLog (@"events size = %d", [events count]); } - (void) writeEvents:(NSTimer *) theTimer { NSLog (@"Saving Events"); NSDate * now = [NSDate date]; NSDateFormatter * formatter = [[NSDateFormatter alloc] init]; NSError * error = nil; NSFileManager * fileManager = [NSFileManager defaultManager]; NSBundle * bundle = [NSBundle mainBundle]; NSArray * desktops = NSSearchPathForDirectoriesInDomains(NSDesktopDirectory, NSUserDomainMask, YES); NSMutableString * analyticsFolder = [NSMutableString stringWithString:[desktops lastObject]]; [analyticsFolder appendFormat:@"/%@", ANALYTICS_FOLDER]; NSString * rootFolder = [analyticsFolder copy]; BOOL isDir = NO; [formatter setDateFormat:@"yyyy/MM/dd"]; [analyticsFolder appendFormat:@"/%@", [formatter stringFromDate:now]]; if (![fileManager fileExistsAtPath:analyticsFolder isDirectory:&isDir] || !isDir) { [fileManager removeItemAtPath:analyticsFolder error:&error]; [fileManager createDirectoryAtPath:analyticsFolder withIntermediateDirectories:YES attributes:nil error:&error]; [fileManager copyItemAtPath:[bundle pathForResource:@"style" ofType:@"css"] toPath:[rootFolder stringByAppendingString:@"/style.css"] error:&error]; [fileManager copyItemAtPath:[bundle pathForResource:@"style" ofType:@"xsl"] toPath:[rootFolder stringByAppendingString:@"/style.xsl"] error:&error]; } [formatter setDateFormat:@"HH.mm.ss"]; NSString * xmlFile = [analyticsFolder stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.xml", [formatter stringFromDate:now]]]; NSXMLElement * root = [[NSXMLElement alloc] initWithName:@"analytics"]; NSXMLDocument * doc = [[NSXMLDocument alloc] initWithRootElement:root]; [doc setVersion:@"1.0"]; [doc setCharacterEncoding:@"UTF-8"]; NSXMLNode * proc = [NSXMLNode processingInstructionWithName:@"xml-stylesheet" stringValue:@"type=\"text/xsl\" href=\"../../../style.xsl\""]; [doc insertChild:proc atIndex:0]; NSSortDescriptor * dateSort = [[NSSortDescriptor alloc] initWithKey:ANALYTICS_DATE ascending:YES]; NSArray * sortedEvents = [events sortedArrayUsingDescriptors:[NSArray arrayWithObject:dateSort]]; for (NSDictionary * event in sortedEvents) { NSXMLElement * eventElement = [[NSXMLElement alloc] initWithName:EVENT_ELEMENT]; [eventElement addAttribute:[NSXMLNode attributeWithName:NAME stringValue:[event valueForKey:ANALYTIC_NAME]]]; [eventElement addAttribute:[NSXMLNode attributeWithName:DATE stringValue:[[event valueForKey:ANALYTICS_DATE] description]]]; NSObject * value = [event valueForKey:ANALYTIC_VALUE]; if ([value isKindOfClass:[NSDictionary class]]) { NSDictionary * dict = (NSDictionary *) value; NSArray * keys = [[dict allKeys] sortedArrayUsingSelector:@selector(compare:)]; for (NSString * key in keys) { NSXMLElement * componentElement = [[NSXMLElement alloc] initWithName:COMPONENT]; [componentElement addAttribute:[NSXMLNode attributeWithName:NAME stringValue:key]]; [componentElement setStringValue:[[dict valueForKey:key] description]]; [eventElement addChild:componentElement]; [componentElement release]; } } else [eventElement setStringValue:[value description]]; [root addChild:eventElement]; [eventElement release]; } [events removeObjectsInArray:sortedEvents]; NSData * xmlData = [doc XMLData]; NSLog (@"writing to %@", xmlFile); [xmlData writeToFile:xmlFile atomically:YES]; [doc release]; [dateSort release]; [formatter release]; } - (void) writeOnSave:(NSNotification *) theNote { [self writeEvents:nil]; } @end