//deal with loading levels from XML files
//this is the only place that XML code should exist
//also there is a case to be made for refactoring this
//into a fluent API
ig.module(
    'game.xml-loader'
)
.requires(
    'game.floor',
    'game.utils',
    'game.entities.window-a',
    'game.entities.duck-spawner',
    'game.entities.pie-spawner',
    'game.level'
)
.defines(function () {
    "use strict";
    ig.global.XmlLoader = {
        levelCount: 0,
        init: function (levelData) {
            var xmlhttp = new XMLHttpRequest();
            xmlhttp.open("GET", levelData, false);
            xmlhttp.send();
            this.xmlDoc = xmlhttp.responseXML;
            this.levelCount = this.getLevelCount(this.getXStage(0));
        },

        getLevelCount: function (xstage) {
            var levels = xstage.getElementsByTagName("Level");
            return levels.length;
        },
        //The getX family of functions retrives
        //an XML DOM element for the specified
        //part of a level
        getXStage: function (num) {
            var doc = this.xmlDoc;
            var nodes = doc.getElementsByTagName("Stage");
            var retval;
            for (var i = 0; i < nodes.length; ++i) {
                var stageID = nodes.item(i).attributes.getNamedItem("ID").nodeValue;
                if (stageID == num) {
                    retval = nodes.item(i);
                }
            }
            if (retval === undefined) {
                throw new Error("Stage number " + num + "does not exist in level data");
            } else {
                return retval;
            }
        },
        getXLevel: function (xstage, num) {
            var levels = xstage.getElementsByTagName("Level");
            var retval;
            for (var i = 0; i < levels.length; ++i) {
                var levelID = levels.item(i).attributes.getNamedItem("ID").nodeValue;
                if (levelID == num) {
                    retval = levels.item(i);
                }
            }
            if (retval === undefined) {
                throw new Error("Level number" + num + " does not exist in level data");
            } else {
                return retval;
            }
        },
        getXFloor: function (xlevel, num) {
            var floors = xlevel.getElementsByTagName("Floor");
            var retval;
            for (var i = 0; i < floors.length; ++i) {
                if (floors.item(i).attributes.getNamedItem("ID").nodeValue === num) {
                    retval = floors.item(i);
                }
            }
            if (retval === undefined) {
                throw new Error("Floor number" + num + " does not exist in level data");
            } else {
                return retval;
            }
        },
        getXWindow: function (xfloor, num) {
            var windows = xfloor.getElementsByTagName("Window");
            //windows do not have IDs
            var retval = xfloor.item(i);
            if (retval === undefined) {
                throw new Error("Window number " + num + " is does not exist in level data");
            } else {
                return retval;
            }
        },
        parseXWindow: function (xwindow, windowColor) {
            var retval = ig.game.spawnEntity(EntityWindowA, 0, 0, { color: windowColor });
            switch (xwindow.attributes.getNamedItem("StateStart").nodeValue) {
                case "Broken1":
                    retval.finalAnim = retval.anims.topBroken;
                    break;
                case "Broken2":
                    retval.finalAnim = retval.anims.bothBroken;
                    break;
                case "Empty":
                    retval.finalAnim = retval.anims.bottomOpen;
                    retval.currentAnim = retval.anims.bottomOpen;
                    break;
                case "Fixed":
                    retval.finalAnim = retval.anims.fixed;
                    break;
                case "Unbreakable":
                    retval.currentAnim = retval.anims.unbreakable;
                    retval.finalAnim = retval.anims.unbreakable;
                    break;
            }
            if (xwindow.attributes.getNamedItem("ObstRight").nodeValue === "True") {
                retval.spawnObstacle('right');
            }
            if (xwindow.attributes.getNamedItem("ObstBottom").nodeValue === "True") {
                retval.spawnObstacle('down');
            }
            if (xwindow.attributes.getNamedItem("ObstLeft").nodeValue === "True") {
                retval.spawnObstacle('left');
            }
            if (xwindow.attributes.getNamedItem("ObstTop").nodeValue === "True") {
                retval.spawnObstacle('up');
            }
            return retval;

        },
        parseXFloor: function (xfloor, isFirstLevel, offset, offsetX, floorColor) {
            var options = {
                hasDoor: false,
                isAboveDoor: false
            };

            //look at the floor id to see if we need to make doors or move windows
            if (isFirstLevel && xfloor.attributes.ID.nodeValue == 0) {
                options.hasDoor = true;
            } else if (isFirstLevel && xfloor.attributes.ID.nodeValue == 1) {
                options.isAboveDoor = true;
            }

            //make our windows
            var windows = [];
            for (var i = 0; i < xfloor.childNodes.length; ++i) {
                if (xfloor.childNodes[i].nodeType === Node.ELEMENT_NODE) {
                    windows.push(this.parseXWindow(xfloor.childNodes[i], floorColor));
                }
            }
            return new Floor(parseInt(xfloor.attributes.ID.nodeValue, 10), options, windows, offset, offsetX);

        },
        parseXLevel: function (xlevel, offset, offsetX) {
            var isFirstLevel = false;
            var retval = new Level();
            if (xlevel.attributes.ID.nodeValue == 0) {
                isFirstLevel = true;
            }
            var xfloors = [];
            for (var i = 0; i < xlevel.childNodes.length; ++i) {
                if (xlevel.childNodes[i].localName === "Floor") {
                    xfloors.push(xlevel.childNodes[i]);
                }
            }
            var color = xlevel.attributes.getNamedItem("Color").nodeValue;
            for (var i = 0; i < xfloors.length; ++i) {
                retval.floors[i] = this.parseXFloor(xfloors[i], isFirstLevel, offset, offsetX, color);
                for (var j = 0; j < retval.floors[i].windows.length; ++j) {
                    //set up our event handlers
                    retval.floors[i].windows[j].onBreak = retval.handleBreak;
                    retval.floors[i].windows[j].onFixed = retval.handleFix;
                    //sync the number of broken windows in the level
                    //with the number of actually broken windows, 
                    //should only need to do this once
                    if (!retval.floors[i].windows[j].isFixed()) {
                        retval.handleBreak();
                    }
                }
            }
            //push on an extra two floors since we need a place after the ledge
            for (var i = 0; i < 2; ++i) {
                retval.floors.push(new Floor(retval.floors.length, undefined, undefined, offset, offsetX, color));
            }
            var duckSpawner = this.parseXDuck(xlevel);
            if (duckSpawner !== undefined) {
                retval.duckSpawner = duckSpawner;
            }

            var pieSpawner = this.parseXPie(xlevel);
            if (pieSpawner !== undefined) {
                retval.pieSpawner = pieSpawner;
            }

            ig.game.sortEntities();
            return retval;
        },
        parseXRalph: function (xLevel) {
            var ralphNode = xLevel.getElementsByTagName("Ralf");
            if (ralphNode.length > 1) {
                //we dont want to chug along if the XML is wrong
                //that said the definigion is wrong here is not strictly defined
                throw new Error("Malformed Level data there is more than one Ralph node");
            }
            ralphNode = ralphNode[0];
            var ralphAttributes = ralphNode.attributes;
            var ralphOptions = {};
            var getAttribute = function (attrName) {
                return parseFloat(ralphAttributes.getNamedItem(attrName).nodeValue);
            }
            //I could use looping to construct
            //the right object but I would like to
            //change some of the names and such so I will not do that
            ralphOptions.throwBrickChance = getAttribute("RandomThrowBrick");
            ralphOptions.timeBetweenBricks = getAttribute("TimeBetwinBricks");
            ralphOptions.randomArmsUp = getAttribute("RandomArmsUp");
            ralphOptions.randomYell = getAttribute("RandomYell");
            ralphOptions.throwBrickDuration = getAttribute("ThrowBrickDuration");
            ralphOptions.timeToNextWindow = getAttribute("TimeToReachNextWindows");
            ralphOptions.maxTimeBetweenThrow = getAttribute("MaximumTimeBetwinThrowBrick");
            ralphOptions.minTimeBetweenThrow = getAttribute("MinimumTimeBetwinThrowBrick");
            ralphOptions.maxTimeToBeforeYell = getAttribute("MaximumTimeBeforeYell");
            ralphOptions.minTimeBeforeYell = getAttribute("MinimumTimeBeforeYell");
            ralphOptions.maxTimeBeforeArmsUp = getAttribute("MaximumTimeBeforeArmsUp");
            ralphOptions.minTimeBeforeArmsUp = getAttribute("MinimumTimeBeforeArmsUp");
            ralphOptions.minTimeBeforeDecision = getAttribute("MinimumTimeBeforeDecision");
            ralphOptions.maxTimeBeforeDecition = getAttribute("MaximumTimeBeforeDecision");
            ralphOptions.maxWalkCycle = getAttribute("MaximumWalkCycle");
            for (var elm in ralphOptions) {
                if (isNaN(ralphOptions[elm])) {
                    throw new Error(elm + " is NaN, perhaps it was not defined in your level's Ralph section");
                }
            }
            return ralphOptions;
        },
        parseXDuck: function (xlevel) {
            var duck = xlevel.getElementsByTagName("Duck");
            var duckNode = null;
            if (duck.length === 0) {
                return undefined;
            } else {
                duckNode = duck[0];
            }

            //parse the level config file to find out duck settings
            var speed = parseFloat(duckNode.attributes.getNamedItem("DuckSpeed").nodeValue);
            var maxNum = parseFloat(duckNode.attributes.getNamedItem("SpawnRateFrom").nodeValue);
            var min = parseFloat(duckNode.attributes.getNamedItem("SpawnRateFrom").nodeValue);
            var max = parseFloat(duckNode.attributes.getNamedItem("SpawnRateTo").nodeValue);


            var retval = ig.game.spawnEntity(EntityDuckSpawner, min, max, maxNum);
            retval.vel.x = speed;
            return retval;

        },
        parseXPie: function (xlevel) {
            var pie = xlevel.getElementsByTagName("Pie");
            var defaultSettings = {
                minSpawnTime: 10,
                maxSpawnTime: 20,
                spawnProb: 0,
                maxPies: 0
            };
            var pieNode = null;
            if (pie.length === 0) {
                return ig.game.spawnEntity(EntityPieSpawner, 0, 0, defaultSettings);
            } else {
                pieNode = pie[0];
            }
            var minSpawnTime = parseFloat(pieNode.attributes.getNamedItem("SpawnRateFrom").nodeValue);
            var maxSpawnTime = parseFloat(pieNode.attributes.getNamedItem("SpawnRateTo").nodeValue);
            var spawnProb = parseFloat(pieNode.attributes.getNamedItem("Probability").nodeValue);
            var maxPies = parseFloat(pieNode.attributes.getNamedItem("NbMax").nodeValue);
            //var minSpawnTime = 0.5;
            //var maxSpawnTime = 1;
            //var spawnProb = 1;
            //var maxPies = 20;
            var spawnerSettings = {
                minSpawnTime: minSpawnTime,
                maxSpawnTime: maxSpawnTime,
                prob: spawnProb,
                maxPies: maxPies
            };
            var retval = ig.game.spawnEntity(EntityPieSpawner, 0, 0, spawnerSettings);
            return retval;

        },
        parseXBrick: function (xlevel) {
            var brick = xlevel.getElementsByTagName("Brick");
            var brickNode = null;
            if (brick.length === 0) {
                return undefined;
            } else {
                brickNode = brick[0];
            }
            var randomBreakWindow = parseFloat(brickNode.attributes.getNamedItem("RandomBreakWindow").nodeValue);
            //var randomBreakWindow = 1;
            var brickSpeed = parseFloat(brickNode.attributes.getNamedItem("Speed").nodeValue);
            var brickSettings = {
                randomBreak: randomBreakWindow,
                vel: brickSpeed
            }
            return brickSettings;
        }

    };
});
