define(['./group.js'], function (Group) {
    /**
     * Undo/Save object
     * @class Undo
     * @constructor
     * @property {Array} history - array of actions performed since last save.
     */
    var Undo = function() {"use strict";
        this.model = new Undo.Model();
        this.view = new Undo.View();
        this.model.setView(this.view);
        this.view.setModel(this.model);
        this.view.init();
    };

    Undo.Model = function() {"use strict";
        this.view = null;

        /**
         * Array of actions
         * @private
         * @type {Array}
         */
        this.history = [];
    };

    Undo.Model.prototype = (function() {"use strict";
        /**
         * Undo field move
         * @private
         * @memberOf Undo
         * @param {Object} revert - Undo history object
         * @returns {Object} Undo
         */
        var undoMove = function(revert) {
            _.each(revert.fields, function(field) {
                var sourceGroup = Instance.Groups.collection.getByGroupId(revert.sourceGroup);
                var targetGroup = Instance.Groups.collection.getByGroupId(revert.targetGroup);
                var targetIndex = _.findIndex(targetGroup.model.fields.collection.fields, function(content) {
                    return field.symName === content.model.symName;
                });
                sourceGroup.model.fields.collection.fields.push(targetGroup.model.fields.collection.fields[targetIndex]);
                targetGroup.model.fields.collection.fields.splice(targetIndex, 1);
            });
            cla.showMessage(lmsg('infocapture.admin.field_groups.message_title'), lmsg('infocapture.admin.field_groups.undo_group_field_move'), 0);
            return this;
        };

        /**
         * Undo delete group
         * @private
         * @memberOf Undo
         * @param {Object} revert - Undo history object
         * @returns {Object} Undo
         */
        var undoDelete = function(revert) {
            var instance = new Group({
                id : revert.id,
                name : revert.name,
                fields : {},
                dropdown : {}
            });
            Instance.Groups.collection.groups.splice(revert.index, 0, instance);
            if (revert.move.fields.length > 0) {
                undoMove(revert.move);
            }
            cla.showMessage(lmsg('infocapture.admin.field_groups.message_title'), lmsg('infocapture.admin.field_groups.undo_group_delete'), 0);
            return this;
        };

        /**
         * Undo edit group name
         * @private
         * @memberOf Undo
         * @param {Object} revert - Undo history object
         * @returns {Object} Undo
         */
        var undoEdit = function(revert) {
            var group = Instance.Groups.collection.getByGroupId(revert.id);
            group.model.name = revert.oldName;
            cla.showMessage(lmsg('infocapture.admin.field_groups.message_title'), lmsg('infocapture.admin.field_groups.undo_group_edit'), 0);
            return this;
        };

        /**
         * Undo add group
         * @private
         * @memberOf Undo
         * @param {Object} revert - Undo history object
         * @returns {Object} Undo
         */
        var undoAdd = function(revert) {
            var groupIndex = Instance.Groups.collection.getIndexByGroupId(revert.id);
            cla.showMessage(lmsg('infocapture.admin.field_groups.message_title'), lmsg('infocapture.admin.field_groups.undo_group_add', _.escape(Instance.Groups.collection.groups[groupIndex].model.name)), 0);
            Instance.Groups.collection.groups.splice(groupIndex, 1);
            return this;
        };

        /**
         * Revert the last item in the history array
         * @public
         * @memberOf Undo
         * @returns {Object} Undo
         */
        var addHistory = function(obj) {
            this.history.push(obj);
            this.view.toggleVisibility();
            return this;
        };

        /**
         * Revert the last item in the history array
         * @public
         * @memberOf Undo
         * @returns {Object} Undo
         */
        var undo = function() {
            if (Instance.Undo.model.history.length > 0) {
                var revert = Instance.Undo.model.history.pop();
                switch(revert.action) {
                    case 'move' :
                        undoMove(revert);
                        break;
                    case 'delete' :
                        undoDelete(revert);
                        break;
                    case 'edit' :
                        undoEdit(revert);
                        break;
                    case 'add' :
                        undoAdd(revert);
                        break;
                }
                Instance.Groups.view.render();
            }
            Instance.Undo.view.toggleVisibility();
            return this;
        };

        /**
         * Save changes to the groups
         * @public
         * @memberOf Undo
         * @returns {Object} Undo
         */
        var save = function() {
            $(this).hide();
            $('#saving').show();
            $('#save').hide();
            $('#undo').hide();
            var group;
            if (Instance.Undo.model.history.length > 0) {
                var sync = Instance.Undo.model.history.shift();
                switch(sync.action) {
                    case 'move' :
                        xajax_group_move_fields(sync.sourceGroup, sync.targetGroup, sync.fields, projectId);
                        break;
                    case 'delete' :
                        xajax_group_delete(sync.id, projectId);
                        break;
                    case 'edit' :
                        //console.log(sync);
                        xajax_group_update({
                            id : sync.id,
                            name : sync.newName
                        }, window.projectId);
                        break;
                    case 'add' :
                        xajax_group_add({
                            id : sync.id,
                            name : sync.name
                        }, window.projectId);
                        break;
                }
            } else {
                cla.showMessage('', lmsg('infocapture.admin.general.changes_saved'), false);
                Instance.Undo.view.toggleVisibility();
            }
            return this;
        };

        var setView = function(view) {
            this.view = view;
        };

        var updateGroupId = function(previous, current) {
            _.each(Instance.Undo.model.history, function(sync) {
                switch(sync.action) {
                    case 'move' :
                        if (sync.sourceGroup === parseInt(previous, 10)) {
                            sync.sourceGroup = parseInt(current, 10);
                        } else if (sync.targetGroup === parseInt(previous, 10)) {
                            sync.targetGroup = parseInt(current, 10);
                        }
                        break;
                    case 'delete' :
                    case 'edit' :
                        if (sync.id === parseInt(previous, 10)) {
                            sync.id = parseInt(current, 10);
                        }
                        break;
                }
            });
        };

        return {
            /**
             * @public
             * @memberOf Undo.Model
             */
            addHistory : addHistory,

            /**
             * @public
             * @memberOf Undo.Model
             */
            undo : undo,

            /**
             * @public
             * @memberOf Undo.Model
             */
            save : save,

            setView : setView,

            updateGroupId : updateGroupId
        };
    })();

    Undo.View = function() {"use strict";
        this.model = null;
    };

    Undo.View.prototype = (function() {"use strict";
        /**
         * Toggle the save and undo buttons
         * @private
         * @memberOf Undo.View
         * @returns {Object} Undo
         */
        var toggleVisibility = function() {
            var undoButton = $('#undo');
            var saveButton = $('#save');
            var savingButton = $('#saving');
            if (Instance.Undo.model.history.length > 0) {
                undoButton.fadeIn();
                saveButton.fadeIn();
            } else {
                undoButton.fadeOut();
                saveButton.fadeOut();
                savingButton.fadeOut();
            }
            return this;
        };

        var setModel = function(model) {
            this.model = model;
        };

        return {
            /**
             * Initialise object
             * @public
             * @memberOf Undo.View
             */
            init : function() {
                $('#undo').on('click', this.model.undo);
                $('#save').on('click', this.model.save);
            },

            /**
             * @public
             * @memberOf Undo.View
             */
            toggleVisibility : toggleVisibility,

            setModel : setModel
        };
    })();

    return Undo;
});
