jscape.settings = jscape.settings || {};

/** @class */
jscape.ServerDatabaseServiceConfiguration = Class.extend(
    /** @lends {jscape.ServerDatabaseServiceConfiguration.prototype} */
{
    DEFAULTS: {url: "jdbc:h2:data/server", connectionPoolSize: 100, idleConnectionTtlMillis: 10 * 1000, synchronizationPeriodMillis: null},

    /** @constructor */
    initialize: function(a, b, c, d, e, f) {
        this.url = a || this.DEFAULTS.url;
        this.username = b || "";
        this.password = c || "";
        this.connectionPoolSize = parseInt(d) || this.DEFAULTS.connectionPoolSize;
        this.idleConnectionTtlMillis = parseInt(e) || this.DEFAULTS.idleConnectionTtlMillis;
        this.synchronizationPeriodMillis = parseInt(f) || this.DEFAULTS.synchronizationPeriodMillis;
    }
});
jscape.ServerDatabaseServiceConfiguration.fromJSON = function(data) {
    return data ? new jscape.ServerDatabaseServiceConfiguration(data.url, data.username, data.password, data.connectionPoolSize, data.idleConnectionTtlMillis, data.synchronizationPeriodMillis) : null;
};

/** @class */
jscape.settings.DatastoreModule = jscape.settings.SettingsModule.extend(
    /** @lends {jscape.settings.DatastoreModule.prototype} */
{
    onCreate: function(managementService) {
        this._super.apply(this, arguments);

        this.controller = new jscape.settings.ServerDatabaseController();
        this.controller.onCreate(managementService);
    },

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

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

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

/** @class */
jscape.settings.ServerDatabaseController = Class.extend(
    /** @lends {jscape.settings.ServerDatabaseController.prototype} */
{
    DEFAULT_CONFIG: new jscape.ServerDatabaseServiceConfiguration(),
    RECONNECT_DELAY: 1500,

    config: null,
    view: null,

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

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

    onResume: function () {
        this.managementService.getServerDatabaseConfiguration()
                .done($.proxy(function (config) { this.config = config; }, this))
                .fail($.proxy(function () { this.config = this.DEFAULT_CONFIG; }, this))
                .always($.proxy(function () { this.view && this._setupView(this.config); }, this));
    },

    hasChanged: function () {
        return this.config != null && !Object._equals(this.config, this._createConfiguration());
    },

    onChange: function () {
        var config = this._createConfiguration();
        var modified = config.url != (this.config ? this.config.url : null)
                       || config.username != (this.config ? this.config.username : null)
                       || config.password != (this.config ? this.config.password : null);
        this.view.setNotification(modified ? window.R.string.DATASTORE_WARNING_RECONNECT_REQUIRED : "");
    },

    onTest: function () {
        var config = this._createConfiguration();
        return this.managementService.testServerDatabase(config)
                .done($.proxy(this._testPassed, this));
    },

    onCreateDb: function() {
        var config = this._createConfiguration();
        return this.managementService.createServerDatabase(config)
                .done($.proxy(this._databaseCreated, this));
    },

    onApply: function () {
        var deferred = $.Deferred();
        var reconnect = this.hasChanged();
        var config = this._createConfiguration();

        this._confirmCopyDb()
                .done($.proxy(function (copyData) {
                          this.managementService.prefetchServerDatabaseData(config)
                                  .then($.proxy(function (restConfig) {
                                            return this.managementService.setServerDatabaseConfiguration(config, copyData)
                                                    .done($.proxy(function (newConfig) {
                                                              this.config = newConfig;
                                                              if (reconnect) {
                                                                  this._reconnect(restConfig);
                                                              } else {
                                                                  this._fireApplySuccess();
                                                              }
                                                              deferred.resolve(newConfig);
                                                              deferred = null;
                                                          }, this));
                                        }, this))
                                  .fail(function () { deferred.reject(); deferred = null; });
                      }, this));
/*        this.managementService.prefetchServerDatabaseData(config)
                .then($.proxy(function (restConfig) {
                          return this.managementService.setServerDatabaseConfiguration(config)
                                  .done($.proxy(function (dbConfig) {
                                            this.config = dbConfig;
                                            if (reconnect) {
                                                this._reconnect(restConfig);
                                            } else {
                                                this._fireApplySuccess();
                                            }
                                            deferred.resolve(dbConfig);
                                            deferred = null;
                                        }, this))
                      }, this))
                .fail(function () { deferred.reject(); deferred = null; });*/
        return deferred.promise();
    },

    onDiscard: function() {
        this._setupView(this.config);
        return $.Deferred().resolve().promise();
    },

    _confirmCopyDb: function () {
        var deferred = $.Deferred();
        var dialog = $.messager.confirm({
            title: window.R.string.DATASTORE_CONFIRM_COPY_DB_TITLE,
            msg: window.R.string.DATASTORE_CONFIRM_COPY_DB_MESSAGE,
            buttons: [
                {
                    text: window.R.string.DIALOG_BUTTON_YES,
                    onClick: function () {
                        dialog.dialog("close");
                        deferred.resolve(true);
                        dialog = deferred = null;
                    }
                },
                {
                    text: window.R.string.DIALOG_BUTTON_NO,
                    onClick: function () {
                        dialog.dialog("close");
                        deferred.resolve(false);
                        dialog = deferred = null;
                    }
                }
            ]
        });
        return deferred.promise();
    },

    _createConfiguration: function () {
        return new jscape.ServerDatabaseServiceConfiguration(this.view.getUrl(),
                                                             this.view.getUsername(),
                                                             this.view.getPassword(),
                                                             this.view.getPoolSize(),
                                                             this.view.getPoolTimeout(),
                                                             this.view.getSyncPeriod());
    },

    _setupView: function(config) {
        if (config) {
            this.view.setUrl(config.url);
            this.view.setUsername(config.username);
            this.view.setPassword(config.password);
            this.view.setPoolSize(config.connectionPoolSize);
            this.view.setPoolTimeout(config.idleConnectionTtlMillis);
            this.view.setSyncPeriod(config.synchronizationPeriodMillis);
        }
    },

    _reconnect: function (config) {
        setTimeout($.proxy(function () {
            this._redirect(config);
        }, this), this.RECONNECT_DELAY);
    },

    _redirect: function (config) {
        var secure = /^https/i.test(window.location.protocol) && config.httpsEnabled;
        var host = secure ? config.httpsHost : config.httpHost;
        if ("0.0.0.0" === host) {
            window.location = "//" + window.location.host;
        } else {
            var port = secure ? config.httpsPort : config.httpPort;
            window.location = "//" + host + ((!secure && port == 80) || (secure && port == 443) ? "" : ":" + port);
        }
    },

    _testPassed: function (result) {
        $.messager.alert({
            width: 350, height: "auto", icon: "info", escapeXml: false,
            title: window.R.string.DATASTORE_TEST_DB_TITLE,
            msg: "<p><b>" + window.R.string.DATASTORE_TEST_DB_PASSED_MESSAGE + "</b></p>"
                 + "<div style='clear:both;margin-left:4em;line-height:1.6'>"
                 + this._styleTestResult(window.R.string.DATASTORE_TEST_DB_RESULT_MANAGEMENT_CONFIG, result.managementConfigurationPresent)
                 + this._styleTestResult(window.R.string.DATASTORE_TEST_DB_RESULT_WEB_MANAGEMENT_CONFIG, result.webManagementConfigurationPresent)
                 + this._styleTestResult(window.R.string.DATASTORE_TEST_DB_RESULT_ADMINISTRATOR, result.administratorPresent)
                 + "</div>"
        });
    },

    _styleTestResult: function (message, success) {
        return "<div>{2}<span class='{0}' style='display:inline-block;width:16px;height:16px;line-height:16px;margin-left:1em' title='{1}'>&nbsp;</span></div>"
                .supplant({
                    0: !!success ? "icon-ok" : "icon-no",
                    1: !!success,
                    2: (message || "").escapeXml()
                });
    },

    _databaseCreated: function() {
        $.messager.alert(window.R.string.DATASTORE_CREATE_DB_TITLE,
                         window.R.string.DATASTORE_CREATE_DB_SUCCESS_MESSAGE,
                         "info");
    },

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

/** @class */
jscape.settings.ServerDatabaseView = Class.extend(
    /** @lends {jscape.settings.ServerDatabaseView.prototype} */
{
    TIMEOUT_FACTOR: 1000,

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

        this.url = $("input[name=dburl]", this.fieldset).textbox({required: true, validType: "length[1,2048]", missingMessage: window.R.string.DATASTORE_ERROR_BAD_DB_URL, invalidMessage: window.R.string.DATASTORE_ERROR_BAD_DB_URL, onChange: $.proxy(this._onChange$Form, this), width: "50%"});
        this.url.textbox("textbox").on("input", $.proxy(this._onChange$Form, this));
        this.username = $("input[name=username]", this.fieldset).textbox({required: true, validType: "length[1,50]", missingMessage: window.R.string.DATASTORE_ERROR_BAD_USER, invalidMessage: window.R.string.DATASTORE_ERROR_BAD_USER, onChange: $.proxy(this._onChange$Form, this), width: "30%"});
        this.username.textbox("textbox").on("input", $.proxy(this._onChange$Form, this));
        this.password = $("input[name=password]", this.fieldset).textbox({type: "password", onChange: $.proxy(this._onChange$Form, this), width: "30%"});
        this.password.textbox("textbox").on("input", $.proxy(this._onChange$Form, this));
        this.poolSize = $("input[name=poolsize]", this.fieldset).numberspinner({min: 1, max: 100, value: 5, width: 60});
        this.poolTimeout = $("input[name=poolttl]", this.fieldset).numberspinner({min: 1, max: 100, value: 5, width: 60});

        this.syncEnabled = $("input[name=syncenabled]:checkbox", this.fieldset).change($.proxy(function() {
            if (this.syncEnabled.is(":checked")) {
                this.syncPeriod.numberspinner("enable").numberspinner("enableValidation");
                this.syncPeriodUnit.combobox("enable").combobox("enableValidation");
            } else {
                this.syncPeriod.numberspinner("disable").numberspinner("disableValidation");
                this.syncPeriodUnit.combobox("disable").combobox("disableValidation");
            }
        }, this));
        this.syncPeriod = $("input[name=syncperiod]", this.fieldset).numberspinner({min: 1, max: 60, value: 60, width: 60, required: true, disabled: true});
        this.syncPeriodUnit = $("select[name=syncperiodunit]", this.fieldset).combobox({required: true, editable: false, disabled: true, width: 80, panelHeight: "auto"});

        this.testButton = $("a[role=button][name=test]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$TestButton, this)});
        this.createDbButton = $("a[role=button][name=createdb]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$CreateDbButton, 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)});

        this.notification = $(".warning", this.fieldset).hide();
    },

    getUrl: function () {
        return this.url.textbox("getValue");
    },

    setUrl: function (value) {
        this.url.textbox("setValue", value).textbox("isValid");
    },

    getUsername: function () {
        return this.username.textbox("getValue");
    },

    setUsername: function (value) {
        this.username.textbox("setValue", value).textbox("isValid");
    },

    getPassword: function () {
        return this.password.textbox("getValue");
    },

    setPassword: function (value) {
        this.password.textbox("setValue", value).textbox("isValid");
    },

    getPoolSize: function () {
        return parseInt(this.poolSize.numberspinner("getValue"));
    },

    setPoolSize: function (value) {
        this.poolSize.numberspinner("setValue", parseInt(value));
    },

    getPoolTimeout: function () {
        return parseInt(this.poolTimeout.numberspinner("getValue")) * this.TIMEOUT_FACTOR;
    },

    setPoolTimeout: function (value) {
        this.poolTimeout.numberspinner("setValue", parseInt(value) / this.TIMEOUT_FACTOR).numberspinner("validate");
    },

    getSyncPeriod: function() {
        var factor = parseInt(this.syncPeriodUnit.combobox("getValue")) || 1;
        return this.syncEnabled.is(":checked") ? parseInt(this.syncPeriod.numberspinner("getValue")) * factor : null;
    },

    setSyncPeriod: function(value) {
        value = parseInt(value);
        if (isNaN(value)) {
            this.syncEnabled.prop("checked", false).change();
        } else {
            var factor = $.fn._unitValueFor(value);
            this.syncEnabled.prop("checked", true).change();
            this.syncPeriod.numberspinner("setValue", value / factor);
            this.syncPeriodUnit.combobox("select", factor + "");
        }
    },

    setNotification: function (text) {
        if (text && text.trim().length) {
            this.notification.text(text).show();
        } else {
            this.notification.text("").hide();
        }
    },

    show: function (listener) {
        this.listener = listener || jscape.settings.ServerDatabaseView.LISTENER;
        this.fieldset.form("validate");
    },

    _valid: function() {
        return this.fieldset.form("validate");
    },

    _onChange$Form: function() {
        if (this._valid()) {
            this.listener.onChange();
        }
    },

    _onClick$TestButton: function () {
        if (this._valid()) {
            this.testButton.linkbutton("disable");
            this.listener.onTest(this)
                    .always($.proxy(function () { this.testButton.linkbutton("enable"); }, this));
        }
    },

    _onClick$CreateDbButton: function () {
        if (this._valid()) {
            this.createDbButton.linkbutton("disable");
            this.listener.onCreateDb(this)
                    .always($.proxy(function () { this.createDbButton.linkbutton("enable"); }, this));
        }
    },

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

    _onClick$DiscardButton: function() {
        this.listener.onDiscard();
    }
});
jscape.settings.ServerDatabaseView.LISTENER = {
    onChange: $.noop,
    onTest: $.noop,
    onCreateDb: $.noop,
    onApply: $.noop,
    onDiscard: $.noop
};