// Playground - noun: a place where people can play

import Cocoa

// Base class for parameters to POST to service
class APIParams {
    func getData() -> Dictionary<String, AnyObject> {
        return Dictionary<String, AnyObject>()
    }
}

// Base class for parsing a JSON Response
class APIResult {
    func parseData(data: AnyObject?) {
        
    }
}

// Derived example for a login service
class DerivedAPIParams: APIParams {
    var user = "some@one.com"
    var pass = "secret"
    
    // THIS METHOD IS CALLED CORRECTLY
    override func getData() -> Dictionary<String, AnyObject> {
        return [ "user": user, "pass": pass ]
    }
}

// Derived example for parsing a login response
class DerivedAPIResult: APIResult {
    var success = false
    var token:String? = ""
    
    // THIS METHOD IS NEVER CALLED
    override func parseData(data: AnyObject?) {
        /*
        self.success = data!.valueForKey("success") as Bool
        self.token = data!.valueForKey("token") as? String
        */
        
        self.success = true
        self.token = "1234"
    }
}

class APIOperation<TParams: APIParams, TResult: APIResult> {
    var url = "http://localhost:3000"
    
    func request(params: TParams, done: (NSError?, TResult?) -> ()) {
        let resultHandler = { (error: NSError?, response: NSHTTPURLResponse?, data: AnyObject?) -> () in
            if (error) {
                done(error, nil)
                return
            }
            
            let parsed = self.parseResult(data)
            
            done(nil, parsed)
        };
        
        let paramData = params.getData()
        
        // ... snip making a request to website ...
        
        let result = self.parseResult(nil)
        
        done(nil, result)
    }
    
    func parseResult(data: AnyObject?) -> TResult {
        var result = TResult.self()
        
        // This should call the derived implementation if passed, right?
        result.parseData(data)
        
        return result
    }
}

let derivedOp = APIOperation<DerivedAPIParams, DerivedAPIResult>()
let params = DerivedAPIParams()

derivedOp.request(params) {(error, result) in
    if result? {
        result!.success
    }
}