//
//  ChooseServerController.m
//  CyTV Client
//
//  Copyright (c) 2004 Andreas Junghans. All rights reserved.
//

#import "ChooseServerController.h"
#import <fcntl.h>
#import <unistd.h>

static NSString* _proxyAuthFile = @"~/Library/Application Support/CyTV/proxy_auth";

//static NSString* advancedKey = @"advanced";
static NSString* transcodeKey = @"transcode";
static NSString* videoBitrateKey = @"videoBitrate";
static NSString* framerateKey = @"framerate";
static NSString* widthKey = @"width";
static NSString* heightKey = @"height";
static NSString* audioBitrateKey = @"audioBitrate";
static NSString* sampleRateKey = @"sampleRate";
static NSString* numberOfChannelsKey = @"numberOfChannels";
static NSString* cacheSizeKey = @"cacheSize";
static NSString* secureConnectionKey = @"useSecureConnection";
static NSString* securePortKey = @"securePort";
static NSString* secureUserKey = @"secureUser";
static NSString* proxyKey = @"useProxy";
static NSString* proxyServerKey = @"proxyServer";
static NSString* proxyAuthKey = @"useProxyAuthentication";
static NSString* deinterlaceKey = @"deinterlaceOnServer";
static NSString* highQualityKey = @"highQuality";

@implementation ChooseServerController

- (void)validateEditing {
    [videoBitrate validateEditing];
    [framerate validateEditing];
    [width validateEditing];
    [height validateEditing];
    [audioBitrate validateEditing];
    [sampleRate validateEditing];
    [numberOfChannels validateEditing];
}

- (void)displayError:(NSString*)msg title:(NSString*)title forWindow:(NSWindow*)aWindow {
    NSBeginAlertSheet(title, nil, nil, nil, aWindow,
                      nil, nil, nil, nil, msg);
}

- (void)displayCriticalError:(NSString*)msg title:(NSString*)title forWindow:(NSWindow*)aWindow {
    NSBeginCriticalAlertSheet(title, nil, nil, nil, aWindow,
                      nil, nil, nil, nil, msg);
}

- (void)displayError:(NSString*)msg forWindow:(NSWindow*)aWindow {
    [self displayError:msg title:@"Please verify your entry" forWindow:aWindow];
}

- (void)correctSettings {
    if (_cacheSize < 128 || _cacheSize > 2000000) {
        _cacheSize = 1024;
    }
    if (_securePort < 1 || _securePort > 65535) {
        _securePort = 443;
    }
    if (_secureUser == nil) {
        _secureUser = [@"" retain];
    }
    if ([_secureUser length] == 0) {
        _secureConnection = FALSE;
    }
    if (_proxyServer == nil) {
        _proxyServer = [@"" retain];
    }
    if (_proxy) {
        if ([_proxyServer length] == 0) {
            _proxy = FALSE;
        } else {
            NSArray* proxyComponents = [_proxyServer componentsSeparatedByString:@":"];
            if ([proxyComponents count] != 2) {
                _proxy = FALSE;
            } else {
                if ([(NSString*)[proxyComponents objectAtIndex:0] length] == 0 ||
                    [(NSString*)[proxyComponents objectAtIndex:1] length] == 0) {
                    _proxy = FALSE;
                }
            }
        }
    }
}

- (void)correctAdvancedSettings {
    if (_videoBitrate < 32 || _videoBitrate > 2000000) {
        _videoBitrate = 1150;
    }
    if (_framerate != 0 && (_framerate < 1 || _framerate > 120)) {
        _framerate = 25;
    }
    if (_width != 0 || _height != 0) {
        if (_width < 1) {
            _width = 1;
        } else if (_width > 65535) {
            _width = 65535;
        }
        if (_height < 1) {
            _height = 1;
        } else if (_height > 65535) {
            _height = 65535;
        }
    }
    if (_audioBitrate < 32 || _audioBitrate > 2000000 || _audioBitrate%32 != 0) {
        _audioBitrate = 224;
    }
    if (_sampleRate != 0 && _sampleRate != 22050 && _sampleRate != 44100 &&
        _sampleRate != 48000 && _sampleRate != 96000) {
        _sampleRate = 44100;
    }
    if (_numberOfChannels != 0 && (_numberOfChannels < 1 || _numberOfChannels > 2)) {
        _numberOfChannels = 2;
    }
}

