define([
    'pgui.user_management_api',
    'pgui.localizer',
    'libs/sprintf',
    'pgui.utils',
    'pgui.change_password_dialog',
    'bootbox',
    'mootools-core',
    'jquery.tmpl',
    'knockout'
], function (PhpGenUserManagementApi, localizer, sprintf, utils) {

    return function () {

        window.PhpGenAdmin.Utils =
        {
            showProgressCursor: function () {
                $('body').addClass('cursor-progress');
            },

            hideProgressCursor: function () {
                $('body').removeClass('cursor-progress');
            }
        };

        window.PhpGenAdmin.UserViewModel = new Class({
            initialize: function (api, id, name, password, email, status, editable) {
                this.api = api;
                this.id = id;
                this.name = ko.observable(name);
                this.password = password;
                this.email = ko.observable(email);
                this.status = ko.observable(status);
                this.editable = ko.observable(editable);
                this.grantsLoaded = ko.observable(false);
                this.grantsExpanded = ko.observable(false);
                this.grants = ko.observableArray([]);
            },

            _loadGrants: function () {
                this.api.getUserGrants(this.id).done(function (grants) {
                    for (var i = 0; i < grants.length; i++) {
                        this.grants.push(
                            new PhpGenAdmin.UserPageGrantsViewModel(
                                this.api,
                                this.id,
                                grants[i].name,
                                grants[i].caption,
                                grants[i].selectGrant,
                                grants[i].updateGrant,
                                grants[i].insertGrant,
                                grants[i].deleteGrant,
                                grants[i].adminGrant
                            )
                        );
                    }
                    this.grantsLoaded(true);
                }.bind(this));
            },

            collapseGrants: function () {
                this.grantsExpanded(false);
            },

            expandGrants: function () {
                if (!this.grantsExpanded()) {
                    this.grantsExpanded(true);
                    if (!this.grantsLoaded())
                        this._loadGrants();
                }
            },

            toggleGrantsExpanded: function () {
                if (!this.grantsExpanded()) {
                    this.grantsExpanded(true);
                    if (!this.grantsLoaded())
                        this._loadGrants();
                }
                else {
                    this.grantsExpanded(false);
                }
            }
        });

        window.PhpGenAdmin.UserPageGrantsViewModel = new Class({
            initialize: function (api, userId, pageName, caption, selectGrant, updateGrant, insertGrant, deleteGrant, adminGrant) {
                this.api = api;
                this.userId = userId;
                this.pageName = ko.observable(pageName);
                this.caption = ko.observable(caption);
                this.selectGrant = ko.observable(selectGrant);
                this.updateGrant = ko.observable(updateGrant);
                this.insertGrant = ko.observable(insertGrant);
                this.deleteGrant = ko.observable(deleteGrant);
                this.adminGrant = ko.observable(adminGrant);

                this.selectGrant.subscribe(function (newValue) {
                    this._updateUserGrant('SELECT', newValue)
                }.bind(this));
                this.updateGrant.subscribe(function (newValue) {
                    this._updateUserGrant('UPDATE', newValue)
                }.bind(this));
                this.insertGrant.subscribe(function (newValue) {
                    this._updateUserGrant('INSERT', newValue)
                }.bind(this));
                this.deleteGrant.subscribe(function (newValue) {
                    this._updateUserGrant('DELETE', newValue)
                }.bind(this));
                this.adminGrant.subscribe(function (newValue) {
                    this._updateUserGrant('ADMIN', newValue)
                }.bind(this));
            },

            isApplication: function() {
                return this.pageName().length === 0;
            },

            _updateUserGrant: function (grantName, newValue) {
                PhpGenAdmin.Utils.showProgressCursor();
                (function () {
                    if (newValue)
                        return this.api.addUserGrant(this.userId, this.pageName(), grantName);
                    else
                        return this.api.removeUserGrant(this.userId, this.pageName(), grantName);
                }.bind(this))()
                    .always(function () {
                        PhpGenAdmin.Utils.hideProgressCursor();
                    })
                    .fail(function (message) {
                        utils.showErrorMessage(message);
                    });

            }
        });

        window.PhpGenAdmin.AdminPanelViewModel = function (api) {
            this.api = api;

            this.newUser =
            {
                id: ko.observable(''),
                name: ko.observable('New user'),
                password: ko.observable(''),
                confirmedPassword: ko.observable(''),
                email: ko.observable('')
            };

            this.changePasswordUser =
            {
                id: ko.observable(''),
                name: ko.observable('')
            };

            this.editUser =
            {
                id: ko.observable(''),
                name: ko.observable('Edit user'),
                password: ko.observable(''),
                email: ko.observable(''),
                status: ko.observable('')
            };

            this.currentUserRoles = ko.observableArray([]);

            this.invokeRemoveUserDialog = function (/*UserViewModel*/user) {
                var self = this;

                bootbox.confirm(
                    sprintf.sprintf(localizer.getString('DeleteUserConfirmation'), user.name()),
                    function (isConfirmed) {
                        if (!isConfirmed) {
                            return;
                        }

                        PhpGenAdmin.Utils.showProgressCursor();
                        self.api.removeUser(user.id)
                            .done(function (result) {
                                self.users.remove(user);
                            }.bind(this))
                            .always(function () {
                                PhpGenAdmin.Utils.hideProgressCursor();
                            }).fail(function (message) {
                                utils.showErrorMessage(message);
                            });
                    }
                );

            };

            this.invokeChangeUserPasswordDialog = function (user) {
                var self = this;
                self.changePasswordUser.id(user.id);
                self.changePasswordUser.name(user.name());
                PhpGenChangePasswordDialog.open();
            };

            this.invokeEditUserDialog = function (user) {
                var self = this;
                var dialog = $("#pg-admin-edit-user-dialog");

                self.editUser.id(user.id);
                self.editUser.name(user.name());
                self.editUser.password(user.password);
                self.editUser.email(user.email());
                self.editUser.status(user.status());

                $('#save-edit-user-dialog').bind('click', function (e) {
                    e.preventDefault();

                    if (self.emailBasedFeaturesEnabled) {
                        self.api.updateUser(self.editUser.id(), self.editUser.name(), self.editUser.email(), self.editUser.status())
                            .fail(function (message) {
                                utils.showErrorMessage(message);
                            })
                            .done(function (result) {
                                user.name(result.name);
                                user.email(result.email);
                                user.status(result.status);
                            });
                    } else {
                        self.api.changeUserName(self.editUser.id(), self.editUser.name())
                            .fail(function (message) {
                                utils.showErrorMessage(message);
                            })
                            .done(function (result) {
                                user.name(result.username);
                            });
                    }
                    dialog.modal('hide');
                });

                dialog.modal('show');
                $('#user-username').focus();
                dialog.bind('hidden.bs.modal', function () {
                    $('#save-edit-user-dialog').unbind('click');
                    dialog.unbind('hidden.bs.modal');
                });
            };

            this.expandAllGrants = function () {
                for (var i = 0; i < this.users().length; i++) {
                    this.users()[i].expandGrants();
                }
            };

            this.collapseAllGrants = function () {
                for (var i = 0; i < this.users().length; i++) {
                    this.users()[i].collapseGrants();
                }
            };

            this.invokeAddUserDialog = function () {
                var self = this;
                var dialog = $("#pg-admin-create-user-dialog");
                var confirmedPasswordErrorControl = $("#newuser-confirmed-password-error");

                self.newUser.id('');
                self.newUser.name('New user');
                self.newUser.password('');
                self.newUser.confirmedPassword('');
                confirmedPasswordErrorControl.hide();
                self.newUser.email('');

                $('#save-create-user-dialog').bind('click', function (e) {
                    e.preventDefault();

                    if (!PhpGenPasswordDialogUtils.validateConfirmedPassword(
                            self.newUser.password(), self.newUser.confirmedPassword(),
                            confirmedPasswordErrorControl)) {
                        return;
                    }

                    if (self.emailBasedFeaturesEnabled) {
                        self.api.addUserEx(self.newUser.name(), self.newUser.password(), self.newUser.email())
                            .fail(function (message) {
                                utils.showErrorMessage(message);
                            })
                            .done(function (result) {
                                self.users.push(
                                    new PhpGenAdmin.UserViewModel(
                                        self.api,
                                        result.id,
                                        result.name,
                                        result.password,
                                        result.email,
                                        0,
                                        true
                                    ));
                            });
                    } else {
                        self.api.addUser(self.newUser.name(), self.newUser.password())
                            .fail(function (message) {
                                utils.showErrorMessage(message);
                            })
                            .done(function (result) {
                                self.users.push(
                                    new PhpGenAdmin.UserViewModel(
                                        self.api,
                                        result.id,
                                        result.name,
                                        result.password,
                                        '', 0,
                                        true
                                    ));
                            });
                    }
                    dialog.modal('hide');
                });

                dialog.modal('show');
                $('#newuser-id').focus();

                dialog.bind('hidden.bs.modal', function () {
                    $('#save-create-user-dialog').unbind('click');
                    dialog.unbind('hidden.bs.modal');
                });
            };

            this.users = ko.observableArray([]);

            this.usersOnCurrentPage = ko.dependentObservable(function () {
                return this.users.slice(0, this.users().length).sort(function (a, b) {
                    if (a.id === -1 || a.id === 0) {
                        if (b.id === 0) {
                            return 1;
                        }

                        return -1;
                    }

                    if (a.name() < b.name()) {
                        return -1;
                    } else if (a.name() > b.name()) {
                        return 1
                    }

                    return 0;
                });
            }, this);
        };

        var api = PhpGenUserManagementApi;
        window.PhpGenAdmin.adminPanelViewModel = new PhpGenAdmin.AdminPanelViewModel(api);
        PhpGenAdmin.adminPanelViewModel.emailBasedFeaturesEnabled = PhpGenAdmin.EmailBasedFeaturesEnabled;

        var i;
        for (i = 0; i < PhpGenAdmin.CurrentUsers.length; i++)
            PhpGenAdmin.adminPanelViewModel.users.push(
                new PhpGenAdmin.UserViewModel(
                    api,
                    PhpGenAdmin.CurrentUsers[i].id,
                    PhpGenAdmin.CurrentUsers[i].name,
                    PhpGenAdmin.CurrentUsers[i].password,
                    PhpGenAdmin.CurrentUsers[i].email,
                    PhpGenAdmin.CurrentUsers[i].status,
                    PhpGenAdmin.CurrentUsers[i].editable
                ));

        ko.applyBindings(PhpGenAdmin.adminPanelViewModel);

        PhpGenChangePasswordDialog.initialize(new PhpGenChangePasswordDialogAdminStrategy(
            function (newPassword) {
                return api.changeUserPassword(PhpGenAdmin.adminPanelViewModel.changePasswordUser.id, newPassword);
            }));

        $("#pg-admin-create-user-dialog").modal({show: false});
        $("#pg-admin-edit-user-dialog").modal({show: false});

    };

});
