//
//  RecordingResponseHandler.m
//  CyTV
//
//  Created by Andreas Junghans on 29.12.07.
//  Copyright 2007 __MyCompanyName__. All rights reserved.
//

#import "RecordingStreamHandler.h"
#import "HTTPServer.h"
#import "RecordingInfo.h"


@implementation RecordingStreamHandler

- (void)dealloc {
    [NSObject cancelPreviousPerformRequestsWithTarget:self];
    if (_responseHandle != nil) {
        printf("File closed\n");
    }
    [_responseHandle closeFile];
    [_responseHandle release];
    [super dealloc];
}

- (void)handleRequest {
    NSString *idString = [_paramsDict objectForKey:@"id"];
    UInt64 idNumber;
    if (idString != nil) {
        NSScanner *idScanner = [NSScanner scannerWithString:idString];
        if (![idScanner scanLongLong:(long long *)&idNumber]) {
            idString = nil;
        }
    }
    NSString *searchString = [_paramsDict objectForKey:@"search"];
    RecordingInfo *recordingInfo = nil;
    if (idString != nil || searchString != nil) {
        int i;
        for (i = 0; i < 2; ++i) {
            if (idString != nil) {
                recordingInfo = [RecordingInfo getRecordingInfoById:idNumber];
            } else if (searchString != nil) {
                recordingInfo = [RecordingInfo getRecordingInfoBySearch:searchString];
            }
            if (recordingInfo == nil && i == 0) {
                [RecordingInfo collectRecordingInfo];
            } else {
                break;
            }
        }
    }
    if (recordingInfo != nil) {
        //NSString *answer = [NSString stringWithFormat:@"Recording found: %@", [recordingInfo getTitle]];
        //const char *answerUTF8 = [answer UTF8String];
        //NSData *answerData = [NSData dataWithBytes:answerUTF8 length:strlen(answerUTF8)];
        NSString *videoFilePath = [recordingInfo getVideoFilePath];
        printf("Video file path: %s\n", [videoFilePath UTF8String]);
        NSDictionary *fileAttributes = [[NSFileManager defaultManager] fileAttributesAtPath:videoFilePath traverseLink:YES];
        if (fileAttributes != nil) {
            printf("File attributes found\n");
            unsigned long long fileSize = [fileAttributes fileSize];
            
            CFIndex statusCode = 200;
            _responseRange.rangeStart = 0;
            _responseRange.rangeEnd = fileSize;
            NSString *range = [(NSString *)CFHTTPMessageCopyHeaderFieldValue(_request, CFSTR("Range")) autorelease];
            if (range != nil && [range hasPrefix:@"bytes="] && fileSize > 0) {
                NSArray *rangeParts = [[range substringFromIndex:6] componentsSeparatedByString:@"-"];
                if ([rangeParts count] > 0) {
                    statusCode = 206;
                    NSScanner *scanner = [NSScanner scannerWithString:[rangeParts objectAtIndex:0]];
                    long long value = 0;
                    [scanner scanLongLong:&value];
                    _responseRange.rangeStart = value;
                    if ([rangeParts count] > 1) {
                        scanner = [NSScanner scannerWithString:[rangeParts objectAtIndex:1]];
                        value = fileSize - 1;
                        [scanner scanLongLong:&value];
                        _responseRange.rangeEnd = value + 1;
                    }
                }
                if (_responseRange.rangeStart >= fileSize || _responseRange.rangeEnd > fileSize ||
                    _responseRange.rangeEnd <= _responseRange.rangeStart) {
                    
                    // Status Code 400 - Bad Request
                    [ResponseHandler writeResponseWithCode:400 content:nil socket:_asyncSocket timeout:WRITE_ERROR_TIMEOUT];
                    return;
                }
            }
            unsigned long long contentLength = _responseRange.rangeEnd - _responseRange.rangeStart;
            
            CFHTTPMessageRef response = CFHTTPMessageCreateResponse(kCFAllocatorDefault, statusCode, NULL, kCFHTTPVersion1_1);
            NSString *contentLengthString = [[NSNumber numberWithUnsignedLongLong:contentLength] stringValue];
            CFHTTPMessageSetHeaderFieldValue(response, CFSTR("Content-Length"), (CFStringRef)contentLengthString);
            CFHTTPMessageSetHeaderFieldValue(response, CFSTR("Content-Type"), CFSTR("video/mpeg"));
            if (statusCode == 206) {
                CFHTTPMessageSetHeaderFieldValue(response, CFSTR("Content-Range"),
                                                 (CFStringRef)[NSString stringWithFormat:@"bytes %llu-%llu/%llu",
                                                     _responseRange.rangeStart,
                                                     _responseRange.rangeEnd - 1,
                                                     contentLength]);
            }
            NSData *responseData = [(NSData *)CFHTTPMessageCopySerializedMessage(response) autorelease];
            if (contentLength == 0) {
                [_asyncSocket writeData:responseData withTimeout:WRITE_BODY_TIMEOUT tag:HTTP_RESPONSE];
            } else {
                printf("File opened\n");
                _responseHandle = [[NSFileHandle fileHandleForReadingAtPath:videoFilePath] retain];
                [_responseHandle seekToFileOffset:_responseRange.rangeStart];
                [_asyncSocket writeData:responseData withTimeout:WRITE_BODY_TIMEOUT tag:HTTP_PARTIAL_RESPONSE];
            }
            CFRelease(response);
            return;
        }
    }

    [ResponseHandler writeResponseWithCode:404 content:@"Not found" socket:_asyncSocket timeout:WRITE_ERROR_TIMEOUT];
}

- (void)onSocketCanWrite:(AsyncSocket *)sock {
    if (_responseHandle != nil) {
        //printf("Can write (handle != nil)\n");
        NSData *data = [_responseHandle readDataOfLength:18800];
        if ([_responseHandle offsetInFile] >= _responseRange.rangeEnd) {
            [_asyncSocket writeData:data withTimeout:WRITE_BODY_TIMEOUT tag:HTTP_RESPONSE];
        } else {
            [_asyncSocket writeData:data withTimeout:WRITE_BODY_TIMEOUT tag:HTTP_PARTIAL_RESPONSE];
        }
    }
}

@end