- (void)initSettings {
    NSUserDefaults *def = [NSUserDefaults standardUserDefaults];
    //_advanced = [def boolForKey:advancedKey];
    _cacheSize = [def integerForKey:cacheSizeKey];
    _secureConnection = [def boolForKey:secureConnectionKey];
    _securePort = [def integerForKey:securePortKey];
    [_secureUser autorelease];
    _secureUser = [[def stringForKey:secureUserKey] retain];
    _proxy = [def boolForKey:proxyKey];
    [_proxyServer autorelease];
    _proxyServer = [[def stringForKey:proxyServerKey] retain];
    _proxyAuth = [def boolForKey:proxyAuthKey];
    [self correctSettings];
    /*NSRect frame = [window frame];
    if (_advanced) {
        //[advanced setState:NSOnState];
        if (frame.size.height != [window maxSize].height) {
            frame.origin.y -= [window maxSize].height - [window minSize].height;
            frame.size = [window maxSize];
            [window setFrame:frame display:NO animate:NO];
        }
    } else {
        //[advanced setState:NSOffState];
        if (frame.size.height != [window minSize].height) {
            frame.origin.y += [window maxSize].height - [window minSize].height;
            frame.size = [window minSize];
            [window setFrame:frame display:NO animate:NO];
        }
    }*/
    [cacheSize setIntValue:_cacheSize];
    if (_secureConnection) {
        [secureConnection setState:NSOnState];
    } else {
        [secureConnection setState:NSOffState];
    }
    [self secureConnection:nil];
    [securePort setIntValue:_securePort];
    [secureUser setStringValue:_secureUser];
    if (_proxy) {
        [proxy setState:NSOnState];
    } else {
        [proxy setState:NSOffState];
    }
    [self proxy:nil];
    [proxyServer setStringValue:_proxyServer];
    if (_proxyAuth) {
        [proxyAuthSwitch setState:NSOnState];
    } else {
        [proxyAuthSwitch setState:NSOffState];
    }
    [self proxyAuthSwitch:nil];
}

- (void)initAdvancedSettings {
    NSUserDefaults *def = [NSUserDefaults standardUserDefaults];
    _transcode = [def boolForKey:transcodeKey];
    _videoBitrate = [def integerForKey:videoBitrateKey];
    _framerate = [def floatForKey:framerateKey];
    _width = [def integerForKey:widthKey];
    _height = [def integerForKey:heightKey];
    _audioBitrate = [def integerForKey:audioBitrateKey];
    _sampleRate = [def integerForKey:sampleRateKey];
    _numberOfChannels = [def integerForKey:numberOfChannelsKey];
    _deinterlace = [def boolForKey:deinterlaceKey];
    _highQuality = [def boolForKey:highQualityKey];
    [self correctAdvancedSettings];
    if (_transcode) {
        [transcode setState:NSOnState];
    } else {
        [transcode setState:NSOffState];
    }
    [self transcode:nil];
    [videoBitrate setIntValue:_videoBitrate];
    if (_framerate == 0) {
        [framerate setStringValue:@""];
    } else {
        [framerate setFloatValue:_framerate];
    }
    if (_width == 0) {
        [width setStringValue:@""];
    } else {
        [width setIntValue:_width];
    }
    if (_height == 0) {
        [height setStringValue:@""];
    } else {
        [height setIntValue:_height];
    }
    [audioBitrate setIntValue:_audioBitrate];
    if (_sampleRate == 0) {
        [sampleRate setStringValue:@""];
    } else {
        [sampleRate setIntValue:_sampleRate];
    }
    if (_numberOfChannels == 0) {
        [numberOfChannels setStringValue:@""];
    } else {
        [numberOfChannels setIntValue:_numberOfChannels];
    }
    if (_deinterlace) {
        [deinterlace setState:NSOnState];
    } else {
        [deinterlace setState:NSOffState];
    }
    if (_highQuality) {
        [highQuality setState:NSOnState];
    } else {
        [highQuality setState:NSOffState];
    }
}

