/*

Quicktetris published by Thomas Kjeldahl Nilsson under 
Creative Commons Attribution 3.0 license.
License terms: http://creativecommons.org/licenses/by/3.0/

*/

/*
Tetris piece shape represented as 4x4 matrix. Example for the square structure:

0000
0110 
0110 
0000 
 	
We define and hold each topology/shape in memory as singletons,
point 'currShape' reference to the one that matches current state.
So we never create more than the one piece, we just change its 
state and "blueprint" from time to time.

We use four constant "tile" sprites to draw the areas marked '1' in the shape.
NOTE: Currently limited to four sprites, shapes with more marked slots won't work.

Piece position is x, y location of upper left corner of matrix.
*/

// Define all the possible piece topologies
//  xx
//  xx : square
var square0dg = [[0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]];

var squareRotations = [square0dg];

//  xxxx : line
var line0dg = [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]];

var line90dg = [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]];

var lineRotations = [line0dg, line90dg];

//   x
//  xxx : tee
var tee0dg = [[0, 0, 1, 0], [0, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]];
var tee90dg = [[0, 0, 1, 0], [0, 0, 1, 1], [0, 0, 1, 0], [0, 0, 0, 0]];
var tee180dg = [[0, 0, 0, 0], [0, 1, 1, 1], [0, 0, 1, 0], [0, 0, 0, 0]];
var tee270dg = [[0, 0, 1, 0], [0, 1, 1, 0], [0, 0, 1, 0], [0, 0, 0, 0]];

var teeRotations = [tee0dg, tee90dg, tee180dg, tee270dg];

//  xx
// xx  : left hook
var lhook0dg = [[0, 0, 1, 0], [0, 1, 1, 0], [0, 1, 0, 0], [0, 0, 0, 0]];
var lhook90dg = [[0, 1, 1, 0], [0, 0, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]];

var lhookRotations = [lhook0dg, lhook90dg];

// xx
//  xx  : right hook
var rhook0dg = [[0, 0, 1, 0], [0, 0, 1, 1], [0, 0, 0, 1], [0, 0, 0, 0]];
var rhook90dg = [[0, 0, 1, 1], [0, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]];

var rhookRotations = [rhook0dg, rhook90dg];

//  x
//  x
// xx  : left L
var leftL0dg = [[0, 0, 1, 0], [0, 0, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]];
var leftL90dg = [[0, 1, 0, 0], [0, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]];
var leftL180dg = [[0, 0, 1, 1], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 0, 0]];
var leftL270dg = [[0, 1, 1, 1], [0, 0, 0, 1], [0, 0, 0, 0], [0, 0, 0, 0]];

var leftLRotations = [leftL0dg, leftL90dg, leftL180dg, leftL270dg];

//  x
//  x
//  xx  : right L
var rightL0dg = [[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 1], [0, 0, 0, 0]];
var rightL90dg = [[0, 0, 0, 0], [0, 1, 1, 1], [0, 1, 0, 0], [0, 0, 0, 0]];
var rightL180dg = [[0, 1, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 0, 0]];
var rightL270dg = [[0, 0, 0, 1], [0, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]];

var rightLRotations = [rightL0dg, rightL90dg, rightL180dg, rightL270dg];

