//
//  URLFetcher.m
//  LeakTest
//
//  Created by Andreas Junghans on Sat Nov 15 2003.
//  Copyright (c) 2003-2004 Andreas Junghans. All rights reserved.
//

#import "URLFetcher.h"

#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

@implementation URLFetcher

/**
 * Initializes this instance.
 */

- (id)init {
    if (self = [super init]) {
        _unlockToStart = [[NSLock alloc] init];
        [_unlockToStart lock];
        _unlockToStop = [[NSLock alloc] init];
        [_unlockToStop lock];
        //_accessLock = [[NSLock alloc] init];
        [NSThread detachNewThreadSelector: @selector(run:)
                  toTarget: self
                  withObject: nil];
        return self;
    }
    return nil;
}


/**
 * Handles a request.
 */

- (void)handleRequest {
    [_unlockToStart lock];
    _receivedData = [[NSMutableData data] retain];
    [NSURLConnection connectionWithRequest:_request delegate:self];
}


/**
 * Main run loop (run in a separate thread).
 */

- (void)run:(id)param {
    NSAutoreleasePool* pool;
    
    // make sure we have an autorelease pool
    pool = [[NSAutoreleasePool alloc] init];

    // wait for the first request
    [self handleRequest];
    
    // enter the run loop
    [[NSRunLoop currentRunLoop] run];

    // in case the loop ever exits
    // (which it usually doesn't), release the pool
    [pool release];
}


/**
 * Fetches the contents of an URL.
 */

- (NSString *)fetchURL:(NSString *)url {
    //[_accessLock lock];
    // remove the comment to make this method thread-safe
    // (or better yet, derive a thread-safe sub class)
    
    // handle weird OS X problem: if the request is local
    // and making the connection fails, Internet Connect is
    // popped up; to prevent this, first check if a connection
    // can be made
    if ([url hasPrefix:@"http://127.0.0.1:"]) {
        struct sockaddr_in check;
        bzero(&check, sizeof(check));
        check.sin_len = sizeof(check);
        check.sin_family = AF_INET;
        check.sin_addr.s_addr = INADDR_LOOPBACK;
        int portNumber = [[[url componentsSeparatedByString:@":"] objectAtIndex:2] intValue];
        check.sin_port = htons(portNumber);
        int mysocket = socket(AF_INET, SOCK_STREAM, 0);
        int success = connect(mysocket, (struct sockaddr*)&check, sizeof(check));
        close(mysocket);
        if (success != 0) {
            return @"";
        }
    }
    
    _request = [NSURLRequest requestWithURL: [NSURL URLWithString: url]];
    [_unlockToStart unlock];
    [_unlockToStop lock];
    NSString* retVal = [[_response retain] autorelease];
        // make sure the response won't be
        // released by the other thread's
        // autorelease pool
    //[_accessLock unlock];
    return retVal;
}


/**
 * Delegate methods.
 */

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    //printf("connection:didReceiveAuthenticationChallange:\n");
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    //printf("connection:didReceiveData:\n");
    [_receivedData appendData:data];
}

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    //printf("connection:didReceiveResponse:\n");
    [_receivedData setLength:0];
}

-(NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse {
    //printf("connection:willCacheResponse:\n");
    return nil;
}

-(NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse {
    //printf("connection:willSendRequest:redirectResponse:\n");
    return request;
}

-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
    //printf("connectionDidFinishLoading\n");
    _response = [[[NSString alloc] initWithBytes: [_receivedData bytes]
                                   length: [_receivedData length]
                                   encoding: NSUTF8StringEncoding] autorelease];
    [_receivedData release];
    [_unlockToStop unlock];
    [self handleRequest];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    //printf("connection:didFailWithError: %s\n", [[error localizedDescription] cString]);
    _response = @"";
    [_receivedData release];
    [_unlockToStop unlock];
    [self handleRequest];
}

@end
