#include <stdio.h>

#include "board.h"
#include "utils.h"
#include "direction.h"

int 		try_swap(board_t*,int row, int col);

unsigned char	*positioned;
char		is_stat;	/* Is status display enabled! */

main(int argc, char *argv[])
{
	int 	row=3,col=3;
	int 	ctrl,i,j,ret,seed;
	int	cur_row, cur_col;
	board_t	board;

	setbuf(stdout,NULL);
	memset(&board,0,sizeof(board));	
	
	if(argc >= 2) {
		row=col=atoi(argv[1]); /* dimensions given as first arg */
		if(argc >=3) {
			if(strcmp(argv[1],"-f")) 
				seed=atoi(argv[2]);
			else {
				/* read board from file */
				board = read_board_file(argv[2]); 
				row=col=board.row;
			}
		}
		if(argc >=4)
			is_stat=1;	/* status display enabled */
	}	

	/* positioned holds the status of each cell in the board */	
	positioned = (char*) malloc(row*col*sizeof(char));
	if(positioned == NULL)
		die(1,"Low Memory");
	memset(positioned,0,row*col);
	
	/* if board is not read from file */
	if(!board.row) { 
		/* make a board randomly with above dimensions*/
		board = make_board(row, col);
		if(board.row != row)
			die(1,"Low Memory");
		srand(seed);
		for(i=0;i<row;i++)
			for(j=0;j<col;j++) {
				int val;
				while(positioned[val= rand()%(row*col) ]) 
					srand(rand());
				/*printf("%d\n",val);*/
				board.cell[i][j] = val;
				positioned[val]=1; /*cell is alloted*/
			}
	}

	memset(positioned,0,row*col);
	print_board(board);
	
	ctrl=0;
	while(ctrl<row) {
	for(i=ctrl;i<row;i++) {
		for(j=ctrl;j<((i==ctrl)?col:(ctrl+1));j++) {
			if(i==row-1 && j==col-1)
				break;
			ret=0;
			while(board.cell[i][j] != i*row + j + 1) {
				board_position(board,i*row+j+1,\
						&cur_row,&cur_col);
				fprintf(stderr,"Target : %d\n\n",i*row+j+1);
				ret=-1;
				if(cur_col > j) 
					ret=move(&board,cur_row,cur_col,left);
				else if(cur_col < j )
					ret=move(&board,cur_row,cur_col,right);
				if(ret==-1) {
				if(cur_row > i)
					ret=move(&board,cur_row,cur_col,up);
				else if(cur_row < i)
					ret=move(&board,cur_row,cur_col,down);
				}	
				if(ret == -1) {
					ret=try_swap(&board,cur_row,cur_col);
					if(ret==-1)
						die(3,"Its Impossible!");
					//die(2,"Failed Move!!");
				}
			}
			if(ret == 0)
				positioned[i*row+j+1]=1;
		}
	}
	ctrl++;
	}
}

char str[100];

int move(board_t *board,int row, int col, int dir)
{
	int ret=0,i,j;
	static int visited[10][10];
	
	if( row < 0 || row >= board->row || col < 0 || col >= board->col)
		return -1;
	
	if(visited[row][col])
		return -1;

	if(board->cell[row][col] == 0)
		return 0;
	
	if(positioned[board->cell[row][col]])
		return -1;
	visited[row][col] = 1;
	if(is_stat) status();
	switch(dir) {
		case left:
			/* try moving the left one to the left */
			ret = move(board, row, col-1, left);
			if(ret == -1) 
 				/*try moving the left one down*/
				ret = move(board, row, col-1, down);
			if(ret == -1) 
				/*try moving the left one up*/
				ret = move(board, row, col-1, up);
			if(ret == 0) 
				/* One of the above attempts is sucesful
				 * And the left one is blank now!
				 */
				cell_swap(board,row, col, row, col-1);
			break;
		case right:
			ret = move(board, row, col+1, right);
			if(ret == -1)
				ret = move(board, row, col+1, down);
			if(ret == -1)
				ret = move(board, row, col+1, up);
			if(ret == 0)
				cell_swap(board, row, col, row, col+1);
			break;
		case up:
			ret = move(board, row-1, col, up);
			if(ret == -1)
				ret = move(board, row-1, col, right);
			if(ret == -1)
				ret = move(board, row-1, col, left);
			if(ret == 0)
				cell_swap(board, row, col, row-1, col);
			break;
		case down:
			ret = move(board, row+1, col, down);
			if(ret == -1)
				ret = move(board, row+1, col, right);
			if(ret == -1)
				ret = move(board, row+1, col, left);
			if(ret == 0)
				cell_swap(board, row, col, row+1, col);
			break;
	}	
	visited[row][col] = 0;
	if(ret == -1) {
		fprintf(stderr,"Unable to make the requested move: %d to %s\n",\
				board->cell[row][col], dir2str(dir));
	} else if(ret == 0) {
		//printf("\n");
		print_board(*board);
		//printf("\n");
	}
	return ret;
}