- (BOOL)validateSettings {
    int cacheSizeInt = [cacheSize intValue];
    BOOL secureConnectionBool = ([secureConnection state] == NSOnState);
    int securePortInt = [securePort intValue];
    NSString *secureUserString = [secureUser stringValue];
    BOOL proxyBool = ([proxy state] == NSOnState);
    NSString *proxyServerString = [proxyServer stringValue];
    if (cacheSizeInt < 128 || cacheSizeInt > 2000000) {
        [self displayError:@"The cache size must be between 128 and 2000000 KB."
              forWindow:window];
        return FALSE;
    }
    if (secureConnectionBool) {
        if (securePortInt < 1 || securePortInt > 65535) {
            [self displayError:@"The secure port must be between 1 and 65535."
                  forWindow:window];
            return FALSE;
        }
        if ([secureUserString length] == 0) {
            [self displayError:@"The secure username must not be empty."
                  forWindow:window];
            return FALSE;
        }
    }
    if (proxyBool) {
        if ([proxyServerString length] == 0) {
            [self displayError:@"The proxy server address must not be empty."
                  forWindow:window];
            return FALSE;
        }
        NSArray* proxyComponents = [proxyServerString componentsSeparatedByString:@":"];
        BOOL proxyError = FALSE;
        if ([proxyComponents count] != 2) {
            proxyError = TRUE;
        } else {
            if ([(NSString*)[proxyComponents objectAtIndex:0] length] == 0 ||
                [(NSString*)[proxyComponents objectAtIndex:1] length] == 0) {
                proxyError = TRUE;
            }
        }
        if (proxyError) {
            [self displayError:@"The proxy address must be specified as\n\nserver:port"
                  forWindow:window];
            return FALSE;
        }
    }
    _cacheSize = cacheSizeInt;
    _secureConnection = secureConnectionBool;
    _securePort = securePortInt;
    [_secureUser autorelease];
    _secureUser = [secureUserString retain];
    _proxy = proxyBool;
    [_proxyServer autorelease];
    _proxyServer = [proxyServerString retain];
    _proxyAuth = ([proxyAuthSwitch state] == NSOnState);
    [self correctSettings];

    NSUserDefaults *def = [NSUserDefaults standardUserDefaults];
    //[def setBool:_advanced forKey:advancedKey];
    [def setInteger:_cacheSize forKey:cacheSizeKey];
    [def setBool:_secureConnection forKey:secureConnectionKey];
    [def setInteger:_securePort forKey:securePortKey];
    [def setObject:_secureUser forKey:secureUserKey];
    [def setBool:_proxy forKey:proxyKey];
    [def setObject:_proxyServer forKey:proxyServerKey];
    [def setBool:_proxyAuth forKey:proxyAuthKey];

    [self initSettings];
    return TRUE;
}

