/*
 * LeLevel
 *
 * Level Object
 */

import Block from './Block.js';

export default class LeLevel {

    constructor(whole, mapname) {

        this.whole = whole;

        this.game = this.whole.game;

        this.mapname = mapname;

        this.stats = {};

    }


    preload() {
        this.lodingres = this.game.load.tilemap(this.mapname, 'level/' + this.mapname + '.json', null, Phaser.Tilemap.TILED_JSON);
    }

    _newBlock(x = 0, y = 0, index = -10) {
        if (index == -10) {
            index = this.tilemap.layers[0].data[y][x].index;
        }
        if (index !== -1) {
            return new Block(this, x, y, index-1);
        } else {
            return index;
        }
    }

    init(x = 0, y = 0) {


        // this._tgroup = this.game.add.group();
        this._blockgroup = this.game.add.group();

        this.tilemap = this.game.add.tilemap(this.mapname);

        this.x = x;
        this.y = y; 

        this.width = this.tilemap.width;
        this.height = this.tilemap.height;
        this.tileWidth = this.tilemap.tileWidth;
        this.tileHeight = this.tilemap.tileHeight;

        this._blockgroup.pivot.x = (this.width * this.tileWidth)>>1;
        this._blockgroup.pivot.y =  (this.height * this.tileHeight)>>1;

        this._grid = [];

        for (var tx = 0; tx < this.width; tx++ ) {
            for (var ty = 0; ty < this.width; ty++ ) {
                this._setGridBlock(tx, ty, this._newBlock( tx, ty) );
                if (typeof this._getGridBlock(tx, ty) === 'object') {
                    this._blockgroup.add(this._getGridBlock(tx, ty));
                }
            }
        }

        if (this.x === -1) {
            this.x = (this.whole.game.width>>1) ;
        }
        if (this.y === -1) {
            this.y = (this.whole.game.height>>1) ;
        }

        this._blockgroup.x = this.x;
        this._blockgroup.y = this.y;

        this.topx = this.x - ( (this.width * this.tileWidth) >> 1);
        this.topy = this.y - ( (this.height * this.tileHeight) >> 1);

        // console.log(this._blockgroup);
        //
        // console.log(this.x, this.y);

        // console.log(this.tilemap, this._grid);

        this.levelStats();
    }

    shiftUp()   {this._shiftBlocks(0);}
    shiftRight(){this._shiftBlocks(1);}
    shiftDown() {this._shiftBlocks(2);}
    shiftLeft() {this._shiftBlocks(3);}

    _shiftBlocks(direction = 1) {

        var s = this.whole.gamestate.selector;

         // get all blocks in the row and add them to a temporary group


        this._tgroup = this.game.add.group();
        this._blockgroup.add(this._tgroup);

        this._tgroupblocks = [];

        // console.log(this._grid, ty);

        // compensate rotation
        var angle = Math.round( (this._blockgroup.angle / 90)) % 4;
        if (angle < 0)
            angle += 4;
        // console.log(direction, angle, ((direction - angle) + 4 )% 4);
        direction = ((direction - angle) + 4)  % 4;


        var cy = s.y - this.topy;
        cy = Math.round(cy / this.tileHeight);
        var cx = s.x - this.topx;
        cx = Math.round(cx / this.tileWidth);


        // HORIZONTAL
        if (direction == 1 || direction == 3) {
            // console.log('horizontal');
            var ty = cy;

            if (angle == 2)
                ty = 8 - ty;

            if (!this._canMove(4, ty, direction)) {
                return;
            }

            for (var tx = 0; tx < this.width; tx++) {
                if (typeof this._grid[tx+ty*this.width] === 'object') {
                    // console.log(typeof this._grid[tx+ty*this.width], tx, ty);
                    this._tgroup.add(this._getGridBlock(tx,ty));
                    this._tgroupblocks.push(this._getGridBlock(tx,ty));
                }
            }

        // VERTICAL
        } else {
            // console.log('vertical');
            var tx = cy;

            if (angle == 3)
                tx = 8 - cy;

            if (!this._canMove(tx, 4, direction)) {
                return;
            }

            for (var ty = 0; ty < this.height; ty++) {
                if (typeof this._grid[tx+ty*this.width] === 'object') {
                    // console.log(typeof this._grid[tx+ty*this.width], tx, ty);
                    this._tgroup.add(this._getGridBlock(tx,ty));
                    this._tgroupblocks.push(this._getGridBlock(tx,ty));
                }
            }

        }

        this.removeTGroupBlocksFromGrid();

        var animdir = {x: 0, y: 0};

        if (direction === 0) {
            animdir.y = -this.tileHeight;
        }
        if (direction === 1) {
            animdir.x = this.tileWidth;
        }
        if (direction === 2) {
            animdir.y = this.tileHeight;
        }
        if (direction === 3) {
            animdir.x = -this.tileWidth;
        }


        this._diffx = animdir.x;
        this._diffy = animdir.y;

        var animate = this.game.add.tween( this._tgroup );

        animate.to( animdir,
            this.whole.gamesettings.animation.speed,
            this.whole.gamesettings.animation.easing );


        // ON COMPLETE
        // --------------
        animate.onComplete.add(function() {

            // console.log('animate complete');

            // PUT BLOCKS BACK into the grid and update all references
            this._tgroupblocks.forEach(function( currblock ){

                // manual internal position update
                // TODO: make sure this workaround funzt in future versions
                currblock.position.y +=  this._diffy;
                currblock.position.x +=  this._diffx;

                // update the block's grid posititon
                if (this._diffx>0) {
                    currblock.grid_x++;
                } else if (this._diffx<0) {
                    currblock.grid_x--;
                }
                if (this._diffy>0) {
                    currblock.grid_y++;
                } else if (this._diffy<0) {
                    currblock.grid_y--;
                }

                // remove from temp group
                this._tgroup.remove(currblock);

                // add to main group
                this._blockgroup.add(currblock);



            }, this);

            // destroy old group
            this._tgroup.destroy(false);

            this.addTGroupBlocksToGrid();

            // this.echoGrid(); 
            
            this.whole.isAnimating = false; 
            
            this.whole.hazWinning(); 

        }, this);


        // START ANIMATION
        // -------------------
        this.whole.sounds.leftright.play();
        animate.start();

        // this.echoGrid();

    }