var Piece = {

    // Piece state
    State: {
        piecePos: {
            x: 0,
            y: 0
        },
        color: "black",
        currRotation: squareRotations[0],
        currShape: squareRotations,
        rotationCounter: 0,
        tiles: [null, null, null, null],
        // The four sprites that make up the piece
        tileWidth: 23,
        tileHeight: 30
    },

    drawSingleTile: function(xSlot, ySlot, tileNo) {
        var derivedX = this.State.piecePos.x + (xSlot * this.State.tileWidth);
        var derivedY = this.State.piecePos.y + (ySlot * this.State.tileHeight);
        this.State.tiles[tileNo].style.top = derivedY;
        this.State.tiles[tileNo].style.left = derivedX;
    },

    redraw: function() {
        var tileCounter = 0;
        this.State.currRotation.eachWithIndexes(function(element, x, y) {
            if (element === 1) { // Is the matrix slot ticked?
                Piece.drawSingleTile(x, y, tileCounter);
                tileCounter++;
            }
        });
        tileCounter = 0;
    },

    move: function(dx, dy) {
        var directionIsDown = (dy > 0);

        var collisionCheck = Field.checkCollisions(this.State.piecePos.x, this.State.piecePos.y, this.State.currRotation, directionIsDown, dx, dy);
        if (collisionCheck.collides) {
            if (collisionCheck.sticks) {
                Field.mergeShapeIntoField(this.State.piecePos.x, this.State.piecePos.y, this.State.currRotation);

		Sound.playLandingSound();
                this.reset();
                this.isGameOver();
            }
        }
        else {
            this.State.piecePos.x += dx;
            this.State.piecePos.y += dy;
            this.redraw();
        }
    },

    // Reset piece pos to middle of middle, top
    reset: function() {
        this.State.piecePos.x = Field.State.posX + ((Field.WIDTH / 2) * this.State.tileWidth) - (2 * this.State.tileWidth);
        this.State.piecePos.y = Field.State.posY - (this.State.tileHeight * 2);
        this.setRandomShape();
        this.redraw();
    },

    // Game over if game unable to place new piece in field.
    isGameOver: function() {
        var gameEndingCollision = Field.checkCollisions(this.State.piecePos.x, this.State.piecePos.y, this.State.currRotation, true, 0, 0);
        if (gameEndingCollision.collides) {
            QuickTetris.gotoGameOver();
        }
    },

    moveUp: function(speed) {
        this.move(0, -(speed));
    },
    moveDown: function(speed) {
        this.move(0, speed);
    },
    moveLeft: function(speed) {
        this.move( - (speed), 0);
    },
    moveRight: function(speed) {
        this.move(speed, 0);
    },

    init: function(color) {
        rotationCounter = 0;

        var width = this.State.tileWidth;
        var height = this.State.tileHeight;

        if (!color) { // Assume colorful test pattern
            this.State.tiles[0] = Graphics.createRectangleDiv("green", 0, 0, width, height);
            this.State.tiles[1] = Graphics.createRectangleDiv("yellow", 0, 0, width, height);
            this.State.tiles[2] = Graphics.createRectangleDiv("orange", 0, 0, width, height);
            this.State.tiles[3] = Graphics.createRectangleDiv("red", 0, 0, width, height);
        }
        else {
            this.State.tiles[0] = Graphics.createRectangleDiv(color, 0, 0, width, height);
            this.State.tiles[1] = Graphics.createRectangleDiv(color, 0, 0, width, height);
            this.State.tiles[2] = Graphics.createRectangleDiv(color, 0, 0, width, height);
            this.State.tiles[3] = Graphics.createRectangleDiv(color, 0, 0, width, height);
        }

        this.reset();
    },

    setRandomShape: function() {
        var random = Math.floor(Math.random() * 7);

        switch (random) {
        case 0:
            this.toggleSquareShape();
            break;
        case 1:
            this.toggleLineShape();
            break;
        case 2:
            this.toggleTeeShape();
            break;
        case 3:
            this.toggleRHookShape();
            break;
        case 4:
            this.toggleLHookShape();
            break;
        case 5:
            this.toggleRightLShape();
            break;
        case 6:
            this.toggleLeftLShape();
            break;
        }
    },

    rotate: function(doCollisionCheck) {
        this.State.rotationCounter++;
        if (this.State.rotationCounter == this.State.currShape.length) {
            this.State.rotationCounter = 0;
        }

        if (doCollisionCheck) {
            var collisionCheck = Field.checkCollisions(this.State.piecePos.x, this.State.piecePos.y, this.State.currShape[this.State.rotationCounter], false, 0, 0);
            if (collisionCheck.collides) {
                return;
            }
        }

        this.State.currRotation = this.State.currShape[this.State.rotationCounter];
	
	Sound.playRotationSound();

        this.redraw();
    },

    resetRotation: function() {
        this.State.currRotation = this.State.currShape[0];
        this.State.rotationCounter = 0;
        this.redraw();
    },

    toggleSquareShape: function() {
        this.State.currShape = squareRotations;
        this.resetRotation();
    },

    toggleLineShape: function() {
        this.State.currShape = lineRotations;
        this.resetRotation();
    },

    toggleTeeShape: function() {
        this.State.currShape = teeRotations;
        this.resetRotation();
    },

    toggleRHookShape: function() {
        this.State.currShape = rhookRotations;
        this.resetRotation();
    },

    toggleLHookShape: function() {
        this.State.currShape = lhookRotations;
        this.resetRotation();
    },

    toggleLeftLShape: function() {
        this.State.currShape = leftLRotations;
        this.resetRotation();
    },

    toggleRightLShape: function() {
        this.State.currShape = rightLRotations;
        this.resetRotation();
    }

};