- (BOOL)validateAdvancedSettings {
    BOOL transcodeBool = ([transcode state] == NSOnState);
    int videoBitrateInt = [videoBitrate intValue];
    float framerateFloat = [framerate floatValue];
    int widthInt = [width intValue];
    int heightInt = [height intValue];
    int audioBitrateInt = [audioBitrate intValue];
    int sampleRateInt = [sampleRate intValue];
    int numberOfChannelsInt = [numberOfChannels intValue];
    BOOL deinterlaceBool = ([deinterlace state] == NSOnState);
    BOOL highQualityBool = ([highQuality state] == NSOnState);
    if (transcodeBool) {
        if (videoBitrateInt < 32 || videoBitrateInt > 2000000) {
            [self displayError:@"The video bitrate must be a number greater than or equal to 32."
                  forWindow:advancedWindow];
            return FALSE;
        }
        if (framerateFloat != 0 && (framerateFloat < 1 || framerateFloat > 120)) {
            [self displayError:@"The framerate must be a number between 1 and 120."
                  forWindow:advancedWindow];
            return FALSE;
        }
        if (widthInt != 0 || heightInt != 0) {
            if (widthInt < 1 || widthInt > 65535) {
                if ([[width stringValue] length] == 0 && [[height stringValue] length] != 0) {
                    [self displayError:@"If you specify a height, you must also specify a width."
                          forWindow:advancedWindow];
                } else {
                    [self displayError:@"The width must be a number between 1 and 65535."
                          forWindow:advancedWindow];
                }
                return FALSE;
            }
            if (heightInt < 1 || heightInt > 65535) {
                if ([[height stringValue] length] == 0 && [[width stringValue] length] != 0) {
                    [self displayError:@"If you specify a width, you must also specify a height."
                          forWindow:advancedWindow];
                } else {
                    [self displayError:@"The height must be a number between 1 and 65535."
                          forWindow:advancedWindow];
                }
                return FALSE;
            }
        }
        if (audioBitrateInt < 32 || audioBitrateInt > 2000000) {
            [self displayError:@"The audio bitrate must be a number greater than or equal to 32."
                  forWindow:advancedWindow];
            return FALSE;
        }
        if (audioBitrateInt%32 != 0) {
            [self displayError:@"The audio bitrate must be divisible by 32."
                  forWindow:advancedWindow];
            return FALSE;
        }
        if (sampleRateInt != 0 && sampleRateInt != 22050 && sampleRateInt != 44100 &&
            sampleRateInt != 48000 && sampleRateInt != 96000) {
            [self displayError:@"The sample rate must be a 22050, 44100, 48000, or 96000."
                  forWindow:advancedWindow];
            return FALSE;
        }
        if (numberOfChannelsInt != 0 && (numberOfChannelsInt < 1 || numberOfChannelsInt > 2)) {
            [self displayError:@"The number of channels must be 1 or 2 (or empty to leave the original number alone)."
                  forWindow:advancedWindow];
            return FALSE;
        }
    }
    _transcode = transcodeBool;
    _videoBitrate = videoBitrateInt;
    _framerate = framerateFloat;
    _width = widthInt;
    _height = heightInt;
    _audioBitrate = audioBitrateInt;
    _sampleRate = sampleRateInt;
    _numberOfChannels = numberOfChannelsInt;
    _deinterlace = deinterlaceBool;
    _highQuality = highQualityBool;
    [self correctAdvancedSettings];

    NSUserDefaults *def = [NSUserDefaults standardUserDefaults];
    [def setBool:_transcode forKey:transcodeKey];
    [def setInteger:_videoBitrate forKey:videoBitrateKey];
    [def setFloat:_framerate forKey:framerateKey];
    [def setInteger:_width forKey:widthKey];
    [def setInteger:_height forKey:heightKey];
    [def setInteger:_audioBitrate forKey:audioBitrateKey];
    [def setInteger:_sampleRate forKey:sampleRateKey];
    [def setInteger:_numberOfChannels forKey:numberOfChannelsKey];
    [def setBool:_deinterlace forKey:deinterlaceKey];
    [def setBool:_highQuality forKey:highQualityKey];

    [self initAdvancedSettings];
    return TRUE;
}


/**
 * Create an URL fragment containing the specified transcode
 * settings.
 * Call this method only after a successful validation!
 */

