jscape.domain = jscape.domain || {};

/** @class */
jscape.ConnectionStatistics = Class.extend(
    /** @lends {jscape.ConnectionStatistics.prototype} */
{
    /** @constructor */
    initialize: function (a, b, c, d, e, f, g, h, i) {
        this.type = a || "";
        this.creationTime = parseInt(b) || 0;
        this.upTimeMillis = parseInt(c) || 0;
        this.localAddress = d || "";
        this.localPort = parseInt(e) || 0;
        this.remoteAddress = f || "";
        this.remotePort = parseInt(g) || 0;
        this.username = h || "";
        this.path = i || "";
    }
});
jscape.ConnectionStatistics.fromJSON = function(data) {
    return $.extend(new jscape.ConnectionStatistics(), data);
};

/** @class */
jscape.domain.StatisticsModule = jscape.domain.DomainModule.extend(
    /** @lends {jscape.domain.SessionsModule.prototype} */
{
    DEFAULT_DELAY: 5 * 1000,

    view: null,
    timerId: null,
    delay: 0,

    onStart: function() {
        if (this.view == null) {
            this.view = new jscape.domain.DomainStatisticsView();
        }
        this.view.show(this);
    },

    onStop: function() {
        this._stopPoll();
    },

    onResume: function() {
        this.delay = this.DEFAULT_DELAY;
        this._poll();
    },

    onRefresh: function() {
        return this.managementService.getDomainStatistics(this.domainName)
                .done($.proxy(function() { this.delay = this.DEFAULT_DELAY; }, this))
                .fail($.proxy(function() { this.delay *= 2; }, this));
    },

    onPause: function() {
        this._stopPoll();
    },

    _poll: function (delay) {
        this._stopPoll();
        this.timerId = setTimeout($.proxy(function () {
            this.timerId = null;
            this.view.refresh();
            this._poll(this.delay);
        }, this), delay || 0);
    },

    _stopPoll: function () {
        if (this.timerId) {
            clearInterval(this.timerId);
        }
    }
});

/** @class */
jscape.domain.SessionsModule = jscape.domain.DomainModule.extend(
    /** @lends {jscape.domain.SessionsModule.prototype} */
{
    DEFAULT_DELAY: 5 * 1000,

    view: null,
    timerId: null,
    delay: 0,

    onStart: function() {
        if (this.view == null) {
            this.view = new jscape.domain.SessionsView();
        }
        this.view.show(this);
    },

    onStop: function() {
        this._stopPoll();
    },

    onResume: function() {
        this.delay = this.DEFAULT_DELAY;
        this._poll();
    },

    onPause: function() {
        this._stopPoll();
    },

    onRefresh: function() {
        return this.managementService.getDomainConnections(this.domainName)
                .done($.proxy(function() { this.delay = this.DEFAULT_DELAY; }, this))
                .fail($.proxy(function() { this.delay *= 2; }, this));
    },

    onCloseConnection: function (session) {
        new jscape.domain.CloseSessionController()
                .start(this.managementService, this.domainName, session)
                .done($.proxy(this._sessionClosed, this, session));
    },

    _sessionClosed: function (session) {
        var copy = [].concat(this.view.getRecords());
        var index = $.inArray(session, copy);
        copy.splice(index, 1);
        if (copy.length) {
            index = Math.min(Math.max(0, index), copy.length - 1);
            this.view.refresh($.proxy(function (record) {
                record && this.view.selectRecord(record);
            }, this, copy[index]));
        }
    },

    _poll: function (delay) {
        this._stopPoll();
        this.timerId = setTimeout($.proxy(function () {
            this.timerId = null;
            this.view.refresh();
            this._poll(this.delay);
        }, this), delay || 0);
    },

    _stopPoll: function () {
        if (this.timerId) {
            clearTimeout(this.timerId);
        }
    }
});

