#include "maze.h"

#include <allegro.h>
#include <iostream.h>
#include <time.h>
#include <stdlib.h>

#define maxx 800
#define maxy 600

#define linux
//#define DOS

#ifdef linux
#define GFX_DRIVER GFX_XWINDOWS
#endif

#ifdef DOS
#define GFX_DRIVER GFX_AUTODETECT
#endif

#define empty 2       //redefinition
#define path -1       //solution path
#define visited -2    //already visited

void draw_maze_solve(BITMAP* dest, char* maze, int n, coord pos);

coord find_next_move(char* maze, int n, coord pos);
coord find_next_backspace(char* maze, int n, coord pos);


int main(int argc, char** argv)
{
  if(argc!=3)
  {
    cout<<"Argument error..."<<endl
        <<"mazsolve.exe [size] [delay]"<<endl;
    return -1;
  }


  int n = atoi(argv[1]);
  int delay = atoi(argv[2]);
  int count(0);

  maze_t maze(n);

  maze.generate();
  
  allegro_init();

  install_keyboard();

  install_timer(); //rest()

  set_color_depth(32);
  if(set_gfx_mode(GFX_DRIVER,maxx,maxy,0,0)<0)
  {
    cout<<"Graphics error: "<<allegro_error<<endl;
    return -2;
  }


  BITMAP* buffer;

  buffer=create_bitmap(maxx,maxy);
  clear(buffer);

  draw_maze_solve(buffer,maze.maze,maze.n,maze.beg);

  blit(buffer,screen,0,0,0,0,maxx,maxy);


  // ALGORYTHM STARTS HERE:

  coord pos,t;

  pos=maze.beg;

  while(pos!=maze.end && !key[KEY_ESC])
  {
    maze[pos]=path;

    t=find_next_move(maze.maze,maze.n,pos);

    if(!int(t))
    {
      t=find_next_backspace(maze.maze,maze.n,pos);
      maze[pos]=visited;
    }

    pos=t;

    if(delay<0)
    {
      if(count>=(-delay))
      {
        draw_maze_solve(buffer,maze.maze,maze.n,pos);
        blit(buffer,screen,0,0,0,0,maxx,maxy);
        count=0;
      }

      count++;
    }

    if(delay>0)
	{
		rest(delay);
		draw_maze_solve(buffer,maze.maze,maze.n,pos);
        blit(buffer,screen,0,0,0,0,maxx,maxy);
	}

  }

  // ALGORYTHM ENDS HERE.


  draw_maze_solve(buffer,maze.maze,maze.n,pos);
  blit(buffer,screen,0,0,0,0,maxx,maxy);
  textout(screen,font,"SOLVED!!!",maxx/2,maxy/2,makecol32(255,255,255));

  
  #ifdef dos
  #define KEY_ESC 1
  #endif
  
  while(!key[KEY_ESC]);

  destroy_bitmap(buffer);
  allegro_exit();

  return 0;
}

#ifdef linux
END_OF_MAIN();
#endif

#define wall_c makecol32(125,125,125)
#define wall_c2 makecol32(0,0,0)
#define floor_c makecol32(255,255,150)
#define empty_c makecol32(255,255,255)
#define pos_c makecol32(255,50,25)
#define path_c makecol32(255,100,75)
#define visited_c makecol32(50,200,255)


void draw_maze_solve(BITMAP* dest, char* maze, int n, coord pos)
{
  int w = dest->w,//gets size of mem. bufer
      h = dest->h;

  coord b;//begining and length coords on mem. buffer

  b.x=w/8;//this is where our maze will begin
  b.y=h/8;
  float l_x=((3*w)/4)/n;//this is the length(size) of each cell
  float l_y=((3*h)/4)/n;

  int i,j,x;//some temp variables

  for(i=0; i<n; i++)
    for(j=0; j<n; j++)
    {
      x=maze[i*n+j];
      switch(x)
      {
        case wall://if current cell is a wall
          rectfill(dest,b.x+i*l_x,b.y+j*l_y,b.x+(i+1)*l_x,b.y+(j+1)*l_y,wall_c);
          rect(dest,1+b.x+i*l_x,1+b.y+j*l_y,b.x+(i+1)*l_x-1,b.y+(j+1)*l_y-1,wall_c2);
          break;
        case floor: //if it is a floor
          rectfill(dest,b.x+i*l_x,b.y+j*l_y,b.x+(i+1)*l_x,b.y+(j+1)*l_y,floor_c);
          break;
        case path:
          rectfill(dest,b.x+i*l_x,b.y+j*l_y,b.x+(i+1)*l_x,b.y+(j+1)*l_y,path_c);
          break;
        case visited:
          rectfill(dest,b.x+i*l_x,b.y+j*l_y,b.x+(i+1)*l_x,b.y+(j+1)*l_y,visited_c);
          break;
        default:
        case empty://if it is empty  (used for debug pourposes, but shouldn't usually occur)
          rectfill(dest,b.x+i*l_x,b.y+j*l_y,b.x+(i+1)*l_x,b.y+(j+1)*l_y,empty_c);
      }
    }

    if(pos!=coord()) rectfill(dest,b.x+pos.x*l_x+2,b.y+pos.y*l_y+2,b.x+(pos.x+1)*l_x-2,b.y+(pos.y+1)*l_y-2,pos_c);
}


coord find_next_move(char* maze, int n, coord pos)
{
  coord m[4];
  int c(0);

  if(maze[(pos.ret(-1,0)).m_pos(n)]==floor)
  {
    m[c]=pos.ret(-1,0);
    c++;
  }

  if(maze[(pos.ret(1,0)).m_pos(n)]==floor)
  {
    m[c]=pos.ret(1,0);
    c++;
  }

  if(maze[(pos.ret(0,-1)).m_pos(n)]==floor)
  {
    m[c]=pos.ret(0,-1);
    c++;
  }

  if(maze[(pos.ret(0,1)).m_pos(n)]==floor)
  {
    m[c]=pos.ret(0,1);
    c++;
  }

  if(c==0) return coord();

  return m[number_range(0,c-1)];
}



coord find_next_backspace(char* maze, int n, coord pos)
{
  coord m[4];
  int c(0);

  if(maze[(pos.ret(-1,0)).m_pos(n)]==path)
  {
    m[c]=pos.ret(-1,0);
    c++;
  }

  if(maze[(pos.ret(1,0)).m_pos(n)]==path)
  {
    m[c]=pos.ret(1,0);
    c++;
  }

  if(maze[(pos.ret(0,-1)).m_pos(n)]==path)
  {
    m[c]=pos.ret(0,-1);
    c++;
  }

  if(maze[(pos.ret(0,1)).m_pos(n)]==path)
  {
    m[c]=pos.ret(0,1);
    c++;
  }

  if(c==0) return coord();

  return m[number_range(0,c-1)];

}
