jscape.account = jscape.account || {};

/** @class */
jscape.account.PublicKeyAuthenticationModule = jscape.ApplicationModule.extend(
    /** @lends {jscape.account.PublicKeyAuthenticationModule.prototype} */
{
    onCreate: function() {
        this.controller = new jscape.account.PublicKeyAuthenticationController();
    },

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

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

/** @class */
jscape.account.PublicKeyAuthenticationController = Class.extend(
    /** @lends {jscape.account.PublicKeyAuthenticationController.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.view = new jscape.account.PublicKeyAuthenticationView();

        this.generateController = new jscape.account.GenerateKeyPairController();
        this.importController = new jscape.account.ImportPublicKeyController();
        this.deleteController = new jscape.account.DeletePublicKeyController();

        this._initValidators();
    },

    start: function() {
        this.view.show(this);
    },

    onResume: function() {
    },

    onGenerateKey: function() {
        this.generateController.start()
                .done($.proxy(this._fireApplySuccess, this, window.R.string.PUBLIC_KEY_SUCCESS_CREATED));
    },

    onImportKey: function() {
        this.importController.start()
                .done($.proxy(this._fireApplySuccess, this, window.R.string.PUBLIC_KEY_SUCCESS_IMPORTED));
    },

    onDeleteKey: function() {
        this.deleteController.start()
                .done($.proxy(this._fireApplySuccess, this, window.R.string.PUBLIC_KEY_SUCCESS_DELETED));
    },

    _initValidators: function() {
        var v = new jscape.Validator();
        v.rule("file_password_confirm", $.proxy(this._passwordConfirmed, this), window.R.string.PUBLIC_KEY_BAD_CONFIRM_PWD);
    },

    _passwordConfirmed: function (value, params) {
        return params && params.length && $(params[0]).val() == value;
    },

    _fireApplySuccess: function(message) {
        $(document).triggerHandler("broadcast", [message]);
    }
});

/** @class */
jscape.account.PublicKeyAuthenticationView = Class.extend(
    /** @lends {jscape.account.PublicKeyAuthenticationView.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.fieldset = $("fieldset[name=publicauthfields]");

        this.generateButton = $("a[role=button][name=generate]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$GenerateButton, this)});
        this.importButton = $("a[role=button][name=import]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$ImportButton, this)});
        this.deleteButton = $("a[role=button][name=delete]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$DeleteButton, this)});
    },

    show: function(listener) {
        this.listener = listener || jscape.account.PublicKeyAuthenticationView.LISTENER;
        this._adjustState();
    },

    _onClick$GenerateButton: function() {
        this.listener.onGenerateKey();
    },

    _onClick$ImportButton: function() {
        this.listener.onImportKey();
    },

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

    _adjustState: function() {
    }
});
jscape.account.PublicKeyAuthenticationView.LISTENER = {
    onGenerateKey: $.noop,
    onImportKey: $.noop,
    onDeleteKey: $.noop
};

/** @class */
jscape.account.GenerateKeyPairController = Class.extend(
    /** @lends {jscape.account.GenerateKeyPairController.prototype} */
{
    DEFAULT_FILE_TYPE: "PEM",

    deferred: null,

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

    onSubmit: function(dialog) {
        jscape.API.generateKeyPair(dialog.getKeyType(),
                                   dialog.getKeyLength(),
                                   dialog.getFileType(),
                                   dialog.getFilePassword())
                .done($.proxy(function(info) { this.deferred.resolve(info); this.deferred = null; }, this))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this))
                .always(function() { dialog.destroy(); });
    },

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

    onChangeKeyType: function(dialog) {
        dialog.setKeyLengths(jscape.KeyPairAlgorithm.lengthsOf(dialog.getKeyType()));
    },

    _setupDialog: function() {
        var dialog = new jscape.account.GenerateKeyPairDialog();
        dialog.setKeyTypes(jscape.KeyPairAlgorithm.values());
        dialog.setFileType(this.DEFAULT_FILE_TYPE);
        return dialog;
    }
});

/** @class */
jscape.account.GenerateKeyPairDialog = Class.extend(
    /** @lends {jscape.account.GenerateKeyPairDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.dialog = $("#d-pubkeyauth-generate").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, handler: $.proxy(this._onSubmit, this)},
                {text: window.R.string.DIALOG_BUTTON_CANCEL, handler: $.proxy(this._onCancel, this)}
            ],
            onClose: $.proxy(function () {if (!this.closing) { this._onCancel(); }}, this)
        }).show();

        this.fieldset = $("fieldset[name=keypairfields]", this.dialog);

        this.keyType = $("select[name=type]", this.fieldset).combobox({required: true, editable: false, width: 120, panelHeight: "auto", onChange: $.proxy(this._onChange$KeyType, this)});
        this.keyLength = $("select[name=length]", this.fieldset).combobox({required: true, editable: false, width: 120, panelHeight: "auto"});
        this.fileType = $("input[name=filetype]:radio", this.fieldset);

        var id = $.now().toString(36);
        this.password = $("input[name=password]", this.fieldset).attr("id", id).passwordbox({lastDelay: 0, validateOnBlur: true, width: "50%"});
        this.password.passwordbox("textbox").on("input", $.proxy(function() {
            this.confirmPassword.passwordbox("textbox").validatebox("options").required = this.password.textbox("textbox").val().length != 0;
            this.confirmPassword.passwordbox("validate");
        }, this));
        this.confirmPassword = $("input[name=confirmpwd]", this.fieldset).passwordbox({lastDelay: 0, validateOnBlur: true, validType: "file_password_confirm['#" + id + "']", missingMessage: window.R.string.PUBLIC_KEY_BAD_CONFIRM_PWD, width: "50%"});
    },

    getKeyType: function() {
        return this.keyType.combobox("getValue");
    },

    setKeyTypes: function(values) {
        var data = $.map(values || [], function(item) { return {text: item.name, value: item.name}; });
        this.keyType.combobox("loadData", data);
    },

    getKeyLength: function() {
        return parseInt(this.keyLength.combobox("getValue"));
    },

    setKeyLengths: function(values) {
        this.keyLength.combobox("loadData", values);
    },

    getFileType: function() {
        return this.fileType.filter(":checked").val();
    },

    setFileType: function(value) {
        this.fileType.filter("[value=" + value + "]").prop("checked", true).change();
    },

    getFilePassword: function() {
        return this.password.passwordbox("getValue");
    },

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

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

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

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

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

    _onChange$KeyType: function() {
        this.listener.onChangeKeyType(this);
    },

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

/** @class */
jscape.account.ImportPublicKeyController = Class.extend(
    /** @lends {jscape.account.ImportPublicKeyController.prototype} */
{
    DEFAULT_FILE_TYPE: "SSH",

    deferred: null,

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

    onSubmit: function(dialog) {
        jscape.API.importPublicKey(dialog.getFile(), dialog.getFileType())
                .done($.proxy(function(info) { this.deferred.resolve(info); this.deferred = null; }, this))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this))
                .always(function() { dialog.destroy(); });
    },

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

    _setupDialog: function() {
        var dialog = new jscape.account.ImportPublicKeyDialog();
        dialog.setFileType(this.DEFAULT_FILE_TYPE);
        return dialog;
    }
});

/** @class */
jscape.account.ImportPublicKeyDialog = Class.extend(
    /** @lends {jscape.account.ImportPublicKeyDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        var template = $("#d-pubkeyauth-import");
        this.dialog = template.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, handler: $.proxy(this._onSubmit, this)},
                {text: window.R.string.DIALOG_BUTTON_CANCEL, handler: $.proxy(this._onCancel, this)}
            ],
            onClose: $.proxy(function () {if (!this.closing) { this._onCancel(); }}, this)
        }).show();

        this.fieldset = $("fieldset[name=publickeyfields]", this.dialog);

        this.file = $("input[name=file]", this.fieldset).validatebox({required: true}).change(function() { $(this).validatebox("validate"); });
        this.type = $("input[name=filetype]:radio", this.fieldset);
    },

    getFile: function() {
        return this.file[0].files[0];
    },

    getFileType: function() {
        return this.type.filter(":checked").val();
    },

    setFileType: function(value) {
        this.type.filter("[value=" + value + "]").prop("checked", true).change();
    },

    show: function (listener) {
        this.listener = listener;
        this.dialog.dialog("center").dialog("open");
        this.fieldset.form("validate");
        this.file.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");
    },

    _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.account.DeletePublicKeyController = Class.extend(
    /** @lends {jscape.account.DeletePublicKeyController.prototype} */
{
    deferred: null,

    start: function() {
        return this._confirmDelete()
                .then($.proxy(this._deleteConfirmed, this));
    },

    _confirmDelete: function() {
        return jscape.ConfirmDialog.confirm(window.R.string.PUBLIC_KEY_CONFIRM_DELETE_TITLE,
                                            window.R.string.PUBLIC_KEY_CONFIRM_DELETE_MESSAGE);
    },

    _deleteConfirmed: function() {
        return jscape.API.deletePublicKey();
    }
});