/** @class */
jscape.domain.DomainStatisticsView = Class.extend(
    /** @lends {jscape.domain.DomainStatisticsView.prototype} */
{
    /** @constructor */
    initialize: function(container) {
        this.dateFormat = new jscape.DateFormat();

        this.fieldset = $("fieldset[name=domainstatisticsfields]", container);

        this.status = $("dd[aria-label=status]", this.fieldset);
        this.startDate = $("dd[aria-label=startdate]", this.fieldset);
        this.stopDate = $("dd[aria-label=stopdate]", this.fieldset);
        this.connections = $("dd[aria-label=connections]", this.fieldset);
        this.transfers = $("dd[aria-label=transfers]", this.fieldset);
        this.totalConnections = $("dd[aria-label=totalconnections]", this.fieldset);
        this.sessionUploaded = $("dd[aria-label=sessionuploaded]", this.fieldset);
        this.sessionDownloaded = $("dd[aria-label=sessiondownloaded]", this.fieldset);
        this.uploadsQuota = $("dd[aria-label=uploadsquota]", this.fieldset);
        this.downloadsQuota = $("dd[aria-label=downloadsquota]", this.fieldset);
        this.transfersQuota = $("dd[aria-label=transfersquota]", this.fieldset);
    },

    setStatistics: function(stats) {
        this.status.text(this._formatStatus(stats));
        this.startDate.text(this._formatDate(stats.startDate));
        this.stopDate.text(this._formatDate(stats.stopDate));
        this.connections.text(stats.currentSessions);
        this.transfers.text(stats.currentTransfers);
        this.totalConnections.text(stats.totalSessions);
        this.sessionUploaded.text(this._formatTransfers(stats.bytesUploaded, stats.filesUploaded));
        this.sessionDownloaded.text(this._formatTransfers(stats.bytesDownloaded, stats.filesDownloaded));
        this.uploadsQuota.text(this._formatQuota(stats.uploadsQuota, stats.currentUploadedBytes));
        this.downloadsQuota.text(this._formatQuota(stats.downloadsQuota, stats.currentDownloadedBytes));
        this.transfersQuota.text(this._formatQuota(stats.transfersQuota, stats.currentTransferredBytes));
    },

    show: function(listener) {
        this.listener = listener || jscape.domain.DomainStatisticsView.LISTENER;
    },

    refresh: function() {
        this.listener.onRefresh().done($.proxy(this.setStatistics, this));
    },

    _formatStatus: function(stats) {
        return window.R.string["DOMAIN_STATUS_" + jscape.DomainStatus.valueOf(stats).toUpperCase()];
    },

    _formatDate: function(value) {
        return value ? new Date(value).toLocaleString() : "-";
    },

    _formatTransfers: function(bytes, files) {
        return window.R.string.STATISTICS_TEMPLATE_TRANSFERS.supplant({0: jscape.SizeFormat.format(bytes), 1: files});
    },

    _formatQuota: function(quota, bytes) {
        return quota ? window.R.string.STATISTICS_TEMPLATE_QUOTA.supplant({0: jscape.SizeFormat.format(bytes), 1: jscape.SizeFormat.format(quota)}) : "-";
    }
});
jscape.domain.DomainStatisticsView.LISTENER = {
    onRefresh: $.noop
};

/** @class */
jscape.domain.SessionsView = jscape.ui.DatagridView.extend(
    /** @lends {jscape.domain.SessionsView.prototype} */
{
    selection: null,

    /** @constructor */
    initialize: function(container) {
        var initializing = true;

        this.timeFormat = new jscape.DateFormat("{hh}:{mm}:{ss}");

        this.fieldset = $("fieldset[name=sessionsfields]", container);
        this.data = $("table[role=grid][aria-label=sessions]", this.fieldset);
        this.data.datagrid({
            fit: true,
            fitColumns: true,
            singleSelect: true,
            remoteSort: false,
            sortName: "type",
            columns: [[
                {field: "type", title: $("thead th:nth-child(1)", this.data).text(), sortable: true, width: 100},
                {field: "localAddress", title: $("thead th:nth-child(2)", this.data).text(), sortable: true, width: 220, formatter: $.proxy(function(_, row) { return this._formatServerAddress(row); }, this)},
                {field: "remoteAddress", title: $("thead th:nth-child(3)", this.data).text(), sortable: true, width: 220, formatter: $.proxy(function(_, row) { return this._formatClientAddress(row); }, this)},
                {field: "username", title: $("thead th:nth-child(4)", this.data).text(), sortable: true, width: 170},
                {field: "creationTime", title: $("thead th:nth-child(5)", this.data).text(), sortable: true, width: 200, align: "right", formatter: $.proxy(function(_, row) { return this._formatCreationTime(row); }, this), sorter: $.proxy(this._compareDateTime, this)},
                {field: "uptime", title: $("thead th:nth-child(6)", this.data).text(), sortable: false, width: 170, align: "right", formatter: $.proxy(function(_, row) { return this._formatUptime(row); }, this)},
                {field: "path", title: $("thead th:nth-child(7)", this.data).text(), sortable: false, width: 170}
            ]],
            onSelect: $.proxy(this._adjustButtonsState, this),
            onUnselect: $.proxy(this._adjustButtonsState, this),
            loader: $.proxy(this._onLoad$Data, this),
            onBeforeLoad: $.proxy(function() { return this.data.length && !initializing; }, this),
            onLoadSuccess: $.proxy(this._adjustButtonsState, this)
        });

        this.closeButton = $("a[role=button][name=close]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$CloseButton, this)});

        initializing = false;
    },

    show: function(listener) {
        this.listener = listener || jscape.domain.SessionsView.LISTENER;
        this._adjustButtonsState();
    },

    refresh: function() {
        if (this.data.length) {
            this._super.apply(this, arguments);
        }
    },

    _formatCreationTime: function(stats) {
        return new Date(stats.creationTime).toLocaleString();
    },

    _formatUptime: function(stats) {
        // millis are greater than logical range, the adjacent value will be adjusted
        return this.timeFormat.format(new Date(0, 0, 1, 0, 0, stats.upTimeMillis / 1000));
    },

    _formatServerAddress: function(stats) {
        return (stats.localAddress + ":" + stats.localPort).escapeXml();
    },

    _formatClientAddress: function(stats) {
        return (stats.remoteAddress + ":" + stats.remotePort).escapeXml();
    },

    _compareDateTime: function(o1, o2) {
        o1 = parseInt(o1);
        o2 = parseInt(o2);
        return isNaN(o1)
                ? (isNaN(o2) ? 0 : 1)
               : (isNaN(o2) ? 1 : (o1 == o2 ? 0 : o1 > o2 ? 1 : -1));
    },

    _onLoad$Data: function (params, success, error) {
        var selection = [].concat(this.selection);
        this.listener.onRefresh(params)
                .done($.proxy(function (data) {
                          success.call(success, data);
                          if (selection.length) {
                              this.data.datagrid("selectRow", this.data.datagrid("getRowIndex", selection[0]));
                          }
                      }, this))
                .fail(error);
    },

    _onClick$CloseButton: function() {
        this.listener.onCloseConnection(this.selection[0]);
    },

    _adjustButtonsState: function () {
        this.selection = this.data.datagrid("getSelections");
        this.closeButton.linkbutton(this.selection.length == 1 ? "enable" : "disable");
    }
});
jscape.domain.SessionsView.LISTENER = {
    onRefresh: $.noop,
    onCloseConnection: $.noop
};

/** @class */
jscape.domain.CloseSessionController = Class.extend(
    /** @lends {jscape.domain.CloseSessionController.prototype} */
{
    deferred: null,

    start: function(managementService, domainName, stats) {
        this.managementService = managementService;
        this.domainName = domainName;
        this.stats = stats;
        this.deferred = $.Deferred();
        this._setupDialog(stats).show(this);
        return this.deferred.promise();
    },

    onSubmit: function(dialog) {
        var scope = dialog.getScope();
        dialog.destroy();
        this.managementService.closeConnection(this.domainName, this.stats, scope)
                .done($.proxy(function() { this.deferred.resolve(); this.deferred = null; }, this))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));
    },

    onCancel: function(dialog) {
        dialog.destroy();
        this.deferred.reject();
        this.deferred = null;
    },

    _setupDialog: function (stats) {
        var dialog = new jscape.domain.CloseSessionDialog();
        dialog.setStatistics(stats);
        return dialog;
    }
});

