"use strict";
var _ = require("./lodash.custom");
var fs = require("fs");
var config = require("./config");
function getPath(options, relative, port) {
    if (options.get("mode") === "snippet") {
        return options.get("scheme") + "://HOST:" + port + relative;
    }
    else {
        return "//HOST:" + port + relative;
    }
}
var connectUtils = {
    /**
     * @param {Immutable.Map} options
     * @returns {String}
     */
    scriptTags: function (options) {
        var scriptPath = this.clientScript(options);
        var async = options.getIn(["snippetOptions", "async"]);
        var scriptDomain = options.getIn(["script", "domain"]);
        /**
         * Generate the [src] attribute based on user options
         */
        var scriptSrc = (function () {
            if (options.get("localOnly")) {
                return [
                    options.get("scheme"),
                    "://localhost:",
                    options.get("port"),
                    scriptPath
                ].join("");
            }
            /**
             * First, was "scriptPath" set? if so the user wanted full control over the
             * script tag output
             *
             */
            if (_.isFunction(options.get("scriptPath"))) {
                return options
                    .get("scriptPath")
                    .apply(null, getScriptArgs(options, scriptPath));
            }
            /**
             * Next, if "script.domain" was given, allow that + the path to the JS file
             * eg:
             *  script.domain=localhost:3000
             * -> localhost:3000/browser-sync/browser-sync-client.js
             */
            if (scriptDomain) {
                if (_.isFunction(scriptDomain)) {
                    return scriptDomain.call(null, options) + scriptPath;
                }
                if (scriptDomain.match(/\{port\}/)) {
                    return (scriptDomain.replace("{port}", options.get("port")) +
                        scriptPath);
                }
                return scriptDomain + scriptPath;
            }
            /**
             * Now if server or proxy, use dynamic script
             * eg:
             *  browser-sync start --server
             * ->
             *  "HOST:3000/browser-sync/browser-sync-client.js".replace("HOST", location.hostname)
             */
            if (options.get("server") || options.get("proxy")) {
                return scriptPath;
            }
            /**
             * Final use case is snippet mode
             * -> "http://HOST:3000/browser-sync/browser-sync-client.js".replace("HOST", location.hostname)
             * -> "//HOST:3000/browser-sync/browser-sync-client.js".replace("HOST", location.hostname)"
             */
            return getPath(options, scriptPath, options.get("port"));
        })();
        /**
         * Decide which template shall be used to generate the script tags
         */
        var template = (function () {
            if (scriptDomain || options.get("localOnly")) {
                return config.templates.scriptTagSimple;
            }
            return config.templates.scriptTag;
        })();
        /**
         * Finally read the template file from disk and replace
         * the dynamic values.
         */
        return fs
            .readFileSync(template, "utf8")
            .replace("%script%", scriptSrc)
            .replace("%async%", async ? "async" : "");
    },
    /**
     * @param {Map} options
     * @returns {String}
     */
    socketConnector: function (options) {
        var socket = options.get("socket");
        var template = fs.readFileSync(config.templates.connector, "utf-8");
        var url = connectUtils.getConnectionUrl(options);
        /**
         * ***Backwards compatibility***. While `socket.path` is technically a
         * socketIoClientConfig property, it's been documented previously
         * as a top-level option, so must stay.
         */
        var clientConfig = socket.get("socketIoClientConfig").merge({
            path: socket.get("path")
        });
        template = template
            .replace("%config%", JSON.stringify(clientConfig.toJS()))
            .replace("%options%", JSON.stringify(options))
            .replace("%url%", url);
        return template;
    },
    /**
     * @param {Object} socketOpts
     * @param {Map} options
     * @returns {String|Function}
     */
    getNamespace: function (socketOpts, options) {
        var namespace = socketOpts.namespace;
        if (typeof namespace === "function") {
            return namespace(options);
        }
        if (!namespace.match(/^\//)) {
            namespace = "/" + namespace;
        }
        return namespace;
    },
    /**
     * @param {Map} options
     * @returns {string}
     */
    getConnectionUrl: function (options) {
        var socketOpts = options.get("socket").toJS();
        var namespace = connectUtils.getNamespace(socketOpts, options);
        var protocol = "";
        var withHostnamePort = "'{protocol}' + location.hostname + ':{port}{ns}'";
        var withHost = "'{protocol}' + location.host + '{ns}'";
        var withDomain = "'{domain}{ns}'";
        var port = options.get("port");
        // default use-case is server/proxy
        var string = withHost;
        if (options.get("mode") !== "server") {
            protocol = options.get("scheme") + "://";
            string = withHostnamePort;
        }
        if (options.get("mode") === "proxy" && options.getIn(["proxy", "ws"])) {
            port = options.getIn(["socket", "port"]);
        }
        /**
         * Ensure socket.domain is always a string (for noop replacements later)
         */
        socketOpts.domain = (function () {
            if (options.get("localOnly")) {
                string = withDomain;
                return [
                    options.get("scheme"),
                    "://localhost:",
                    options.get("port")
                ].join("");
            }
            if (socketOpts.domain) {
                string = withDomain;
                /**
                 * User provided a function
                 */
                if (_.isFunction(socketOpts.domain)) {
                    return socketOpts.domain.call(null, options);
                }
                /**
                 * User provided a string
                 */
                if (_.isString(socketOpts.domain)) {
                    return socketOpts.domain;
                }
            }
            return "";
        })();
        return string
            .replace("{protocol}", protocol)
            .replace("{port}", port)
            .replace("{domain}", socketOpts.domain.replace("{port}", port))
            .replace("{ns}", namespace);
    },
    /**
     * @param {Object} [options]
     * @param {Boolean} [both]
     */
    clientScript: function (options, both) {
        var prefix = options.getIn(["socket", "clientPath"]);
        var script = prefix + "/browser-sync-client.js";
        var versioned = prefix + "/browser-sync-client.js?v=" + options.get("version");
        if (both) {
            return {
                path: script,
                versioned: versioned
            };
        }
        return versioned;
    }
};
/**
 * @param options
 * @returns {*[]}
 */
function getScriptArgs(options, scriptPath) {
    var abspath = options.get("scheme") + "://HOST:" + options.get("port") + scriptPath;
    return [scriptPath, options.get("port"), options.set("absolute", abspath)];
}
module.exports = connectUtils;
//# sourceMappingURL=connect-utils.js.map