"use strict";

App.module("ContextModule", function(ContextModule, App, Backbone, Marionette, $, _, Logger) {

    // Define private variables
    var logger = null;

    ContextModule.addInitializer(function(options){
        
        logger = Logger.get("ContextModule.AppContext");
        logger.setLevel(Logger.DEBUG);
        
        /**
         * AppContext is an object that describes the current user’s environment.
         * It keeps the current state, a history of states and state bookmarks.
         */
        ContextModule.AppContext = Backbone.Model.extend({
            defaults: function() {
                return {
                    state: new ContextModule.State(),
                    stateHistory: new ContextModule.StateHistory(),
                    stateBookmarks: new ContextModule.StateBookmarkCollection()
                };
            },

            /**
             * @memberOf App.ContextModule.AppContext
             */
            initialize: function() {
                this._modificationPropagationEnabled = true;
                this._linkBetweenStateAndStateHistoryEnabled = true;
                this._attributesWereModified = false;

                this._registerStateChange();
                
                this.attributes.state.bind("change", this._registerStateChange, this);
                this.attributes.stateHistory.bind("change", this._registerStateHistoryChange, this);
                this.attributes.stateBookmarks.bind("change", this._registerStateBookmarksChange, this);
            },

            /**
             * @memberOf App.ContextModule.AppContext
             */
            serialize: function() {
                //logger.debug("method called: AppContext::serialize");
                var result = {
                        stateHistory: this.attributes.stateHistory.serialize(),
                        stateBookmarks: this.attributes.stateBookmarks.serialize(),
                };
                
                return result;
            },
            
            /**
             * @memberOf App.ContextModule.AppContext
             */
            unserialize: function(serializedAttributes) {
                //logger.debug("method called: AppContext::unserialize");
                this._modificationPropagationEnabled = false;
                
                var fixedSerializedAttributes = serializedAttributes;
                if (!_.isSimpleObject(fixedSerializedAttributes)) {
                    logger.warn("AppContext::unserialize called for not an object: ", serializedAttributes);
                    fixedSerializedAttributes = {};
                }
                this.attributes.stateBookmarks.unserialize(fixedSerializedAttributes.stateBookmarks);
                
                var serializedStateHistory = fixedSerializedAttributes["stateHistory"];
                if (!_.isSimpleObject(serializedStateHistory)) {
                    serializedStateHistory = {};
                }
                this._linkBetweenStateAndStateHistoryEnabled = false;
                this.attributes.state.unserialize(serializedStateHistory.currentSerializedState);
                serializedStateHistory.currentSerializedState = this.attributes.state.serialize();
                this.attributes.stateHistory.unserialize(serializedStateHistory);
                this._linkBetweenStateAndStateHistoryEnabled = true;
                
                this._triggerModificationEventsIfNeeded();
                this._modificationPropagationEnabled = true;
            },
            
            _registerStateChange: function() {
                if (this._linkBetweenStateAndStateHistoryEnabled) {
                    this.attributes.stateHistory.set("currentSerializedState", this.attributes.state.serialize());
                }
                this._registerModificationOfAttribute();
            },

            _registerStateHistoryChange: function() {
                if (this._linkBetweenStateAndStateHistoryEnabled) {
                    this.attributes.state.unserialize(this.attributes.stateHistory.get("currentSerializedState"));
                }
                if (this._stateHistoryModificationPropagationEnabled) {
                    this._registerModificationOfAttribute();
                }
            },
            
            _registerStateBookmarksChange: function() {
                this._registerModificationOfAttribute();
            },
            
            _registerModificationOfAttribute: function() {
                this._attributesWereModified = true;
                if (this._modificationPropagationEnabled) {
                    this._triggerModificationEventsIfNeeded();
                };
            },

            _triggerModificationEventsIfNeeded: function() {
                if (this._attributesWereModified) {
                    this.trigger("change");
                }
                this._attributesWereModified = false;
            },
        });

    });
}, Logger);
