#import "AppDelegate.h"

#import <netinet/in.h>
#import <sys/socket.h>

#define GUID [[NSProcessInfo processInfo] globallyUniqueString]

@interface AppDelegate ()

- (void)startTestTimers;
- (void)disconnect;

@end

@implementation AppDelegate

@synthesize filteredObjects;

//START:disconnect
- (void)disconnect
{
  [pingTimer invalidate], pingTimer = nil;
  [fetchTimer invalidate], fetchTimer = nil;
  [insertTimer invalidate], insertTimer = nil;
  [deleteTimer invalidate], deleteTimer = nil;
  [childDeleteTimer invalidate], childDeleteTimer = nil;
  [childInsertTimer invalidate], childInsertTimer = nil;
  
  NSConnection *connection = [(NSDistantObject*)server connectionForProxy];
  [connection invalidate];
  server = nil;
}
//END:disconnect

#pragma mark -
#pragma mark Application Delegate Methods

//START:applicationDidFinishLaunching
- (void)applicationDidFinishLaunching:(NSNotification*)notification
{
  NSNetServiceBrowser *myBrowser = [[NSNetServiceBrowser alloc] init];
  [myBrowser setDelegate:self];
  [myBrowser searchForServicesOfType:kServiceName inDomain:kDomainName];
}
//END:applicationDidFinishLaunching

- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender 
{
  [self disconnect];
  return NSTerminateNow;
}

#pragma mark -
#pragma mark NSNetServiceBrowser Delegate

//START:didFindService
- (void)netServiceBrowser:(NSNetServiceBrowser*)browser 
           didFindService:(NSNetService*)service 
               moreComing:(BOOL)more
{
  [service retain];
  [service setDelegate:self];
  [service resolveWithTimeout:5.0];
  [service startMonitoring];
  
  [browser stop];
  [browser release], browser = nil;
}
//END:didFindService

#pragma mark -
#pragma mark NetService delegate methods

//START:netServiceDidResolveAddress
- (void)netServiceDidResolveAddress:(NSNetService*)service
{
  NSConnection *clientConnection = nil;
  NSSocketPort *socket = nil;
  NSData *address = [[service addresses] lastObject];
  u_char family = ((struct sockaddr*)[address bytes])->sa_family;
  socket = [[NSSocketPort alloc] initRemoteWithProtocolFamily:family 
                                                   socketType:SOCK_STREAM 
                                                     protocol:IPPROTO_TCP 
                                                      address:address];
  clientConnection = [NSConnection connectionWithReceivePort:nil 
                                                    sendPort:socket];
  [clientConnection enableMultipleThreads];
  server = [clientConnection rootProxy];
  
  [socket release], socket = nil;
  [service stop];
  [service release];
  
  [self startTestTimers];
}
//END:netServiceDidResolveAddress

#pragma mark -
#pragma mark Start Test Timers

//START:startTestTimers
- (void)startTestTimers
{
  SEL selector = @selector(testPing);
  pingTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 
                                               target:self 
                                             selector:selector
                                             userInfo:nil 
                                              repeats:YES];
  
  selector = @selector(testObjectInsertion);
  insertTimer = [NSTimer scheduledTimerWithTimeInterval:0.5
                                                 target:self
                                               selector:selector
                                               userInfo:nil 
                                                repeats:YES];
  
  selector = @selector(testObjectDeletion);
  deleteTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 
                                                 target:self 
                                               selector:selector
                                               userInfo:nil 
                                                repeats:YES];
  
  selector = @selector(testChildInsertion);
  childInsertTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 
                                                      target:self 
                                                    selector:selector
                                                    userInfo:nil 
                                                     repeats:YES];
  
  selector = @selector(testChildDeletion);
  childDeleteTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 
                                                      target:self 
                                                    selector:selector
                                                    userInfo:nil 
                                                     repeats:YES];
  
  selector = @selector(testObjectFetch);
  fetchTimer = [NSTimer scheduledTimerWithTimeInterval:15.0 
                                                target:self 
                                              selector:selector
                                              userInfo:nil 
                                               repeats:YES];
}
//END:startTestTimers

#pragma mark -
#pragma mark Test Methods

//START:testPing
- (void)testPing
{
  [server ping];
}
//END:testPing

//START:testObjectFetch
- (void)testObjectFetch
{
  NSString *test = [GUID substringToIndex:3];
  NSPredicate *predicate = nil;
  predicate = [NSPredicate predicateWithFormat:@"name contains[c] %@", test];
  
  NSArray *results = [server objectsOfName:@"Test" withPredicate:predicate];
  
  NSEnumerator *enumerator = [results objectEnumerator];
  NSManagedObject *object;
  while (object = [enumerator nextObject]) {
    [object setValue:GUID forKey:@"name"];
  }
  
  [self setFilteredObjects:results];
}
//END:testObjectFetch

//START:testObjectInsertion
- (void)testObjectInsertion
{
  if ((rand() % 2) == NO) return;
  NSManagedObject *object = [server createObject];
  [object setValue:GUID forKey:@"name"];
}
//END:testObjectInsertion

//START:testObjectDeletion
- (void)testObjectDeletion
{
  NSArray *objects = [server allObjects];
  
  if (![objects count]) return;

  int index = (rand() % [objects count]);
  NSManagedObject *toBeDeleted = [objects objectAtIndex:index];
  
  [server deleteObject:toBeDeleted];
}
//END:testObjectDeletion

//START:testChildInsertion
- (void)testChildInsertion
{
  NSArray *objects = [server allObjects];
  id object = [objects objectAtIndex:(rand() % [objects count])];
  id child = [server createChildForObject:object];
  [child setValue:GUID forKey:@"name"];
}
//END:testChildInsertion

//START:testChildDeletion
- (void)testChildDeletion
{
  NSArray *objects = [server allObjects];

  int index = (rand() % [objects count]);
  id object = [objects objectAtIndex:index];

  NSSet *children = [object valueForKey:@"children"];
  
  if (![children count]) return;

  id child = [children anyObject];
  [server deleteObject:child];
}
//END:testChildDeletion

@end
