//
//  PacServer.swift
//  taichi-iOS
//
//  Created by taichi on 15/4/21.
//  Copyright (c) 2015 taichi. All rights reserved.
//

import Foundation

class PacServer
{
    
    class var sharedInstance: PacServer {
        struct Static {
            static var instance: PacServer? = nil
        }
        if Static.instance == nil {
            Static.instance = PacServer()
        }
        return Static.instance!
    }

    var gfwlist = ["twitter.com","facebook.com","youtube.com"]
    
    private var server = HttpServer()
    
    var socks5Port = 1080
    
    var originContentJS: String? = nil
    
    var partPacJS: String {
        if originContentJS != nil {
            return originContentJS!
        }
        
        let head = "// Generated by gfwlist2pac\r\n// https://github.com/clowwindy/gfwlist2pac\r\n\r\nvar proxy = \"SOCKS5 127.0.0.1:\(socks5Port); SOCKS 127.0.0.1:\(socks5Port); DIRECT\";\r\nvar domains = {\r\n";
        
        var gfwStrings = ""
        for domain in gfwlist {
            gfwStrings += "    \"\(domain)\": 1,\r\n"
        }
        gfwStrings += "    \"google.com\": 1"
        
        let tail = "\r\n};\r\nvar direct = 'DIRECT;';\r\nvar hasOwnProperty = Object.hasOwnProperty;\r\n"
    
        var findProxyForURL = ""
        findProxyForURL += "\r\nfunction FindProxyForURL(url, host) {                           "
        findProxyForURL += "\r\n    var suffix;                                                 "
        findProxyForURL += "\r\n    var pos = host.lastIndexOf('.');                            "
        findProxyForURL += "\r\n    pos = host.lastIndexOf('.', pos - 1);                       "
        findProxyForURL += "\r\n    while(1) {                                                  "
        findProxyForURL += "\r\n        if (pos <= 0) {                                         "
        findProxyForURL += "\r\n            if (hasOwnProperty.call(domains, host)) {           "
        findProxyForURL += "\r\n                return proxy;                                   "
        findProxyForURL += "\r\n            } else {                                            "
        findProxyForURL += "\r\n                return direct;                                  "
        findProxyForURL += "\r\n            }                                                   "
        findProxyForURL += "\r\n        }                                                       "
        findProxyForURL += "\r\n        suffix = host.substring(pos + 1);                       "
        findProxyForURL += "\r\n        if (hasOwnProperty.call(domains, suffix)) {             "
        findProxyForURL += "\r\n            return proxy;                                       "
        findProxyForURL += "\r\n        }                                                       "
        findProxyForURL += "\r\n        pos = host.lastIndexOf('.', pos - 1);                   "
        findProxyForURL += "\r\n    }                                                           "
        findProxyForURL += "\r\n}                                                               "

        return head + gfwStrings + tail + findProxyForURL
    }

    var allPacJS: String {
        return "function FindProxyForURL(url, host){\r\n\tif (isInNet(host, \"192.168.1.0\", \"255.255.255.0\"))\r\n\t\treturn \"DIRECT\";\r\n\treturn \"SOCKS5 127.0.0.1:\(socks5Port); SOCKS 127.0.0.1:\(socks5Port); DIRECT\";\r\n}"
    }
    
    func start(listenPort: in_port_t = 8080, error: NSErrorPointer = nil) -> Bool
    {
        if let path = NSBundle.mainBundle().pathForResource("proxy.pac", ofType: nil) {
            let content = NSString(contentsOfFile: path, encoding: NSUTF8StringEncoding, error: nil)
            originContentJS = content as? String
            if originContentJS != nil {
                originContentJS = "var proxy = \"SOCKS5 127.0.0.1:\(socks5Port); SOCKS 127.0.0.1:\(socks5Port); DIRECT;\"\r\n" + originContentJS!
            }
        }
        server["/all.pac"] = { .OK(.RAW("//" + $0.url + "\r\n" + self.allPacJS )) }
        server["/part.pac"] = { .OK(.RAW("//" + $0.url + "\r\n" + self.partPacJS )) }
        return server.start(listenPort: listenPort, error: error)
    }
    
    func stop()
    {
        server.stop()
    }
}