int try_swap(board_t *board, int row, int col)
{
	int fin_row,fin_col;
	int i,count=0;
	void vertical_up(board_t *board,int row, int col);
	void horizontal_left(board_t *board,int row, int col);

	fprintf(stderr,"SWAP ");	
	for(i=0;i<board->row*board->col;i++)
		if(!positioned[i]) count++;
	if(count<4) {
		fprintf(stderr,"FAILED!\n");
		return -1;
	}

	fin_row = board->cell[row][col]/board->row;
	fin_col = board->cell[row][col]%board->row - 1;
	if(fin_col== -1) {
		if(fin_row)
			fin_row--;
		fin_col=board->col-1;
	}
	
	if(col == fin_col) {	
		fprintf(stderr,"VERTICAL.... ");
		if(row == fin_row+1) {
			fprintf(stderr,"UP!\n");
			/*Check*/
			while(1) {
				if(board->cell[row+1][col]==0) {
					vertical_up(board,row,col);
					break;
				} else if(board->cell[row][col-1]==0) {
					move(board,row+1,col-1,up);
					move(board,row+1,col,left);
				} else
					move(board,row+1,col,left);
			}
		}else if(row == fin_row-1) {
			fprintf(stderr,"DOWN!\n");	
			cell_swap(board,row,col,row+1,col);
		}else {
			fprintf(stderr,"Failed!!\n");
			return -1;	
		}
	}
	if(row == fin_row)
	{
		fprintf(stderr,"HORIZONTAL.... ");
		if(col == fin_col+1) {
			fprintf(stderr,"LEFT!\n");
			/*Check*/
			while(1) {
				if(board->cell[row][col+1]==0) {
					horizontal_left(board,row,col);
					break;
				} else if(board->cell[row-1][col]==0) {
					move(board,row-1,col+1,left);
					move(board,row,col+1,up);
				} else 
					move(board,row,col+1,up);
			}
		} else if(col == fin_col-1){
			fprintf(stderr,"RIGHT\n");
			cell_swap(board,row,col,row,col+1);
		} else {
			fprintf(stderr,"Failed\n");
			return -1;
		}
	}
	print_board(*board);	
	return 0;
	/* I never felt the need of using Horizontal-right and
	 * vertical up; if you ever come across, I think using
	 * the same sequence of steps you can solve it.
	 *
	 * Or else mail me at rk_gaddipati@yahoo.com, I will try
	 * to fix it for you :-).
	 */
}

void vertical_up(board_t *board, int row, int col)
{
	/* it assume row+1, col is blank */

	/* move checks for positioned elements....
	 * so releave the one which you should be moving
	 */
	positioned[(row-1)*board->row+col]=0;	
	move(board,row,col,down);
	move(board,row,col-1,right);
	move(board,row+1,col-1,up);
	move(board,row+1,col,left);
	move(board,row,col,down);
	move(board,row-1,col,down);
	move(board,row-1,col-1,right);
	move(board,row,col-1,up);
	move(board,row+1,col-1,up);
	move(board,row+1,col,left);
	move(board,row,col,down);
	move(board,row,col-1,right);
	move(board,row-1,col-1,down);
	move(board,row-1,col,left);
	move(board,row,col,up);
	move(board,row+1,col,up);
	/* Now fix the one which you have moved! */
	positioned[(row-1)*board->row+col]=1;	
}

void horizontal_left(board_t *board, int row, int col)
{
	/* it assume row+1, col is blank */

	/* move checks for positioned elements....
	 * so releave the one which you should be moving
	 */
	positioned[(row-1)*board->row+col]=0;
	move(board,row,col,right);
	move(board,row-1,col,down);
	move(board,row-1,col+1,left);
	move(board,row,col+1,up);
	move(board,row,col,right);
	move(board,row,col-1,right);
	move(board,row-1,col-1,down);
	move(board,row-1,col,left);
	move(board,row-1,col+1,left);
	move(board,row,col+1,up);
	move(board,row,col,right);
	move(board,row-1,col,down);
	move(board,row-1,col-1,right);
	move(board,row,col-1,up);
	move(board,row,col,left);
	move(board,row,col+1,left);
	/* Now fix the one which you have moved! */
	positioned[(row-1)*board->row+col]=1;
}
