#include "BoardLayout.h"
#include <tqfile.h>
#include <tqtextstream.h>
#include <tqtextcodec.h>





BoardLayout::BoardLayout()
{
	filename="";
	clearBoardLayout();
}

BoardLayout::~BoardLayout()
{
}

void BoardLayout::clearBoardLayout() {
	loadedBoard="";
	initialiseBoard();	
}

bool BoardLayout::saveBoardLayout(const TQString where) {
	TQFile f(where);
	if (!f.open(IO_ReadWrite)) {
	    return false;
	}

	TQCString tmp = layoutMagic1_0.utf8();
	if (f.writeBlock(tmp, tmp.length()) == -1) {
	    return(false);	
	}

	for (int z=0; z<depth; z++) {
	    for(int y=0; y<height; y++) {
		if(f.putch('\n')==-1)
		    return(false);
		for (int x=0; x<width; x++) {
		if (board[z][y][x]) {
		    if(f.putch(board[z][y][x])==-1)
		       return false;
		} else {
		    if(f.putch('.')==-1)
			return false;
		}
		}
	    }
	}
	if(f.putch('\n')!=-1)
	    return true;
	else
	    return false;
}


bool BoardLayout::loadBoardLayout(const TQString from)
{
    
    if (from == filename) {
	return true;	
    } 

    TQFile f(from);
    TQString all = "";

    if ( f.open(IO_ReadOnly) ) {    
 	TQTextStream t( &f );
        t.setCodec(TQTextCodec::codecForName("UTF-8"));
	TQString s;
	s = t.readLine();
	if (s != layoutMagic1_0) {
	    f.close();
	    return(false);
	}
	int lines = 0;
	while ( !t.eof() ) {        
	    s = t.readLine();
	    if (s[0] == '#')
		continue;
	    all += s;
	    lines++;
	}
	f.close();
	if (lines == height*depth) {
	    loadedBoard = all;
	    initialiseBoard();
	    filename = from;
	    return(true);
	} else {
	    return(false);
	}
	return(true);
    } else {
	return(false);
    }
}

void BoardLayout::initialiseBoard() {

    short z=0;
    short x=0;          // Rand lassen.
    short y=0;
    maxTileNum = 0;

    const char *pos = (const char *) loadedBoard.ascii();

    memset( &board, 0, sizeof( board) );

    if (loadedBoard.isEmpty())
	return;

    // loop will be left by break or return
    while( true )
    {
        BYTE c = *pos++;

        switch( c )
        {
            case (UCHAR)'1': maxTileNum++;
            case (UCHAR)'3':
            case (UCHAR)'2':
            case (UCHAR)'4': board[z][y][x] = c;
                             break;

            default:         break;
        }
        if( ++x == width)
        {
            x=0;
            if( ++y == height)
            {
                y=0;
                if( ++z == depth)
                {
                    // number of tiles have to be even
                    if( maxTileNum & 1 ) break;
                    return;
                }
            }
        }
    }
}

void BoardLayout::copyBoardLayout(UCHAR *to , unsigned short &n){

    memcpy(to, board, sizeof(board));
    n = maxTileNum;
}

const char* BoardLayout::getBoardLayout()
{
	return loadedBoard.ascii();
}    



void BoardLayout::shiftLeft() {
    for (int z=0; z<depth; z++) {
	for (int y=0; y<height; y++) {
	    UCHAR keep=board[z][y][0];
	    if (keep == '1') {
	        // tile going off board, delete it
	        board[z][y][0]=0;
	        board[z][y][1]=0;
	        board[z][y+1][0]=0;
	        board[z][y+1][1]=0;
	    }
	    for (int x=0; x<width-1; x++) {
		board[z][y][x] = board[z][y][x+1];
	    }
	    board[z][y][width-1] = 0;
	}
    }
}


void BoardLayout::shiftRight() {
    for (int z=0; z<depth; z++) {
	for (int y=0; y<height; y++) {
	    UCHAR keep=board[z][y][width-2];
	    if (keep == '1') {
	        // tile going off board, delete it
	        board[z][y][width-2]=0;
	        board[z][y][width-1]=0;
	        board[z][y+1][width-2]=0;
	        board[z][y+1][width-1]=0;
	    }
	    for (int x=width-1; x>0; x--) {
		board[z][y][x] = board[z][y][x-1];
	    }
	    board[z][y][0] = 0;
	}
    }
}
void BoardLayout::shiftUp() {
    for (int z=0; z<depth; z++) {
	// remove tiles going off the top
	for (int x=0; x<width; x++) {
	    if (board[z][0][x] == '1') {
		board[z][0][x] = 0;
		board[z][0][x+1] = 0;
		board[z][1][x] = 0;
		board[z][1][x+1] = 0;
	    }
	}
    }
    for (int z=0; z<depth;z++) {
	for (int y=0; y<height-1; y++) {
	    for (int x=0; x<width; x++) {
		board[z][y][x]=board[z][y+1][x];
		if (y == height-2)
			board[z][y+1][x]=0;
	    }
        }
    }
}


void BoardLayout::shiftDown() {
    for (int z=0; z<depth; z++) {
	// remove tiles going off the top
	for (int x=0; x<width; x++) {
	    if (board[z][height-2][x] == '1') {
		board[z][height-2][x] = 0;
		board[z][height-2][x+1] = 0;
		board[z][height-1][x] = 0;
		board[z][height-1][x+1] = 0;
	    }
	}
    }
    for (int z=0; z<depth;z++) {
	for (int y=height-1; y>0; y--) {
	    for (int x=0; x<width; x++) {
		board[z][y][x]=board[z][y-1][x];
		if (y == 1)
			board[z][y-1][x]=0;
	    }
        }
    }
}





// is there a tile anywhere above here (top left to bot right quarter)
bool BoardLayout::tileAbove(short z, short y, short x) {
    if (z >= depth -1)
        return false;
    if( board[z+1][y][x]   || board[z+1][y+1][x] || board[z+1][y][x+1] || board[z+1][y+1][x+1] ) {
        return true;
    }
    return false;
}  


bool BoardLayout::blockedLeftOrRight(short z, short y, short x) {
     return( (board[z][y][x-1] || board[z][y+1][x-1]) &&
             (board[z][y][x+2] || board[z][y+1][x+2]) );
}

void BoardLayout::deleteTile(POSITION &p) {
    if ( p.e <depth && board[p.e][p.y][p.x] == '1') {
        board[p.e][p.y][p.x]=0;
        board[p.e][p.y][p.x+1]=0;
        board[p.e][p.y+1][p.x]=0;
        board[p.e][p.y+1][p.x+1]=0;
        maxTileNum--;
    }
} 

bool BoardLayout::anyFilled(POSITION &p) {
    return(board[p.e][ p.y][ p.x] != 0 ||
           board[p.e][ p.y][ p.x+1] != 0 ||
           board[p.e][ p.y+1][ p.x] != 0 ||
           board[p.e][ p.y+1][ p.x+1] != 0);
}
bool BoardLayout::allFilled(POSITION &p) {
    return(board[p.e][ p.y][ p.x] != 0 &&
           board[p.e][p.y][ p.x+1] != 0 &&
           board[p.e][p.y+1][ p.x] != 0 &&
           board[p.e][p.y+1][ p.x+1] != 0);
}
void BoardLayout::insertTile(POSITION &p) {
    board[p.e][p.y][p.x] = '1';
    board[p.e][p.y][p.x+1] = '2';
    board[p.e][p.y+1][p.x+1] = '3';
    board[p.e][p.y+1][p.x] = '4';
}