

#import "ATVDeviceController.h"
#import <sys/types.h>
#import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h>
#import "AppDelegate.h"

#define APP_DELEGATE (AppDelegate *)[[NSApplication sharedApplication] delegate]

@implementation ATVDeviceController


@synthesize deviceController, theComboBox, delegate;

- (NSString *)input: (NSString *)prompt defaultValue: (NSString *)defaultValue {
    NSAlert *alert = [NSAlert alertWithMessageText: prompt
                                     defaultButton:@"OK"
                                   alternateButton:@"Cancel"
                                       otherButton:nil
                         informativeTextWithFormat:@""];
    
    NSTextField *input = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 200, 24)];
    [input setStringValue:defaultValue];
    [alert setAccessoryView:input];
    NSInteger button = [alert runModal];
    if (button == NSAlertDefaultReturn) {
        [input validateEditing];
        NSString *inputString = [input stringValue];

        return inputString;
    } else if (button == NSAlertAlternateReturn) {

        return nil;
    } else {
        
        NSAssert1(NO, @"Invalid input dialog button %d", button);
        //[input autorelease];
        return nil;
    }
}

- (IBAction)menuItemSelected:(id)sender
{
    NSLog(@"sender: %@", sender);
    if (sender == nil)
    {
        return;
    }
    [APP_DELEGATE setAtvAvailable:NO];
    [[APP_DELEGATE progressInd] startAnimation:nil];
    NSInteger index = [sender indexOfSelectedItem];
    
    NSInteger itemCount = [sender numberOfItems];
    
    if (index == 0)
    {
        [APP_DELEGATE setAtvAvailable:FALSE];
        [APP_DELEGATE resetServerSettings];
        
        return;
    }
    
    if (index == itemCount-1)
    {
        //[sender setEditable:TRUE];
        
        NSString *output = [self input:@"Enter an Apple TV name or IP address" defaultValue:@""];
        [APP_DELEGATE setAtvAvailable:TRUE];
        [DEFAULTS setObject:output forKey:@"appleTVHost"];
        return;
        
    } else {
        
        //	[sender setEditable:FALSE];
    }
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND
                                             , 0), ^{
        NSNetService * clickedService = [services objectAtIndex:index];
        NSDictionary *finalDict = [self stringDictionaryFromService:clickedService];
        NSLog(@"finalDict: %@", finalDict);
        if ([[finalDict allKeys] count] > 0)
        {
            NSString *model = [finalDict objectForKey:@"model"];
            if ([model isEqualToString:@"AppleTV3,1"])
            {
                dispatch_async(dispatch_get_main_queue(), ^{
                    [sender selectItemAtIndex:0];
                    [APP_DELEGATE setAtvAvailable:FALSE];
                    [APP_DELEGATE showATVWarning];
                    [[APP_DELEGATE progressInd] stopAnimation:nil];
                });
                
            } else {
                NSString *ip;
                //int port;
                struct sockaddr_in *addr;
                
                addr = (struct sockaddr_in *) [[[clickedService addresses] objectAtIndex:0]
                                               bytes];
                ip = [NSString stringWithUTF8String:(char *) inet_ntoa(addr->sin_addr)];
                
                NSString *fullIP = [NSString stringWithFormat:@"%@:%i", ip, 22];
                
                //[APP_DELEGATE setAtvAvailable:TRUE];
                [DEFAULTS setObject:fullIP forKey:ATV_HOST];
                
                [APP_DELEGATE setStatusText:@"Checking device for jailbreak, please wait..."];
                NSLog(@"ATVADDRESS: %@", APPLE_TV_ADDRESS);
                BOOL jailbroken = [APP_DELEGATE isJailbroken];
                
                //hacky check here to see if its jailbroken
                dispatch_async(dispatch_get_main_queue(), ^{
                    NSLog(@"is jailbroken: %lu", jailbroken);
                    if (jailbroken == FALSE){
                    [APP_DELEGATE showNotJailbrokenWarning];
                    [DEFAULTS removeObjectForKey:ATV_HOST];
                    [DEFAULTS removeObjectForKey:@"selectedValue"];
                        [APP_DELEGATE setStatusText:@"Device is not jailbroken! :("];
                        [[APP_DELEGATE progressInd] stopAnimation:nil];
                    } else {
                        [APP_DELEGATE setStatusText:@"Device is jailbroken!"];
                        [APP_DELEGATE setAtvAvailable:YES];
                        [[APP_DELEGATE progressInd] stopAnimation:nil];
                        [APP_DELEGATE setDeviceDict:finalDict];
                    }
                    
                });
                
            }
        }
    });
    
    
}