/** @class */
jscape.domain.CloseSessionDialog = Class.extend(
    /** @lends {jscape.domain.CloseSessionDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.dialog = $("#d-sessions-close").clone().attr("id", "");
        this.dialog.dialog({
            width: 530, height: "auto",
            modal: true, resizable: false, closable: true, closed: true,
            buttons: [
                {text: window.R.string.DIALOG_BUTTON_OK || "Ok", handler: $.proxy(this._onSubmit, this)},
                {text: window.R.string.DIALOG_BUTTON_CANCEL || "Cancel", handler: $.proxy(this._onCancel, this)}
            ],
            onClose: $.proxy(function () {if (!this.closing) { this._onCancel(); }}, this)
        }).show();

        this.fieldset = $("fieldset[name=closesessionfields]", this.dialog);
        this.scope = $("input[name=scope]:radio", this.fieldset);
    },

    getScope: function() {
        return this.scope.filter(":checked").val();
    },

    setStatistics: function(stats) {
        this._adjustLabel(this.scope.filter("[value=CURRENT_SESSION]"), {0: stats.remoteAddress, 1: stats.remotePort, 2: stats.localAddress, 3: stats.localPort});
        this._adjustLabel(this.scope.filter("[value=ALL_USER_SESSIONS]"), {0: stats.username}).prop("disabled", stats.username.trim().length == 0);
        this._adjustLabel(this.scope.filter("[value=ALL_CLIENT_IP_SESSIONS]"), {0: stats.remoteAddress});
        this._adjustLabel(this.scope.filter("[value=ALL_SERVICE_SESSIONS]"), {0: stats.localAddress, 1: stats.localPort});

        this.scope.first().prop("checked", true);
    },

    show: function (listener) {
        this.listener = listener;
        this.dialog.dialog("center").dialog("open");
        this.fieldset.form("validate");
    },

    hide: function () {
        if (!this._closed()) {
            this.closing = true;
            this.dialog.dialog("close");
            this.fieldset.form("disableValidation");
            this.closing = false;
        }
    },

    destroy: function() {
        this.dialog.dialog("destroy");
    },

    _adjustLabel: function(radio, args) {
        var node = $(radio[0].nextSibling);
        node.replaceWith(node.text().supplant(args));
        return radio;
    },

    _onSubmit: function () {
        if (this.fieldset.form("validate")) {
            this.hide();
            this.listener.onSubmit(this);
        }
    },

    _onCancel: function () {
        this.hide();
        this.listener.onCancel(this);
    },

    _closed: function () {
        return !!this.dialog.dialog("options").closed;
    }
});