    removeTGroupBlocksFromGrid() {
        this._tgroupblocks.forEach(function( currblock ){
            this._setGridBlock(currblock.grid_x, currblock.grid_y, -1);
        }, this);
    }

    addTGroupBlocksToGrid() {
        this._tgroupblocks.forEach(function( currblock ){
            this._setGridBlock(currblock.grid_x, currblock.grid_y, currblock);
        }, this);
    }

    echoGrid() {
        for (var ty = 0; ty < this.height; ty++) {
            var str = '';
            for (var tx = 0; tx < this.width; tx++) {
                if (this._getGridBlock(tx, ty) == -1) {
                    str += '-';
                } else {
                    str += this._getGridBlock(tx,ty).blockindex;
                }
            }
            // console.log(str);
        }
    }

    _getGridBlock(x, y) {
        return this._grid[x+y*this.width];
    }
    _setGridBlock(x, y, block) {
        this._grid[x+y*this.width] = block;
    }

    rotate(degrees = '+90') {

        var animdir = {angle: degrees};

        var animate = this.game.add.tween( this._blockgroup );

        animate.to(animdir,
            this.whole.gamesettings.animation.speed,
            this.whole.gamesettings.animation.easing);


        // ON COMPLETE
        // --------------
        animate.onComplete.add(function () {
            // console.log('animdone');
            this.whole.isAnimating = false;
        }, this);

        this.whole.sounds.rotate.play();
        animate.start();

    }

    _canMove(cx, cy, direction) {

        var result = true;

        // console.log('canmove', cx, cy, this._getGridBlock(cx, cy));
        // this.echoGrid();

        // sitting on empty block
        if (this._getGridBlock(cx, cy) == -1) {
            result = false;
        }

        // have space at the border
        if (result) {
            switch (direction) {
            case 0:
                if (this._getGridBlock(cx, 0) !== -1)
                    result = false;
                break;
            case 1:
                if (this._getGridBlock(8, cy) !== -1)
                    result = false;
                break;
            case 2:
                if (this._getGridBlock(cx, 8) !== -1)
                    result = false;
                break;
            case 3:
                if (this._getGridBlock(0, cy) !== -1)
                    result = false;
                break;
            }
        }

        if (!result) {
            // TODO: play sound
            this.whole.sounds.error.play();
            this.whole.isAnimating = false;
            return false;
        }

        return true;
    }

    levelStats() {

        this._blockgroup.forEach(function(item) {
            if (item.blockindex > 0) {
                if (typeof this.stats[item.blockindex] == "undefined") {
                    this.stats[item.blockindex] = 1;
                    // console.log(this.stats[item.index]);
                } else {
                    this.stats[item.blockindex]++;
                    // console.log(this.stats[item.index]);
                }
            }
        }, this);

        // console.log(this.stats);
    }

    allConnected() {
        var result = true;
        Object.keys(this.stats).forEach(function(entry) {
            if (!this._areConnected(entry))
                result = false;
        }, this);

        return result;
    }

    // find first occurence of block with this id
    _findFirstOccurence(blockid) {
        for (var ty = 0; ty < this.height; ty++) {
            for (var tx = 0; tx < this.width; tx++) {
                if (this._getGridBlock(tx, ty) !== -1) {
                    // console.log(this._getGridBlock(tx, ty).blockindex, blockid);
                    if (this._getGridBlock(tx, ty).blockindex == blockid) {
                        // console.log('_findFirstOccurence', tx, ty);
                        return tx + ty * this.width;
                    }
                }
            }
        }
    }

    _getConnectedLineBlocks(tx, ty) {
        // check horizontal
        var blockid = this._getGridBlock(tx, ty).blockindex;

        var hazx = 0;
        for (var x = 0; x < this.width; x++) {
            if (   (this._getGridBlock(x, ty) !== -1)
                && (this._getGridBlock(x, ty).blockindex == blockid) ) {
                hazx++;
            } else if (hazx>0) {
                // interrupted
                x = this.width;
            }
        }

        var hazy = 0;
        for (var y = 0; y < this.height; y++) {
            if (   (this._getGridBlock(tx, y) !== -1)
                && (this._getGridBlock(tx, y).blockindex == blockid) ) {
                hazy++;
            } else if (hazy>0) {
                // interrupted
                y = this.height;
            }
        }

        if (hazx > hazy) {
            return hazx;
        }
        return hazy;
    }

    _areConnected(blockid) {

        var firstpos = this._findFirstOccurence( blockid );

        // console.log('areconnected: ', firstpos, firstpos % this.width, Math.floor(firstpos/this.width));

        var connectedblocks = this._getConnectedLineBlocks( firstpos % this.width, Math.floor(firstpos/this.width));

        // console.log(blockid, 'first: ', firstpos, connectedblocks);

        if (connectedblocks == this.stats[blockid]) {
            return true;
        }

        return false;
    }
}