- (NSString*)createTranscodeURLFragment {
    if (!_transcode) {
        return @"";
    }
    NSString* result = @"transcode=true";
    if (_videoBitrate != 0) {
        result = [result stringByAppendingString:
                  [NSString stringWithFormat:@"&videoBitrate=%i", (int)_videoBitrate]];
    }
    if (_framerate != 0) {
        result = [result stringByAppendingString:
                  [NSString stringWithFormat:@"&framerate=%f", (double)_framerate]];
    }
    if (_width != 0) {
        result = [result stringByAppendingString:
                  [NSString stringWithFormat:@"&width=%i", (int)_width]];
    }
    if (_height != 0) {
        result = [result stringByAppendingString:
                  [NSString stringWithFormat:@"&height=%i", (int)_height]];
    }
    if (_audioBitrate != 0) {
        result = [result stringByAppendingString:
                  [NSString stringWithFormat:@"&audioBitrate=%i", (int)_audioBitrate]];
    }
    if (_sampleRate != 0) {
        result = [result stringByAppendingString:
                  [NSString stringWithFormat:@"&sampleRate=%i", (int)_sampleRate]];
    }
    if (_numberOfChannels != 0) {
        result = [result stringByAppendingString:
                  [NSString stringWithFormat:@"&numberOfChannels=%i", (int)_numberOfChannels]];
    }
    if (_deinterlace) {
        result = [result stringByAppendingString:@"&deinterlace=true"];
    }
    if (_highQuality) {
        result = [result stringByAppendingString:@"&highQuality=true"];
    }
    return result;
}


- (IBAction)advanced:(id)sender {
    /*_advanced = !_advanced;
    NSRect frame = [window frame];
    if (_advanced) {
        frame.origin.y -= [window maxSize].height - [window minSize].height;
        frame.size = [window maxSize];
    } else {
        frame.origin.y += [window maxSize].height - [window minSize].height;
        frame.size = [window minSize];
    }
    // VINCENT
    [window setFrame:frame display:YES animate:YES];
    */
    [advancedWindow center];
    [advancedWindow makeKeyAndOrderFront:nil];
    [[NSApplication sharedApplication] runModalForWindow:advancedWindow];
}


- (IBAction)transcode:(id)sender {
    if ([transcode state] == NSOnState) {
        [videoBitrate setEnabled:TRUE];
        [framerate setEnabled:TRUE];
        [width setEnabled:TRUE];
        [height setEnabled:TRUE];
        [audioBitrate setEnabled:TRUE];
        [sampleRate setEnabled:TRUE];
        [numberOfChannels setEnabled:TRUE];
        [deinterlace setEnabled:TRUE];
        [highQuality setEnabled:TRUE];
    } else {
        [self validateEditing];
        [videoBitrate setEnabled:FALSE];
        [framerate setEnabled:FALSE];
        [width setEnabled:FALSE];
        [height setEnabled:FALSE];
        [audioBitrate setEnabled:FALSE];
        [sampleRate setEnabled:FALSE];
        [numberOfChannels setEnabled:FALSE];
        [deinterlace setEnabled:FALSE];
        [highQuality setEnabled:FALSE];
    }
}


- (IBAction)secureConnection:(id)sender {
    if ([secureConnection state] == NSOnState) {
        [secureUser setEnabled:TRUE];
        [securePort setEnabled:TRUE];
        [proxy setEnabled:TRUE];
        [self proxy:nil];
    } else {
        [secureUser setEnabled:FALSE];
        [securePort setEnabled:FALSE];
        [proxy setEnabled:FALSE];
        [proxyServer setEnabled:FALSE];
        [proxyAuth setEnabled:FALSE];
    }
}


- (IBAction)advancedOK:(id)sender {
    [self validateEditing];
    if ([self validateAdvancedSettings]) {
        [advancedWindow orderOut:nil];
        [[NSApplication sharedApplication] stopModal];
    }
}

- (IBAction)advancedCancel:(id)sender {
    [advancedWindow orderOut:nil];
    [self validateEditing];
    [self initAdvancedSettings];
    [[NSApplication sharedApplication] abortModal];
}

- (int)cacheSize {
    return _cacheSize;
}


- (BOOL)secureConnection {
    return _secureConnection;
}


- (int)securePort {
    return _securePort;
}


- (NSString*)secureUser {
    return _secureUser;
}


/**
 * Proxy stuff.
 */

- (IBAction)proxy:(id)sender {
    if ([proxy state] == NSOnState) {
        [proxyServer setEnabled:TRUE];
        [proxyAuth setEnabled:TRUE];
    } else {
        [proxyServer setEnabled:FALSE];
        [proxyAuth setEnabled:FALSE];
    }
}