- (NSString *)convertedName:(NSString *)inputName
{
	
	
    NSMutableString	*fixedNetLabel = [NSMutableString stringWithString:[inputName stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@".#,<>/?\'\\\[]{}+=-~`\";:"]]];
	//NSLog(@"fixedNetLabel: %@", fixedNetLabel);
    [fixedNetLabel replaceOccurrencesOfString:@" " withString:@"-" options:0 range:NSMakeRange(0, [fixedNetLabel length])];
	//int nameLength = [fixedNetLabel length];
	//fixedNetLabel = [fixedNetLabel substringToIndex:(nameLength-1)];
    return [NSString stringWithString:fixedNetLabel];
}

- (NSString *)fixedName:(NSString *)inputName
{
	NSInteger nameLength = [inputName length];
	NSString *newName = [inputName substringToIndex:(nameLength-1)];
	return newName;
}



- (NSDictionary *)stringDictionaryFromService:(NSNetService *)theService
{
	NSData *txtRecordDict = [theService TXTRecordData];
	
	NSDictionary *theDict = [NSNetService dictionaryFromTXTRecordData:txtRecordDict];
	NSMutableDictionary *finalDict = [[NSMutableDictionary alloc] init];
	NSArray *keys = [theDict allKeys];
	for (NSString *theKey in keys)
	{
		NSString *currentString = [[NSString alloc] initWithData:[theDict valueForKey:theKey] encoding:NSUTF8StringEncoding];
		[finalDict setObject:currentString forKey:theKey];
	}
    NSString *ip;
    int port;
    struct sockaddr_in *addr;
    if ([[theService addresses] count] == 0)
    {
        NSLog(@"no addresses resolved!?!?");
        return nil;
    }
    addr = (struct sockaddr_in *) [[[theService addresses] objectAtIndex:0]
                                   bytes];
    ip = [NSString stringWithUTF8String:(char *) inet_ntoa(addr->sin_addr)];
    port = ntohs(((struct sockaddr_in *)addr)->sin_port);
    //NSLog(@"ipaddress: %@", ip);
    //NSLog(@"port: %i", port);
    
    NSString *fullIP = [NSString stringWithFormat:@"%@:%i", ip, port];
    finalDict[@"fullIP"] = fullIP;
    finalDict[@"hostname"] = theService.hostName;
	return finalDict;
}






- (id)init {
	
    browser = [[NSNetServiceBrowser alloc] init];
    services = [NSMutableArray array];
    [browser setDelegate:self];
    //NSLog(@"awake from nib");
    // Passing in "" for the domain causes us to browse in the default browse domain

    
   [browser searchForServicesOfType:@"_airplay._tcp." inDomain:@""];
	// [hostNameField setStringValue:@""];
	self = [super init];
    

	NSDictionary *catv = [NSDictionary dictionaryWithObject:@"Choose Apple TV" forKey:@"name"];
	NSDictionary *theDict = [NSDictionary dictionaryWithObject:@"Other..." forKey:@"name"];
	[services addObject:catv];
	[services addObject:theDict];

	return self;
}

- (void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)browser

{
	//NSLog(@"%@ %s", self, _cmd);
    searching = NO;
	//[_parentObject endServices:services];
    [self updateUI];
	
}

- (void)updateUI

{
	//NSLog(@"%@ %s", self, _cmd);
    if(searching)
		
    {
		
        // Update the user interface to indicate searching
		
        // Also update any UI that lists available services
		
    }
	
    else
		
    {
		
		NSLog(@"services: %@", services);
        // Update the user interface to indicate not searching
		
    }
	
}

- (void)netServiceBrowserWillSearch:(NSNetServiceBrowser *)browser

{

	//NSLog(@"%@ %s", self, _cmd);
    searching = YES;
	
    [self updateUI];
	
}

// Error handling code

- (void)handleError:(NSNumber *)error

{
	
    NSLog(@"An error occurred. Error code = %d", [error intValue]);
	
    // Handle error here
	
}


- (BOOL)searching {
    return searching;
}


