"use strict";

describe("ContextModule.AppContext", function() {

    var serializedAppContexts = {
            "empty": {
                "stateHistory": {
                    "currentSerializedState": {
                        "musicCollectionGrid": {
                            "entityConfigs": [],
                            "viewConfigs": [],
                        },
                        "musicRecordingGrid": {
                            "entityConfigs": [],
                            "viewConfigs": [],
                        }
                    },
                    "undoStack": [],
                    "redoStack": []
                },
                "stateBookmarks": []
            },

            "empty_faulty1": {
            },
            "empty_faulty2": 42,
            "empty_faulty3": null,
            
            "empty_incomplete1": {
                "stateHistory": {
                    "currentSerializedState": {
                        "musicCollectionGrid": {
                            "entityConfigs": [],
                            "viewConfigs": [],
                        },
                    },
                    "redoStack": []
                },
                "stateBookmarks": []
            },
            "empty_incomplete2": {
                "stateHistory": {
                    "currentSerializedState": null,
                    "undoStack": [],
                    "redoStack": []
                },
                "stateBookmarks": []
            },
    };
    
    it("is promptly created", function() {
        var testedAppContext = new App.ContextModule.AppContext();
        
        expect(testedAppContext).not.toBe(null);
        
        expect(testedAppContext.get("state")).not.toBe(null);
        expect(testedAppContext.get("state") instanceof App.ContextModule.State).toBe(true);

        expect(testedAppContext.get("stateHistory")).not.toBe(null);
        expect(testedAppContext.get("stateHistory") instanceof App.ContextModule.StateHistory).toBe(true);
        
        expect(testedAppContext.get("stateBookmarks")).not.toBe(null);
        expect(testedAppContext.get("stateBookmarks") instanceof App.ContextModule.StateBookmarkCollection).toBe(true);
        
    });

    it("serializes and unserializes itself", function() {
        var testedAppContext = new App.ContextModule.AppContext();
        
        testedAppContext.unserialize(serializedAppContexts["empty"]);
        expect(testedAppContext.serialize()).toEqual(serializedAppContexts["empty"]);
        
        testedAppContext.unserialize(serializedAppContexts["empty_faulty1"]);
        expect(testedAppContext.serialize()).toEqual(serializedAppContexts["empty"]);
        
        testedAppContext.unserialize(serializedAppContexts["empty_faulty2"]);
        expect(testedAppContext.serialize()).toEqual(serializedAppContexts["empty"]);
        
        testedAppContext.unserialize(serializedAppContexts["empty_faulty3"]);
        expect(testedAppContext.serialize()).toEqual(serializedAppContexts["empty"]);
        
        testedAppContext.unserialize(serializedAppContexts["empty_incomplete1"]);
        expect(testedAppContext.serialize()).toEqual(serializedAppContexts["empty"]);

        testedAppContext.unserialize(serializedAppContexts["empty_incomplete2"]);
        expect(testedAppContext.serialize()).toEqual(serializedAppContexts["empty"]);
    });

    it("triggers change events when something changes", function() {
        var testedAppContext = new App.ContextModule.AppContext();

        var spyNames = [
                "change",
                "changeState",
                "changeStateHistory",
                "changeStateBookmarks",
            ];
        var spy = jasmine.createSpyObj("listener", spyNames);
        var expectSpyCallCount = function() {
            _.each(arguments, function(arg, i) {
                //console.log("___", i, "--->", spy[spyNames[i]].calls.count(), arg);
                expect(spy[spyNames[i]].calls.count()).toEqual(arg);
            });
            for (var i = arguments.length; i < spyNames.length; i++) {
                //console.log("___", i, "--->", spy[spyNames[i]].calls.count(), 0);
                expect(spy[spyNames[i]].calls.count()).toEqual(0);
            }
        };
        var resetSpyCallCount = function() {
            _.each(spyNames, function(spyName) {
                spy[spyName].calls.reset();
            });
        };
        var expectSpyCallCountAndReset = function() {
            expectSpyCallCount.apply(null, arguments);
            resetSpyCallCount();
        };
        
        testedAppContext.on("change", spy["change"]);
        testedAppContext.get("state").on("change", spy["changeState"]);
        testedAppContext.get("stateHistory").on("change", spy["changeStateHistory"]);
        testedAppContext.get("stateBookmarks").on("change", spy["changeStateBookmarks"]);
        
        expectSpyCallCountAndReset(0);
        
        testedAppContext.unserialize(serializedAppContexts["empty"]);
        expectSpyCallCountAndReset(0);
        
        testedAppContext.unserialize(serializedAppContexts["empty_faulty1"]);
        expectSpyCallCountAndReset(0);
        expect(testedAppContext.get("stateHistory").canUndo()).toEqual(false);
        expect(testedAppContext.get("stateHistory").canRedo()).toEqual(false);
        
        testedAppContext.get("state").get("musicCollectionGrid").entityConfigs.add(new App.ContextModule.Config({
            "parameters": {
                "x": 2,
                "y": 3,
            }
        }));
        expectSpyCallCountAndReset(1, 1, 1);
        testedAppContext.get("state").get("musicCollectionGrid").entityConfigs.at(0).planParameterUpdate("x", 10);
        expectSpyCallCountAndReset(1, 1, 1);
        testedAppContext.get("state").get("musicCollectionGrid").entityConfigs.at(0).applyPlannedParameterUpdates();
        expectSpyCallCountAndReset(1, 1, 1);
        testedAppContext.get("state").get("musicCollectionGrid").entityConfigs.at(0).planParameterUpdate("x", 10);
        expectSpyCallCountAndReset(0, 0, 0);
        expect(testedAppContext.get("state").get("musicCollectionGrid").entityConfigs.at(0).getParameterValue("x")).toEqual(10);
        expect(testedAppContext.get("state").get("musicCollectionGrid").entityConfigs.at(0).getPlannedParameterValue("x")).toEqual(10);
        expect(testedAppContext.get("state").get("musicCollectionGrid").entityConfigs.at(0).isPlannedToUpdate("x")).toEqual(false);

        testedAppContext.get("stateHistory").undo();
        expectSpyCallCountAndReset(1, 1, 1);
        expect(testedAppContext.get("stateHistory").canUndo()).toEqual(true);
        expect(testedAppContext.get("stateHistory").canRedo()).toEqual(true);
        expect(testedAppContext.get("state").get("musicCollectionGrid").entityConfigs.at(0).getParameterValue("x")).toEqual(2);
        expect(testedAppContext.get("state").get("musicCollectionGrid").entityConfigs.at(0).getPlannedParameterValue("x")).toEqual(10);
        expect(testedAppContext.get("state").get("musicCollectionGrid").entityConfigs.at(0).isPlannedToUpdate("x")).toEqual(true);
        
        testedAppContext.get("stateHistory").undo();
        testedAppContext.get("stateHistory").undo();
        expectSpyCallCountAndReset(2, 2, 2);
        expect(testedAppContext.get("stateHistory").canUndo()).toEqual(false);
        expect(testedAppContext.get("stateHistory").canRedo()).toEqual(true);
        expect(testedAppContext.get("state").get("musicCollectionGrid").entityConfigs.size()).toEqual(0);

        testedAppContext.get("stateHistory").redo();
        expectSpyCallCountAndReset(1, 1, 1);
        expect(testedAppContext.get("stateHistory").canUndo()).toEqual(true);
        expect(testedAppContext.get("stateHistory").canRedo()).toEqual(true);

        testedAppContext.unserialize(serializedAppContexts["empty"]);
        expectSpyCallCountAndReset(1, 1, 1);
        expect(testedAppContext.get("stateHistory").canUndo()).toEqual(false);
        expect(testedAppContext.get("stateHistory").canRedo()).toEqual(false);
    });
});
