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

/** @class */
jscape.IpAccessRule = Class.extend(
    /** @lends {jscape.IpAccessRule.prototype} */
{
    /** @constructor */
    initialize: function(a, b, c) {
        this.mask = a || "";
        this.reason = b || "";
        this.allowed = c || false;
    }
});
jscape.IpAccessRule.fromJSON = function(data) {
    return new jscape.IpAccessRule(data.mask, data.reason, data.allowed);
};

/** @class */
jscape.domain.IPAccessModule = jscape.domain.DomainModule.extend(
    /** @lends {jscape.domain.IPAccessModule.prototype} */
{
    onCreate: function () {
        this._super.apply(this, arguments);

        this.controller = new jscape.domain.IpAccessController();
        this.controller.onCreate(this.managementService, this.domainName);
    },

    onStart: function () {
        this.controller.onStart();
    },

    onPause: function() {
        if (this.controller.hasChanged()) {
            this._confirmAndApply([this.controller]);
        }
    },

    onResume: function() {
        this.controller.onResume();
    }
});

/** @class */
jscape.domain.IpAccessController = Class.extend(
    /** @lends {jscape.domain.IpAccessController.prototype} */
{
    view: null,
    rules: null,
    copy: null,

    /** @constructor */
    initialize: function() {
        this._initValidators();
    },

    onCreate: function (managementService, domainName) {
        this.managementService = managementService;
        this.domainName = domainName;

        this.addController = new jscape.domain.AddIpAccessController();
        this.editController = new jscape.domain.EditIpAccessController();
        this.deleteController = new jscape.domain.DeleteIpAccessController();
    },

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

    hasChanged: function() {
        return !Object._equals(this.copy, this.rules);
    },

    onResume: function () {
        this.managementService.getIpAccessRules(this.domainName)
                .done($.proxy(function (rules) { this.rules = rules; }, this))
                .fail($.proxy(function () { this.rules = []; }, this))
                .always($.proxy(function () {
                            this.copy = this._copyRules(this.rules);
                            this.view.setRules(this.rules);
                        }, this));
    },

    onApply: function() {
        var rules = this.rules;
        return this.managementService.setIpAccessRules(this.domainName, rules)
                .done($.proxy(function() { this.copy = this._copyRules(rules); }, this))
                .done($.proxy(this._fireApplySuccess, this));
    },

    onDiscard: function() {
        this.rules = this.copy;
        this.copy = this._copyRules(this.rules);
        this.view.setRules(this.rules);
    },

    onAddRule: function() {
        this.addController.start()
                .done($.proxy(this._ruleAdded, this));
    },

    onEditRule: function(rule) {
        var index = $.inArray(rule, this.rules);
        if (index != -1) {
            this.editController.start(rule)
                    .done($.proxy(this._ruleEdited, this, index));
        }
    },

    onDeleteRule: function(rules) {
        this.deleteController.start(rules)
                .done($.proxy(this._ruleDeleted, this, rules));
    },

    onRuleUp: function (rule) {
        var index = $.inArray(rule, this.rules);
        if (index > 0) {
            this.rules.splice(index - 1, 2, this.rules[index], this.rules[index - 1]);
            this.view.setRules(this.rules);
            this.view.selectRule(rule);
        }
    },

    onRuleDown: function (rule) {
        var index = $.inArray(rule, this.rules);
        if (index != -1 && index < this.rules.length - 1) {
            this.rules.splice(index, 2, this.rules[index + 1], this.rules[index]);
            this.view.setRules(this.rules);
            this.view.selectRule(rule);
        }
    },

    onRefresh: function() {
        this.onResume();
    },

    _ruleAdded: function (rule) {
        this.rules.push(rule);
        this.view.setRules(this.rules);
        this.view.selectRule(rule);
    },

    _ruleEdited: function (index, rule) {
        this.rules[index] = rule;
        this.view.setRules(this.rules);
        this.view.selectRule(rule);
    },

    _ruleDeleted: function (rules) {
        var index = -1;
        while (rules.length) {
            index = $.inArray(rules.pop(), this.rules);
            this.rules.splice(index, 1);
        }
        this.view.setRules(this.rules);

        if (this.rules.length) {
            index = Math.max(0, Math.min(index, this.rules.length - 1));
            this.view.selectRule(this.rules[index]);
        }
    },

    _copyRules: function(rules) {
        return $.map(rules, function(rule) { return jscape.IpAccessRule.fromJSON(rule); });
    },

    _fireApplySuccess: function () {
        $(document).triggerHandler("broadcast", [window.R.string.APPLICATION_SUCCESS_APPLY]);
    },

    _initValidators: function() {
        var v = new jscape.Validator();
        v.nonEmptyRule("ipaccess_mask_nonempty", window.R.string.IP_ACCESS_ERROR_BAD_MASK);
        v.rule("ipaccess_unique", $.proxy(this._ruleNotExists, this), window.R.string.IP_ACCESS_ERROR_ALREADY_EXIST);
    },

    _ruleNotExists: function(value, excludes) {
        return $.grep(this.rules, function(rule) {
            return rule.mask == value && (excludes == undefined || $.inArray(rule.mask, excludes) == -1);
        }).length == 0;
    }
});

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

    /** @constructor */
    initialize: function(container) {
        this.selection = [];
        this.fieldset = $("fieldset[name=ipaccessfields]", container);

        this.data = $("table[role=grid][aria-label=ipaccess]", this.fieldset);
        this.data.datagrid({
            fit: true,
            fitColumns: true,
            singleSelect: true,
            pagination: true,
            remoteSort: false,
            search: true,
            onSelect: $.proxy(this._adjustRowSelection, this),
            onUnselect: $.proxy(this._adjustRowSelection, this),
            onLoadSuccess: $.proxy(this._adjustRowSelection, this),
            onDblClickRow: $.proxy(this._onClick$EditButton, this),
            columns: [[
                {field: "mask", title: $("thead th:nth-child(1)", this.data).text(), width: 60},
                {field: "allowed", title: $("thead th:nth-child(2)", this.data).text(), width: 15, formatter: $.proxy(this._formatAccess, this), styler: $.proxy(this._styleAccess, this)},
                {field: "reason", title: $("thead th:nth-child(3)", this.data).text(), width: 25}
            ]]
        });

        this.moveUpButton = $("a[role=button][name=moveup]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$MoveUpButton, this)});
        this.moveDownButton = $("a[role=button][name=movedown]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$MoveDownButton, this)});
        this.addButton = $("a[role=button][name=add]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$AddButton, this)});
        this.editButton = $("a[role=button][name=edit]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$EditButton, this)});
        this.deleteButton = $("a[role=button][name=delete]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$DeleteButton, this)});
        this.refreshButton = $("a[role=button][name=refresh]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$RefreshButton, this)});
        this.applyButton = $("a[role=button][name=apply]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$ApplyButton, this)});
        this.discardButton = $("a[role=button][name=discard]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$DiscardButton, this)});
    },

    setRules: function(values) {
        this.selection = [];
        this.data.datagrid("loading").datagrid("loadData", values).datagrid("loaded");
    },

    selectRule: function(rule) {
        this.data.datagrid("selectRow", this.data.datagrid("getRowIndex", rule));
    },

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

    _formatAccess: function(value) {
        return !!value ? window.R.string.IP_ACCESS_RULE_ALLOWED : window.R.string.IP_ACCESS_RULE_DENIED;
    },

    _styleAccess: function(value) {
        return !!value ? "color:green" : "color:red";
    },

    _onClick$AddButton: function() {
        this.listener.onAddRule();
    },

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

    _onClick$DeleteButton: function() {
        this.listener.onDeleteRule(this.selection);
    },

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

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

    _onClick$RefreshButton: function() {
        this.listener.onRefresh();
    },

    _onClick$ApplyButton: function() {
        if (this.fieldset.form("validate")) {
            this.applyButton.linkbutton("disable");
            this.listener.onApply(this)
                    .always($.proxy(function() { this.applyButton.linkbutton("enable"); }, this));
        }
    },

    _onClick$DiscardButton: function() {
        this.listener.onDiscard();
    },

    _adjustRowSelection: function() {
        this.selection = this.data.datagrid("getSelections");
        this._adjustButtonsState();
    },

    _adjustButtonsState: function() {
        var index = this.selection.length == 1 ? this.data.datagrid("getRowIndex", this.selection[0]) : -1;
        var count = this.data.datagrid("getRows").length;

        this.moveUpButton.linkbutton(index > 0 && index <= count - 1 ? "enable" : "disable");
        this.moveDownButton.linkbutton(index >= 0 && index < count - 1 ? "enable" : "disable");
        this.editButton.linkbutton(this.selection.length == 1 ? "enable" : "disable");
        this.deleteButton.linkbutton(this.selection.length !=0 ? "enable" : "disable");
    }
});

jscape.domain.IpAccessView.LISTENER = {
    onAddRule: $.noop,
    onEditRule: $.noop,
    onDeleteRule: $.noop,
    onRuleUp: $.noop,
    onRuleDown: $.noop,
    onRefresh: $.noop,
    onApply: $.noop,
    onDiscard: $.noop
};

/** @class */
jscape.domain.IpAccessRuleDialog = Class.extend(
    /** @lends {jscape.domain.IpAccessRuleDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.dialog = $("#d-ipaccess-rule").clone().attr("id", new Date().getTime().toString(36));
        this.dialog.dialog({
            width: 530, height: "auto",
            modal: true, resizable: false, closable: true, closed: true,
            buttons: [
                {text: window.R.string.DIALOG_BUTTON_OK || "Ok", disabled: this.dialog.find("fieldset:first").is(":disabled"), 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=ipaccessrulefields]", this.dialog);

        this.mask = $("input[name=mask]", this.fieldset).textbox({required: true, validType: ["ipaccess_mask_nonempty", "ipaccess_unique"], missingMessage: window.R.string.IP_ACCESS_ERROR_BAD_MASK, width: "60%"});
        this.reason = $("input[name=reason]", this.fieldset).textbox({width: "60%"});
        this.allowed = $("input[name=allowed]:radio", this.fieldset);
    },

    setTitle: function(title) {
        this.dialog.dialog("setTitle", title || "");
    },

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

    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");
    },

    getMask: function () {
        return this.mask.textbox("getValue");
    },

    setMask: function (value) {
        this.mask.textbox("setValue", value);
        if (value && value.trim().length) {
            this.mask.textbox("textbox").validatebox("options").validType = ["ipaccess_mask_nonempty", "ipaccess_unique['" + value + "']"];
        }
    },

    getReason: function () {
        return this.reason.textbox("getValue");
    },

    setReason: function (value) {
        this.reason.textbox("setValue", value);
    },

    getAllowed: function () {
        return (/^true$/i).test(this.allowed.filter(":checked").val());
    },

    setAllowed: function (value) {
        this.allowed.filter("[value=" + Boolean(value) + "]").prop("checked", true);
    },

    _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;
    }
});

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

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

    onSubmit: function(dialog) {
        var rule = this._createRule(dialog);
        dialog.destroy();
        this.deferred.resolve(rule);
        this.deferred = null;
    },

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

    _createRule: function(dialog) {
        return new jscape.IpAccessRule(dialog.getMask(), dialog.getReason(), dialog.getAllowed());
    },

    _setupDialog: function () {
        var dialog = new jscape.domain.IpAccessRuleDialog();
        dialog.setTitle(window.R.string.IP_ACCESS_DIALOG_ADD_TITLE);
        dialog.setAllowed(true);
        return dialog;
    }
});

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

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

    onSubmit: function(dialog) {
        var rule = this._createRule(dialog);
        dialog.destroy();
        this.deferred.resolve(rule);
        this.deferred = null;
    },

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

    _createRule: function(dialog) {
        return new jscape.IpAccessRule(dialog.getMask(), dialog.getReason(), dialog.getAllowed());
    },

    _setupDialog: function(rule) {
        var dialog = new jscape.domain.IpAccessRuleDialog();
        dialog.setTitle(window.R.string.IP_ACCESS_DIALOG_EDIT_TITLE);
        dialog.setMask(rule.mask);
        dialog.setReason(rule.reason);
        dialog.setAllowed(rule.allowed);
        return dialog;
    }
});

/** @class */
jscape.domain.DeleteIpAccessController = Class.extend(
    /** @lends {jscape.domain.DeleteIpAccessController.prototype} */
{
    start: function(rules) {
        var text = $.map(rules, function(rule) { return rule.mask; }).join(", ");
        return jscape.ConfirmDialog.confirm(
                window.R.string.IP_ACCESS_CONFIRM_DELETE_TITLE,
                window.R.string.IP_ACCESS_CONFIRM_DELETE_MESSAGE.supplant({0: text}));
    }
});