// This object is the delegate of its NSNetServiceBrowser object. We're only interested in services-related methods, so that's what we'll call.
- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing {
	
    NSInteger servicesCount = [services count]-1;
    
    [services insertObject:aNetService atIndex:servicesCount];

    [aNetService setDelegate:self];
    [aNetService resolveWithTimeout:5.0];
    
    if(!moreComing) {
 		

		[deviceController setContent:services];

		 
	}
}

#if TARGET_OS_OSX
/*
- (NSString *)input: (NSString *)prompt defaultValue: (NSString *)defaultValue {
	NSAlert *alert = [NSAlert alertWithMessageText: prompt
									 defaultButton:@"OK"
								   alternateButton:@"Cancel"
									   otherButton:nil
						 informativeTextWithFormat:@""];
	
	NSTextField *input = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 200, 24)];
	[input setStringValue:defaultValue];

	[alert setAccessoryView:input];
	NSInteger button = [alert runModal];
	if (button == NSAlertDefaultReturn) {
		[input validateEditing];
		NSString *inputString = [input stringValue];

		return inputString;
	} else if (button == NSAlertAlternateReturn) {
		return nil;
	} else {
		
		NSAssert1(NO, @"Invalid input dialog button %d", button);
		return nil;
	}
}
 */
#endif

- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didRemoveService:(NSNetService *)aNetService moreComing:(BOOL)moreComing {
    [services removeObject:aNetService];
    
    if(!moreComing) {
	
	}
}

- (NSDictionary *)deviceDictionary {
    return deviceDictionary;
}

- (void)setDeviceDictionary:(NSDictionary *)value {
    if (deviceDictionary != value) {
    
        deviceDictionary = [value copy];
    }
}

//resolution stuff


- (BOOL)addressesComplete:(NSArray *)addresses

		   forServiceType:(NSString *)serviceType

{
    // Perform appropriate logic to ensure that [netService addresses]
	
    if ([self.delegate respondsToSelector:@selector(servicesFound:)])
    {
        NSMutableArray *fullServices = [NSMutableArray new];
        for (NSNetService *service in services)
        {
            NSDictionary *fullDict = [self stringDictionaryFromService:service];
            if (fullDict != nil)
                [fullServices addObject:fullDict];
        }
        
          [self.delegate servicesFound:fullServices];
    }
    
	
    return YES;
	
}

// Sent when addresses are resolved

- (void)netServiceDidResolveAddress:(NSNetService *)aNetService

{
    NSDictionary *finalDict = [self stringDictionaryFromService:aNetService];
    if ([[finalDict allKeys] count] > 0)
    {
        
        NSString *model = [finalDict objectForKey:@"model"];
        if ([model isEqualToString:@"AppleTV5,3"])
        {
            //NSLog(@"should add service: %@", aNetService);
           // NSInteger servicesCount = [services count]-1;
            
            //[services insertObject:aNetService atIndex:servicesCount];
            
        } else {
            [services removeObject:aNetService];
            
            [deviceController setContent:services];
        }
    }
	/*
    if ([self addressesComplete:[netService addresses]
		 
				 forServiceType:[netService type]]) {
		
		
    }
	*/
}



// Sent if resolution fails

- (void)netService:(NSNetService *)netService

	 didNotResolve:(NSDictionary *)errorDict

{
	//NSLog(@"%@ %s", self, _cmd);
    [self handleError:[errorDict objectForKey:NSNetServicesErrorCode]];
	
    [services removeObject:netService];
	
}

#if TARGET_OS_OSX

// This object is the data source of its NSTableView. servicesList is the NSArray containing all those services that have been discovered.
- (int)numberOfRowsInTableView:(NSTableView *)theTableView {
    return [services count];
}

- (NSDictionary *)currentServiceDictionary {
    NSNetService * clickedService = [services objectAtIndex:[[self theComboBox] indexOfSelectedItem]];
    
    //NSLog(@"clickedService: %@" ,[self theComboBox]);
    
    return [self stringDictionaryFromService:clickedService];
}


- (id)tableView:(NSTableView *)theTableView objectValueForTableColumn:(NSTableColumn *)theColumn row:(int)rowIndex {
   NSString *fixedName = [[[[services objectAtIndex:rowIndex] name] componentsSeparatedByString:@"@"] lastObject];
	return fixedName;
	// return [[services objectAtIndex:rowIndex] name];
}

#endif

@end