- (IBAction)proxyAuthSwitch:(id)sender {
    if ([proxyAuthSwitch state] == NSOnState) {
        [proxyUser setEnabled:TRUE];
        [proxyPassword setEnabled:TRUE];
    } else {
        [proxyUser validateEditing];
        [proxyPassword validateEditing];
        [proxyUser setEnabled:FALSE];
        [proxyPassword setEnabled:FALSE];
    }
}

- (IBAction)proxyAuth:(id)sender {
    // read user and password (if present)
    NSData* proxyAuthData =
        [NSData dataWithContentsOfFile:
         [_proxyAuthFile stringByExpandingTildeInPath]];
    NSString* proxyAuthString =
        [[[NSString alloc] initWithData:proxyAuthData
                               encoding:NSUTF8StringEncoding]
         autorelease];
    NSArray* proxyAuthComponents =
        [proxyAuthString componentsSeparatedByString:@":"];
    if ([proxyAuthComponents count] == 2) {
        [proxyUser setStringValue:[proxyAuthComponents objectAtIndex:0]];
        [proxyPassword setStringValue:[proxyAuthComponents objectAtIndex:1]];
    } else {
        [proxyUser setStringValue:@""];
        [proxyPassword setStringValue:@""];
    }
    
    [proxyWindow center];
    [proxyWindow makeKeyAndOrderFront:nil];
    [[NSApplication sharedApplication] runModalForWindow:proxyWindow];
}


- (IBAction)proxyOK:(id)sender {
    [proxyUser validateEditing];
    [proxyPassword validateEditing];
    
    const char* cFileName = [[_proxyAuthFile stringByExpandingTildeInPath] cString];

    // try to remove the previous file
    // (to make sure we can create a new one with correct permissions);
    // this may fail, but we don't care (maybe there was no file) -
    // however, the following create will fail if there is a file
    // that could not be removed
    remove(cFileName);
    
    // create a new file with the correct permissions
    int fd = open(cFileName, O_CREAT | O_EXCL | O_TRUNC, 0600);
    if (fd > 0) {
        close(fd);
    } else {
        [self displayCriticalError:[NSString stringWithFormat:@"The file '%@' could not be created.",
                                    _proxyAuthFile]
              title:@"Cannot save proxy settings"
              forWindow:proxyWindow];
        return;
    }

    // write out the proxy settings
    NSString* proxySettings = [NSString stringWithFormat:@"%@:%@",
                                        [proxyUser stringValue],
                                        [proxyPassword stringValue]];
    if (![[proxySettings dataUsingEncoding:NSUTF8StringEncoding]
          writeToFile:[_proxyAuthFile stringByExpandingTildeInPath]
          atomically:YES]) {
        [self displayCriticalError:[NSString stringWithFormat:@"The file '%@' could not be saved.",
                                    _proxyAuthFile]
              title:@"Cannot save proxy settings"
              forWindow:proxyWindow];
        return;
    }
    
    [proxyWindow orderOut:nil];
    [[NSApplication sharedApplication] stopModal];

}

- (IBAction)proxyCancel:(id)sender {
    [proxyWindow orderOut:nil];
    [proxyUser validateEditing];
    [proxyPassword validateEditing];
    [[NSApplication sharedApplication] abortModal];
}

- (BOOL)proxy {
    return _proxy;
}

- (NSString*)proxyServer {
    return _proxyServer;
}

- (BOOL)proxyAuth {
    return _proxyAuth;
}

- (NSString*)proxyAuthFile {
    return [_proxyAuthFile stringByExpandingTildeInPath];
}

- (void)setManual {
    [manual setState:NSOnState];
    [manual setEnabled:FALSE];
    [ip setEnabled:TRUE];
    [window makeFirstResponder:ip];
}

- (IBAction)manual:(id)sender {
    [ip setEnabled:([manual state] == NSOnState)];
}

@end
