ig.module('game.entities.ralph')
.requires(
    'impact.impact',
    'impact.input',
    'impact.entity',
    'game.path',
    'game.config',
    'game.utils',
    'game.behavior',
    'game.entities.brick'
)
.defines(function () {
    "use strict"; 
    ig.global.EntityRalph = ig.Entity.extend({
        movementSheet: new ig.AnimationSheet(IMG.PREFIX + 'ralph.png', IMG.SIZE(300), IMG.SIZE(327)),
        endSheet: new ig.AnimationSheet(IMG.PREFIX + 'ralph_end.png', IMG.SIZE(200), IMG.SIZE(280)),
        smashSheet: new ig.AnimationSheet(IMG.PREFIX + 'ralph_smash.png', IMG.SIZE(260), IMG.SIZE(116)),
        endingAnims: [],
        movementAnims: [],
        gravityFactor: 0,
        size: { x: IMG.SIZE(300), y: IMG.SIZE(327) },
        offset: { x: IMG.SIZE(80), y: IMG.SIZE(85) },
        aiOptions: {},
        transitionLock: false,
        renderLock: false,
        behaviorTimers: {},
        zIndex: 4,
        init: function (x, y, settings) {
            //specify movement and regular gameplay anims
            this.movementAnims.idle = new ig.Animation(this.movementSheet, 0.1, [6]);
            this.movementAnims.attack = new ig.Animation(this.movementSheet, 100, [1, 2]);
            this.movementAnims.climb = new ig.Animation(this.movementSheet, 0.15, [3, 4]);
            this.movementAnims.walkLeft = new ig.Animation(this.movementSheet, 0.08, [7, 8]);
            this.movementAnims.walkRight = new ig.Animation(this.movementSheet, 0.08, [9, 10]);
            this.movementAnims.yell = new ig.Animation(this.movementSheet, 0.25, [0, 11]);
            this.movementAnims.jump = new ig.Animation(this.movementSheet, 0.25, [0, 1, 0], true);

            //specify anims that will be played in the ending scene
            this.endingAnims.idle = new ig.Animation(this.endSheet, 0.1, [0]);
            this.endingAnims.carry = new ig.Animation(this.endSheet, 0.1, [1]);
            this.endingAnims.smash = new ig.Animation(this.smashSheet, 2, [0, 1], true);
            this.endingAnims.fall = new ig.Animation(this.movementSheet, 0.1, [5]);

            this.currentAnim = this.movementAnims.idle;
            this.gridPosition = { floor: y, window: x };
            var realx = ig.game.level.getPosition(x, y).x;
            var realy = ig.game.level.getPosition(x, y).y;
            this.path = this.getPathToTop();
            this.timer = new ig.Timer();
            this.initTimers();
            this.decisionDelay = 0;
            //we bind a timer to the function, nobody but this particular
            //funtion will have access to it
            ig.game.player.lock = true;
            this.behavior = Behavior.followPath.bind(window, new ig.Timer(), this, this.getPathToTop(), Behavior.jump.bind(window, new ig.Timer(), this));
            this.currentAnim = this.movementAnims.climb;
            this.parent(realx, realy, settings);
        },
        initTimers: function () {
            this.behaviorTimers.brick = new ig.Timer();
            this.behaviorTimers.yell = new ig.Timer();
        },
        update: function () {
            if (!this.transitionLock) {
                if (this.timer.delta() > this.decisionDelay) {
                    //this.currentAnim = this.movementAnims.idle;
                    this.decisionDelay = Math.random(this.aiOptions.minTimeBeforeDecision,
                        this.aiOptions.maxTimeBeforeDecision);
                    this.behavior();
                }

            }
            //ig.show("BrickTimer", this.behaviorTimers.brick.delta());
            this.parent();
        },
        draw: function() {
            if(!this.renderLock) {
                this.parent();
            }
        },
        //get the path to initially travel
        //when climbing up the building
        //this is "hardcoded" for now, 
        //no pathfinding needed
        getPathToTop: function () {
            var dirs = Utils.directionsEnum;
            return new Path(this.gridPosition, [
                dirs.LEFT,
                dirs.UP,
                dirs.LEFT,
                dirs.UP,
                dirs.RIGHT,
                dirs.RIGHT,
                dirs.UP,
                dirs.LEFT,
                dirs.LEFT,
                dirs.LEFT,
                dirs.UP,
                dirs.RIGHT,
                dirs.UP,
                dirs.LEFT], 0.3);

        },
        //gets a standard path to a destination, for example
        //if I call getPathto({floor: 3, window: 2}) I would get a 
        //path from Ralph's current position to that position
        getPathTo: function (destination) {
            var path = [];
            var curPos = this.gridPosition;
            var distanceX = destination.window - curPos.window;
            var distanceY = destination.floor - curPos.floor;
            //self invoking function that
            //goes and generates the x path positions
            function genPath(path, dist, lessDir, greaterDir) {
                if (dist === 0) {
                    return;
                } else if (dist < 0) {
                    path.push(lessDir);
                    genPath(path, dist + 1, lessDir, greaterDir);
                } else if (dist > 0) {
                    path.push(greaterDir);
                    genPath(path, dist - 1, lessDir, greaterDir);
                }
            };
            genPath(path, distanceX, Utils.directionsEnum.LEFT, Utils.directionsEnum.RIGHT);
            genPath(path, distanceY, Utils.directionsEnum.UP, Utils.directionsEnum.DOWN);
            return new Path(curPos, path, this.aiOptions.timeToNextWindow + 0.5);

        },
        //force ralph to go into the idle state
        forceIdle: function() {
            this.behavior = Behavior.idle.bind(window, new ig.Timer(), this, ig.game.player);
        }
    });
});
