// host.js
//
// data object representing a remote host
//
// Copyright 2013, StatusNet Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

var _ = require("underscore"),
    wf = require("webfinger"),
    async = require("async"),
    qs = require("querystring"),
    OAuth = require("oauth").OAuth,
    DatabankObject = require("databank").DatabankObject,
    OpenFarmGame = require("./openfarmgame"),
    RequestToken = require("./requesttoken");

var Host = DatabankObject.subClass("host");

var OAUTH_RT = "http://apinamespace.org/oauth/request_token",
    OAUTH_AT = "http://apinamespace.org/oauth/access_token",
    OAUTH_AUTHZ = "http://apinamespace.org/oauth/authorize",
    WHOAMI = "http://apinamespace.org/activitypub/whoami",
    OAUTH_CRED = "registration_endpoint";

Host.schema = {
    pkey: "hostname",
    fields: ["client_id",
             "client_secret",
             "registration_endpoint",
             "request_token_endpoint",
             "access_token_endpoint",
             "authorization_endpoint",
             "whoami_endpoint",
             "created",
             "updated"]
};

Host.ensureHost = function(hostname, callback) {
    Host.get(hostname, function(err, host) {
        if (err && err.name == "NoSuchThingError") {
            Host.discover(hostname, callback);
        } else if (err) {
            callback(err, null);
        } else {
            // XXX: update endpoints?
            callback(null, host);
        }
    });
};

Host.discover = function(hostname, callback) {

    var props = {
        hostname: hostname
    };

    async.waterfall([
        function(callback) {
            wf.hostmeta(hostname, callback);
        },
        function(jrd, callback) {
            var rels = {
                registration_endpoint: OAUTH_CRED,
                request_token_endpoint: OAUTH_RT,
                access_token_endpoint: OAUTH_AT,
                authorization_endpoint: OAUTH_AUTHZ,
                whoami_endpoint: WHOAMI
            },
                prop,
                rel;

            for (prop in rels) {
                rel = rels[prop];
                var links = _.where(jrd.links, {rel: rel});
                if (links.length === 0) {
                    callback(new Error(hostname + " does not implement " + rel), null);
                    return;
                } else {
                    props[prop] = links[0].href;
                }
            }

            Host.getCredentials(props.registration_endpoint, callback);
        },
        function(cred, callback) {
            props.client_id = cred.client_id;
            props.client_secret = cred.client_secret;
            Host.create(props, callback);
        }
    ], callback);
};

Host.getCredentials = function(endpoint, callback) {
    async.waterfall([
        function(callback) {
            var body = qs.stringify({type: "client_associate",
                                     application_type: "web",
                                     application_name: "Open Farm Game",
                                     redirect_uris: OpenFarmGame.url("/authorized")});

            Host.dialbackClient.post(endpoint,
                                     OpenFarmGame.hostname,
                                     body,
                                     "application/x-www-form-urlencoded",
                                     callback);
        }
    ], function(err, response, doc) {
        var client;
        if (err) {
            callback(err, null);
        } else if (response.statusCode >= 400 && response.statusCode < 600) {
            callback(new Error("HTTP Error " + response.statusCode + ": " + doc), null);
        } else if (!response.headers["content-type"]) {
            callback(new Error("No content type"), null);
        } else if (response.headers["content-type"].substr(0, "application/json".length) != "application/json") {
            callback(new Error("Bad content type: " + response.headers["content-type"]), null);
        } else {
            try {
                client = JSON.parse(doc);
                callback(null, client);
            } catch (e) {
                callback(e, null);
            }
        }
    });
};

Host.prototype.getRequestToken = function(callback) {
    var host = this,
        oa = host.getOAuth();

    async.waterfall([
        function(callback) {
            oa.getOAuthRequestToken(callback);
        },
        function(token, secret, other, callback) {
            RequestToken.create({token: token,
                                 secret: secret,
                                 hostname: host.hostname},
                                callback);
        }
    ], callback);
};

Host.prototype.authorizeURL = function(rt, callback) {
    var host = this,
        separator;

    if (_.contains(host.authorization_endpoint, "?")) {
        separator = "&";
    } else {
        separator = "?";
    }
    
    return host.authorization_endpoint + separator + "oauth_token=" + rt.token;
};

Host.prototype.getAccessToken = function(rt, verifier, callback) {
    var host = this,
        oa = host.getOAuth();

    oa.getOAuthAccessToken(rt.token, rt.secret, verifier, callback);
};

Host.prototype.whoami = function(token, secret, callback) {
    var host = this,
        oa = host.getOAuth();

    // XXX: ssl

    async.waterfall([
        function(callback) {
            oa.get(host.whoami_endpoint, token, secret, callback);
        }
    ], function(err, doc, response) {
        var obj;
        if (err) {
            callback(err, null);
        } else {
            try {
                obj = JSON.parse(doc);
                callback(null, obj);
            } catch(e) {
                callback(e, null);
            }
        }
    });
};

Host.prototype.getOAuth = function() {

    var host = this;

    return new OAuth(host.request_token_endpoint,
                     host.access_token_endpoint,
                     host.client_id,
                     host.client_secret,
                     "1.0",
                     OpenFarmGame.url("/authorized/"+host.hostname),
                     "HMAC-SHA1",
                     null, // nonce size; use default
                     {"User-Agent": "openfarmgame.com/0.1.0"});
};

module.exports = Host;

@@ -867,27 +867,23 @@
 ct,%0A    
-OpenFarmGam
+PumpLiv
 e = requ
@@ -889,27 +889,23 @@
 uire(%22./
-openfarmgam
+pumpliv
 e%22),%0A   
@@ -3517,21 +3517,16 @@
 e: %22
-Open Farm Gam
+Pump Liv
 e%22,%0A
@@ -3577,27 +3577,23 @@
 t_uris: 
-OpenFarmGam
+PumpLiv
 e.url(%22/
@@ -3693,27 +3693,23 @@
         
-OpenFarmGam
+PumpLiv
 e.hostna
@@ -6563,19 +6563,15 @@
     
-OpenFarmGam
+PumpLiv
 e.ur
@@ -6732,19 +6732,15 @@
 %22: %22
-openfarmgam
+pumpliv
 e.co

Use pumplive