/*
 * ADOBE CONFIDENTIAL
 *
 * Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Adobe Systems Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Adobe Systems Incorporated and its
 * suppliers and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Adobe Systems Incorporated.
 */

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, bitwise: true, node: true */
/*global define: true, require:true, _:true, $:true, module: true, VulcanInterface, VulcanMessage */

"use strict";

var Q = require("q"),
    _ = require("underscore");

//Reference for API
//https://wiki.corp.adobe.com/pages/viewpage.action?spaceKey=Suites&title=CoreSync+and+Third+Party+Vulcan+Client+Interface

var generateCallerId = function () {
    // GUID discussions: http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
    var extensionID = global.__adobe_cep__.getExtensionId(),
        guid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
            var r = Math.random() * 16 | 0,
                v = c === "x" ? r : (r & 0x3 | 0x8);
            return v.toString(16);
        });
    return guid + "_" + extensionID;
};

var getBundleId = function () {
    return global.__adobe_cep__.invokeSync("getBundleId", "");
};

function CoreSyncMessenger(callerId, bundleId) {
    this.callerID = callerId;
    this.bundleID = bundleId;
    this.handleVulcanMessage = this.handleVulcanMessage.bind(this);
    this.registerResponseListeners();
}

CoreSyncMessenger.prototype.WEB_ROOT_MESSAGE_TYPE = "cosy.files.GetRootFolderRequest";
CoreSyncMessenger.prototype.SHOW_IN_WEB_MESSAGE_TYPE = "cosy.files.ShowPathInWebRequest";

CoreSyncMessenger.prototype.registerResponseListeners = function () {
    VulcanInterface.addMessageListener("vulcan.SuiteMessage.cosy.files.GetRootFolderResponse", this.handleVulcanMessage);
    VulcanInterface.addMessageListener("vulcan.SuiteMessage.cosy.files.ShowPathInWebResponse", this.handleVulcanMessage);
};

CoreSyncMessenger.prototype.parseResponse = function (message) {
    var result = {},
        outerWrapperDom = $.parseXML(message.data);
    
    if (!outerWrapperDom) {
        result.status = "error";
        result.message = "Could not parse outer wrapper";
        return result;
    }
    
    var $payload = $("payload", outerWrapperDom);
    if (!$payload.length) {
        return result;
    }
    
    var decodedPayload = global.cep.encoding.convertion.b64_to_utf8($payload.text()),
        payloadDom = $.parseXML(decodedPayload);
    if (!payloadDom) {
        result.status = "error";
        result.message = "Could not parse payload";
        return result;
    }
    
    var $response = $("response", payloadDom),
        childNodes = $response.children(),
        len = childNodes.length,
        i,
        curNode;
    
    for (i = 0; i < len; i++) {
        curNode = childNodes[i];
        result[curNode.nodeName] = $(curNode).text();
    }
    return result;
};

CoreSyncMessenger.prototype.handleGetRootFolderResponse = function (message) {
    if (!this.getRootFolderDeferred) {
        return;
    }
    var result = this.parseResponse(message);
    if (result.status !== "success") {
        this.getRootFolderDeferred.reject("status: " + result.status);
        this.getRootFolderDeferred = null;
    } else if (result.requestid === this.callerID) {
        this.getRootFolderDeferred.resolve(result.rootfolder);
        this.getRootFolderDeferred = null;
    }
};

CoreSyncMessenger.prototype.handleShowPathInWebResponse = function (message) {
    if (!this.showPathInWebDeferred) {
        return;
    }
    var result = this.parseResponse(message);
    if (result.status !== "success") {
        this.showPathInWebDeferred.reject("status: " + result.status);
        this.showPathInWebDeferred = null;
    } else if (result.requestid === this.callerID) {
        this.showPathInWebDeferred.resolve();
        this.showPathInWebDeferred = null;
    }
};

CoreSyncMessenger.prototype.handleVulcanMessage = function (message) {
    if (message && message.type === "vulcan.SuiteMessage.cosy.files.GetRootFolderResponse") {
        this.handleGetRootFolderResponse(message);
    } else if (message && message.type === "vulcan.SuiteMessage.cosy.files.ShowPathInWebResponse") {
        this.handleShowPathInWebResponse(message);
    }
};

CoreSyncMessenger.prototype.formatRequestPayload = function (params) {
    var tags = _.map(params, function (val, key) {
        return "<" + key + ">" + val + "</" + key + ">";
    });
    return "<request>" + tags.join("") + "</request>";
};

CoreSyncMessenger.prototype.getRootFolder = function () {
    if (this.getRootFolderDeferred) {
        return this.getRootFolderDeferred.promise;
    }
    this.getRootFolderDeferred = Q.defer();
    module.exports._cachedLocalRoot = "";
    this.getRootFolderDeferred.promise.then(function (root) {
        module.exports._cachedLocalRoot = root;
    });
    
    var msg = new VulcanMessage(VulcanMessage.TYPE_PREFIX + this.WEB_ROOT_MESSAGE_TYPE),
        payload = {
            type: this.WEB_ROOT_MESSAGE_TYPE,
            requestid: this.callerID
        };
    msg.setPayload(this.formatRequestPayload(payload));
    VulcanInterface.dispatchMessage(msg);
    
    return this.getRootFolderDeferred.promise;
};

CoreSyncMessenger.prototype.showPathInExtract = function (fullpath) {
    if (this.showPathInWebDeferred) {
        return this.showPathInWebDeferred.promise;
    }
    if (!module.exports._cachedLocalRoot) {
        return Q.reject("no local root");
    }
    this.showPathInWebDeferred = Q.defer();
    
    var msg = new VulcanMessage(VulcanMessage.TYPE_PREFIX + this.SHOW_IN_WEB_MESSAGE_TYPE),
        payload = {
            type: this.SHOW_IN_WEB_MESSAGE_TYPE,
            requestid: this.callerID,
            action: "extract",
            localpath: module.exports._getRelativePath(module.exports._cachedLocalRoot, fullpath)
        };
    msg.setPayload(this.formatRequestPayload(payload));
    VulcanInterface.dispatchMessage(msg);
    
    return this.showPathInWebDeferred.promise;
};

var getMessenger = function () {
    if (!module.exports._cachedMessenger) {
        module.exports._cachedMessenger = new CoreSyncMessenger(generateCallerId(), getBundleId());
    }
    return module.exports._cachedMessenger;
};

var _pathIsUnderRoot = function (path, root) {
    return path.indexOf(root) === 0;
};

var _getRelativePath = function (root, path) {
    var rel = path;
    if (module.exports._pathIsUnderRoot(path, root)) {
        rel = path.substr(root.length);
    }
    return rel.replace(/\\/g, '/');
};

var canOpenFileInExtractWeb = function (path) {
    var messenger = module.exports._getMessenger(),
        serverPromise = messenger.getRootFolder();
    return serverPromise.then(module.exports._pathIsUnderRoot.bind(null, path));
};

var openFileInExtractWeb = function (path) {
    var messenger = module.exports._getMessenger(),
        serverPromise = messenger.showPathInExtract(path);
    
    return serverPromise;
};


module.exports.canOpenFileInExtractWeb = canOpenFileInExtractWeb;
module.exports.openFileInExtractWeb = openFileInExtractWeb;
module.exports._pathIsUnderRoot = _pathIsUnderRoot;
module.exports._getRelativePath = _getRelativePath;
module.exports._CoreSyncMessenger = CoreSyncMessenger;
module.exports._getMessenger = getMessenger;
module.exports._cachedMessenger = null;
module.exports._cachedLocalRoot = "";
