var MazeManager = Class.create({
  
    initialize: function() {
  
        // Bind events
        Event.observe(document, 'keydown', this.move.bind(this));
  
        // Set maze look and feel
        this.resX = 640;
        this.resY = 480;
        this.normalBackgroundColor = "#FFFFEE";
        this.startBackgroundColor = "#CCFFCC";
        this.activeBackgroundColor = "#CCCCFF";
        this.endBackgroundColor = "#FFCCCC";
        this.visitedBackgroundColor = "#EEEEEE";
        this.borderColor = "#333333";
        this.borderThickness = 1;
        
        this.timer = new MazeTimer();

        // Controls
        this.controls = {
            'up': 38, /* up arrow */
            'down': 40, /* down arrow */
            'left': 37, /* left arrow */
            'right': 39 /* right arrow */
        };

    },
  
    getBlockId: function(row, column) {
        return 'block' + row + '-' + column;
    },
  
    buildMaze: function() {

        // Set rows and columns
        this.rows = this.maze.length;
        this.columns = this.maze[0].length;

        // Set the current (start) and end points
        for (var row = 0; row < this.maze.length; row++) {
            for (var column = 0; column < this.maze[row].length; column++) {
                if (this.maze[row][column]['start'] === true) {
                    this.startRow = row;
                    this.startColumn = column;
                    this.currentRow = row;
                    this.currentColumn = column;
                } else if (this.maze[row][column]['end'] === true) {
                    this.endRow = row;
                    this.endColumn = column;
                }
            }
        }
    
        // (resolutionX - borderWidth) / columnsCount
        var rowBorderWidth = (this.columns * this.borderThickness) + 
            this.borderThickness;
        var width = Math.floor((this.resX - rowBorderWidth) / this.columns); 
        // (resolutionY - borderWidth) / rowCount
        var columnBorderWidth = (this.rows * this.borderThickness) + 
            this.borderThickness;
        var height = Math.floor((this.resY - columnBorderWidth) / this.rows);
        
        var actualResX = (width * this.columns) + this.columns + 1;
        var actualResY = (height * this.rows) + this.rows + 1;
        var halfActualResX = Math.floor(actualResX / 2);
        
        // Create maze container
        var divMaze = new Element('div', {'id': 'maze'});
        divMaze.setStyle({
            'width': actualResX + "px",
            'height': actualResY + "px",
            'marginLeft': "-" + halfActualResX + "px"
        });
        
        // Build maze blocks
        for (var row = 0; row < this.rows; row++) {
            
            for (var column = 0; column < this.columns; column++) {
        
                // Top & left positions
                var top = 0;
                var left = 0;
                if (column > 0) {
                    left = (column * width) + (this.borderThickness * column) + 
                        this.borderThickness;
                }
                if (row > 0) {
                    top = (row * height) + (this.borderThickness * row) + 
                        this.borderThickness;
                }    
            
                // BG color
                var bgColor = this.normalBackgroundColor;
                if(row === this.startRow && column === this.startColumn) {
                    bgColor = this.startBackgroundColor;
                } else if (row === this.endRow && column === this.endColumn) {
                    bgColor = this.endBackgroundColor;
                }
                
                var mazeBlock = new Element('div', {'id': this.getBlockId(row, 
                    column)});
                mazeBlock.setStyle({
                    'background': bgColor,
                    'width': width + 'px',
                    'height': height + 'px',
                    'position': 'absolute',
                    'top': top + 'px',
                    'left': left + 'px',
                    'padding': '0px',
                    'margin': '0px'
                });
                if (row === 0) {
                    mazeBlock.setStyle({'borderTop': this.borderThickness + 
                        'px solid ' + this.borderColor});
                }
                if (column === 0) {
                    mazeBlock.setStyle({
                        'borderLeft': this.borderThickness + 'px solid ' + 
                            this.borderColor,
                        'clear': 'left'
                    });
                }

                var borderBottomColor = this.normalBackgroundColor;
                var borderRightColor = this.normalBackgroundColor;
                if (this.maze[row][column]['bottomWall'] === true) {
                    borderBottomColor = this.borderColor;
                }
                if (this.maze[row][column]['rightWall'] === true) {
                    borderRightColor = this.borderColor;
                }
                mazeBlock.setStyle({
                    'borderBottom': this.borderThickness + 'px solid ' + 
                        borderBottomColor,
                    'borderRight': this.borderThickness + 'px solid ' + 
                        borderRightColor
                });
                
                mazeBlock.update('&nbsp;');
                
                divMaze.appendChild(mazeBlock);
            
            }
        
        }
        
        // Append maze to document.
        $('middle').update();
        $('middle').appendChild(divMaze);
        
        // Make maze playable
        this.active = true;
        
    },
    
    solved: function() {
        this.timer.stop();
        this.active = false;
    },
  
    move: function(e) {
        
        // Annoying compatibility code. Prototype may handle this?
        if (!e) var e = window.event;
	if (e.keyCode) code = e.keyCode;
	else if (e.which) code = e.which;
        
        if (!this.active) {
            return;
        }
        
        var stopEvent = false;

        var destRow, destColumn, currentWallToBreach;

        switch (code) {
        
            case this.controls['up']:
                destRow = this.currentRow - 1;
                destColumn = this.currentColumn;
                currentWallToBreach = 'topWall';
                stopEvent = true;
                break;
                
            case this.controls['down']:
                destRow = this.currentRow + 1;
                destColumn = this.currentColumn;
                currentWallToBreach = 'bottomWall';
                stopEvent = true;
                break;
        
            case this.controls['left']:
                destRow = this.currentRow;
                destColumn = this.currentColumn - 1;
                currentWallToBreach = 'leftWall';
                stopEvent = true;
                break;
        
            case this.controls['right']:
                destRow = this.currentRow;
                destColumn = this.currentColumn + 1;
                currentWallToBreach = 'rightWall';
                stopEvent = true;
                break;
            
            default:
                destRow = null;
                destColumn = null;
                currentWallToBreach = null;
                
        }
        
        if (destRow !== null && destColumn !== null) {
            
            // Check if destination is in bounds
            if (destRow >= 0 && destRow < this.rows && 
                    destColumn >= 0 && destColumn < this.columns) {
                
                // Make sure there isn't a wall
                if (!this.maze[this.currentRow][this.currentColumn][currentWallToBreach]) {
                    
                    // Start the timer
                    if (!this.timer.alive) {
                        this.timer.start();
                    }
                    
                    // Set style of new block
                    $(this.getBlockId(destRow, destColumn)).setStyle(
                        {'background': this.activeBackgroundColor});
                    
                    // Set style of old block
                    var oldBlockBackgroundColor = this.visitedBackgroundColor;
                    if (this.currentRow === this.startRow && 
                            this.currentColumn === this.startColumn) {
                        var oldBlockBackgroundColor = this.startBackgroundColor;
                    }
                    
                    $(this.getBlockId(this.currentRow, this.currentColumn)).setStyle(
                        {'background': oldBlockBackgroundColor});
                    
                    // Set style of border between new and old block
                    var borders = {
                        'leftWall': {'current': 'borderLeft', 'dest':'borderRight'},
                        'rightWall': {'current': 'borderRight', 'dest':'borderLeft'},
                        'topWall': {'current': 'borderTop', 'dest':'borderBottom'},
                        'bottomWall': {'current': 'borderBottom', 'dest':'borderTop'}
                    };
/*
                    var borderStyle = {};
                    borderStyle[borders[currentWallToBreach]['current']] = 
                        oldBlockBackgroundColor;
                    $(this.getBlockId(this.currentRow, this.currentColumn)).setStyle(
                        borderStyle);
                        
                    borderStyle = {};
                    borderStyle[borders[currentWallToBreach]['dest']] = 
                        this.activeBackgroundColor;
                    $(this.getBlockId(destRow, destColumn)).setStyle(borderStyle);                          
*/
                    // Set dest row and column to current
                    this.currentRow = destRow;
                    this.currentColumn = destColumn;
                    
                    // Check if puzzle was solved
                    if (destRow === this.endRow && destColumn === this.endColumn) {
                        this.solved();   
                    }
                    
                }
                
            }
            
        }
        
        if (stopEvent === true) {
            Event.stop(e);
        }
        
    }
    
});
