//
//  MyHTTPServer.m
//  CyTV
//
//  Created by Andreas Junghans on 18.12.07.
//  Copyright 2007-2008 Andreas Junghans. All rights reserved.
//

#import "MyHTTPConnection.h"
#import "AsyncSocket.h"
#import "RecordingStreamHandler.h"
#import "LiveStreamHandler.h"
#import "RecordingInfoHandler.h"
#import "TranscodingHandler.h"
#import "RecordingPreviewPictureHandler.h"
#import "GUIFileHandler.h"
#import "ChannelInfoHandler.h"
#import "SetChannelActionHandler.h"


@implementation MyHTTPConnection

- (id)initWithAsyncSocket:(AsyncSocket *)newSocket forServer:(HTTPServer *)myServer
{
	if(self = [super initWithAsyncSocket:newSocket forServer:myServer])
	{
        //printf("New connection %lx\n", (unsigned long)newSocket);
    }
    return self;
}

- (void)dealloc {
    [_responseHandler shutDownAndRelease];
    [super dealloc];
}

- (NSDictionary *)createParamsDictFromString:(NSString *)queryString {
    NSMutableDictionary *dict = [[[NSMutableDictionary alloc] init] autorelease];
    if (queryString != nil) {
        NSArray *params = [queryString componentsSeparatedByString:@"&"];
        int i;
        for (i = 0; i < [params count]; ++i) {
            NSArray *keyAndValue = [[params objectAtIndex:i] componentsSeparatedByString:@"="];
            if ([keyAndValue count] == 2) {
                NSString *key = [[keyAndValue objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
                NSString *value = [[keyAndValue objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
                [dict setObject:value forKey:key];
            }
        }
    }
    return dict;
}

/**
 * This method is called after a full HTTP request has been received.
 * The current request is in the CFHTTPMessage request variable.
 **/
- (void)writeResponseForURI:(NSURL *)uri method:(NSString *)method {
    [_responseHandler shutDownAndRelease];  // we shouldn't have a response handler at this point,
    _responseHandler = nil;                 // but better be safe
    
    // Respond properly to HTTP 'GET' commands
    if([method isEqualToString:@"GET"]) {
        NSString *path = [uri path];
        NSString *query = [uri query];
        NSDictionary *paramsDict = [self createParamsDictFromString:query];
        
        NSString *transcodeString = [paramsDict objectForKey:@"transcode"];
        BOOL transcode = FALSE;
        if (transcodeString != nil) {
            NSComparisonResult result = [transcodeString compare:@"true" options:NSCaseInsensitiveSearch];
            if (result == NSOrderedSame) {
                transcode = TRUE;
            }
        }
        if (transcode) {
            _responseHandler = [[TranscodingHandler alloc] init];
        } else if ([path isEqualToString:@"/stream/recording"]) {
            _responseHandler = [[RecordingStreamHandler alloc] init];
        } else if ([path isEqualToString:@"/stream/live"]) {
            _responseHandler = [[LiveStreamHandler alloc] init];
        } else if ([path isEqualToString:@"/info/recordings"]) {
            _responseHandler = [[RecordingInfoHandler alloc] init];
        } else if ([path isEqualToString:@"/info/channels"]) {
            _responseHandler = [[ChannelInfoHandler alloc] init];
        } else if ([path isEqualToString:@"/previewpicture/recording"] || [path isEqualToString:@"/previewpicture/live"]) {
            _responseHandler = [[RecordingPreviewPictureHandler alloc] init];
        } else if ([path isEqualToString:@"/action/setchannel"]) {
            _responseHandler = [[SetChannelActionHandler alloc] init];
        } else if ([path hasPrefix:@"/gui/"]) {
            _responseHandler = [[GUIFileHandler alloc] init];
        } else if ([path isEqualToString:@"/"] || [path isEqualToString:@"/gui"] || [path isEqualToString:@"/gui/"]) {
            CFHTTPMessageRef response = CFHTTPMessageCreateResponse(kCFAllocatorDefault, 302, NULL, kCFHTTPVersion1_1);
            CFHTTPMessageSetHeaderFieldValue(response, CFSTR("Content-Length"), CFSTR("0"));
            CFHTTPMessageSetHeaderFieldValue(response, CFSTR("Location"), CFSTR("/gui/index.html"));
            NSData *responseData = [(NSData *)CFHTTPMessageCopySerializedMessage(response) autorelease];
            [asyncSocket writeData:responseData withTimeout:WRITE_BODY_TIMEOUT tag:HTTP_RESPONSE];
            return;
        }
        if (_responseHandler != nil) {
            [_responseHandler setRequest:request];
            [_responseHandler setURI:uri];
            [_responseHandler setMethod:method];
            [_responseHandler setPath:path];
            [_responseHandler setQuery:query];
            [_responseHandler setParamsDict:paramsDict];
            [_responseHandler setAsyncSocket:asyncSocket];
            [_responseHandler handleRequest];
        } else {
            [ResponseHandler writeResponseWithCode:404 content:@"Not found" socket:asyncSocket timeout:WRITE_ERROR_TIMEOUT];
        }
    } else {
        NSLog(@"HTTP Server: Error 405 - Method Not Allowed: %@", method);
        
        // Status code 405 - Method Not Allowed
        [ResponseHandler writeResponseWithCode:405 content:nil socket:asyncSocket timeout:WRITE_ERROR_TIMEOUT];
    }
}

- (void)onSocketCanWrite:(AsyncSocket *)sock {
    [_responseHandler onSocketCanWrite:sock];
}

- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag {
    if (tag == HTTP_RESPONSE) {
        //printf("Response written\n");
        [_responseHandler shutDownAndRelease];
        _responseHandler = nil;
    }
    [super onSocket:sock didWriteDataWithTag:tag];
}

- (void)onSocketDidDisconnect:(AsyncSocket *)sock {
    //printf("Disconnect\n");
    [_responseHandler shutDownAndRelease];
    _responseHandler = nil;
    [super onSocketDidDisconnect:sock];
}

@end
