#include <move_generator.h>
#include <chess_capture_move.h>
#include <antichess_board.h>

class antichess_move_gen : public move_generator {
public:

    antichess_move_gen(const array <chess_capture_move> *m);
    // Effects: constructs a generator that returns all the valid
    // moves at the current time.

    bool get(move *&m);
    // Modifies: this
    // Effects:  If more moves remain, returns true and sets m to be a pointer
    //  to the next move, else returns false.

private:
    int index;
    int length;
    const array <chess_capture_move> *a;
};

antichess_move_gen::antichess_move_gen (const array <chess_capture_move> *m) {
  index = 0;
  a = m;
  length = m->length();
}

bool antichess_move_gen::get (move *&m) {
  if (index >= length)
    return false;
  
  m = &a->operator[](index++);
  return true;
}

void add_to_array(chess_capture_move mv,array<chess_capture_move> *forces,
		  array<chess_capture_move> *normal){
    
    if (mv.get_piece_taken() != chess_display_board::none)
	forces->append(mv);
    else
	normal->append(mv);
}


move_generator* antichess_board::valid_moves(int p) const{
    int x1, y1,x,y;
    bool is_queen = false;
    int dir;
    antichess_board *b = (antichess_board *) this;
    bool top_right_loop = true;
    bool top_left_loop = true;
    bool bottom_right_loop = true;
    bool bottom_left_loop = true;
    int pieces_to_find;
    array<chess_capture_move> *possible_moves_p=new array <chess_capture_move>;
    array <chess_capture_move> &possible_moves = *possible_moves_p;
    array<chess_capture_move> *forced_moves_p = new array <chess_capture_move>;
    array <chess_capture_move> &forced_moves = *forced_moves_p;

    if (p != current_player())
	return new antichess_move_gen(possible_moves_p);
    
    pieces_to_find = pieces_remaining(p);
        
    color capture_color, this_color;
    if (p==0){
	capture_color = black;
	this_color = white;
	dir = 1;
    }
    else if (p==1){
	capture_color = white;
	this_color = black;
	dir = -1;
    }
    else
	check(p==1,"Invalid player");
    
    for(y1=0;y1<8;y1++)
	for(x1=0;x1<8;x1++){
	    
	    if (pieces_to_find<=0)
		break;
	    
	    if (b->fetch(y1,x1).piece_color != this_color)
		continue;
	    
	    is_queen = false;
	    
	    pieces_to_find--;
	    
	    switch(b->fetch(y1,x1).piece_type){
	    case invalid:  break;  //this should never happen
	    case none:     break;
	    case pawn:
		// Check for 1 forward, not capture
		if ((y1+dir < 8) && (y1 +dir >=0) &&
		    (b->fetch(y1+dir,x1).piece_type == none)){
		    chess_capture_move temp(x1,y1,x1,y1+dir,b);
		    add_to_array(temp, forced_moves_p, possible_moves_p);
		}
		
		// Check for moving 2 forward
		// There was already a check that x2,y2 was legal place to be
		if (((y1==1) && (this_color==white)) ||
		    ((y1==6) && (this_color==black)))
		    if ((y1+2*dir < 8) && (y1 +2*dir >=0) &&
			(b->fetch(y1+2*dir,x1).piece_type == none) &&
			(b->fetch(y1+dir,x1).piece_type == none)){
			chess_capture_move temp(x1,y1,x1,y1+2*dir,b);
			add_to_array(temp, forced_moves_p, possible_moves_p);
		    }
		
		// Check for captures
		if ((y1+dir < 8) && (y1+dir>=0) && (x1+1 < 8) &&
		    (b->fetch(y1+dir,x1+1).piece_color == capture_color)){
		    chess_capture_move temp(x1,y1,x1+1,y1+dir,b);
		    add_to_array(temp, forced_moves_p, possible_moves_p);
		}
		if ((y1+dir < 8) && (y1+dir>=0) && (x1-1 >= 0) &&
		    (b->fetch(y1+dir,x1-1).piece_color == capture_color)){
		    chess_capture_move temp(x1,y1,x1-1,y1+dir,b);
		    add_to_array(temp, forced_moves_p, possible_moves_p);
		}
		break;
		
	    case knight:
		if ((y1+2 < 8) && (x1+1 < 8) &&
		    (b->fetch(y1+2,x1+1).piece_color != this_color)){
		    chess_capture_move temp(x1,y1,x1+1,y1+2,b);
		    add_to_array(temp, forced_moves_p, possible_moves_p);
		}
		if ((y1+2 < 8) && (x1-1 >= 0) &&
		    (b->fetch(y1+2,x1-1).piece_color != this_color)){
		    chess_capture_move temp(x1,y1,x1-1,y1+2,b);
		    add_to_array(temp, forced_moves_p, possible_moves_p);
		}
		if ((y1-2 >=0) && (x1+1 <8) &&
		    (b->fetch(y1-2,x1+1).piece_color != this_color)){
		    chess_capture_move temp(x1,y1,x1+1,y1-2,b);
		    add_to_array(temp, forced_moves_p, possible_moves_p);
		}
		if ((y1-2 >= 0) && (x1-1 >= 0) &&
		    (b->fetch(y1-2,x1-1).piece_color != this_color)){
		    chess_capture_move temp(x1,y1,x1-1,y1-2,b);
		    add_to_array(temp, forced_moves_p, possible_moves_p);
		}
		if ((y1+1 < 8) && (x1+2 <8) &&
		    (b->fetch(y1+1,x1+2).piece_color != this_color)){
		    chess_capture_move temp(x1,y1,x1+2,y1+1,b);
		    add_to_array(temp, forced_moves_p, possible_moves_p);
		}
		if ((y1-1 >= 0) && (x1+2 <8) &&
		    (b->fetch(y1-1,x1+2).piece_color != this_color)){
		    chess_capture_move temp(x1,y1,x1+2,y1-1,b);
		    add_to_array(temp, forced_moves_p, possible_moves_p);
		}
		if ((y1+1 < 8) && (x1-2 >= 0) &&
		    (b->fetch(y1+1,x1-2).piece_color != this_color)){
		    chess_capture_move temp(x1,y1,x1-2,y1+1,b);
		    add_to_array(temp, forced_moves_p, possible_moves_p);
		}
		if ((y1-1 >= 0) && (x1-2 >= 0) &&
		    (b->fetch(y1-1,x1-2).piece_color != this_color)){
		    chess_capture_move temp(x1,y1,x1-2,y1-1,b);
		    add_to_array(temp, forced_moves_p, possible_moves_p);
		}
		break;
		
	    case queen:
		is_queen =true;
		// then fall through: queen = rook+bishop		
	    case rook:
		for(x=x1+1;x<8;x++){
		    if (b->fetch(y1,x).piece_type == none){
			chess_capture_move temp(x1,y1,x,y1,b);
			add_to_array(temp, forced_moves_p, possible_moves_p);
		    }
		    else {
			if (b->fetch(y1,x).piece_color == capture_color){
			    chess_capture_move temp(x1,y1,x,y1,b);
			    add_to_array(temp,forced_moves_p,possible_moves_p);
			}
			break;
		    }
		}

		for(x=x1-1;x>=0;x--){
		    if (b->fetch(y1,x).piece_type == none){
			chess_capture_move temp(x1,y1,x,y1,b);
			add_to_array(temp, forced_moves_p, possible_moves_p);
		    }
		    else {
			if (b->fetch(y1,x).piece_color == capture_color){
			    chess_capture_move temp(x1,y1,x,y1,b);
			    add_to_array(temp,forced_moves_p,possible_moves_p);
			}
			break;
		    }
		}

		for(y=y1+1;y<8;y++){
		    if (b->fetch(y,x1).piece_type == none){
			chess_capture_move temp(x1,y1,x1,y,b);
			add_to_array(temp, forced_moves_p, possible_moves_p);
		    }
		    else {
			if (b->fetch(y,x1).piece_color == capture_color){
			    chess_capture_move temp(x1,y1,x1,y,b);
			    add_to_array(temp,forced_moves_p,possible_moves_p);
			}
			break;
		    }
		}

		for(y=y1-1;y>=0;y--){
		    if (b->fetch(y,x1).piece_type == none){
			chess_capture_move temp(x1,y1,x1,y,b);
			add_to_array(temp, forced_moves_p, possible_moves_p);
		    }
		    else {
			if (b->fetch(y,x1).piece_color == capture_color){
			    chess_capture_move temp(x1,y1,x1,y,b);
			    add_to_array(temp,forced_moves_p,possible_moves_p);
			}
			break;
		    }
		}
		
		if (!is_queen)
		    break;
		
	    case bishop:
		
		for(x=1;x<8;x++){
		    
		    if (top_right_loop && (x1+x<8) && (y1+x<8)) {
			if (b->fetch(y1+x,x1+x).piece_type == none){
			    chess_capture_move temp(x1,y1,x1+x,y1+x,b);
			    add_to_array(temp,forced_moves_p,possible_moves_p);
			}
			else if (b->fetch(y1+x,x1+x).piece_color == 
				capture_color) {
			    top_right_loop = false;
			    chess_capture_move temp(x1,y1,x1+x,y1+x,b);
			    add_to_array(temp,forced_moves_p,possible_moves_p);
			}
			else
			    top_right_loop = false;
		    }			
	
		    if (bottom_right_loop && (x1+x<8) && (y1-x>=0)){
			if (b->fetch(y1-x,x1+x).piece_type == none){
			    chess_capture_move temp(x1,y1,x1+x,y1-x,b);
			    add_to_array(temp,forced_moves_p,possible_moves_p);
			}
			else if (b->fetch(y1-x,x1+x).piece_color == 
				 capture_color){
			    bottom_right_loop = false;
			    chess_capture_move temp(x1,y1,x1+x,y1-x,b);
			    add_to_array(temp,forced_moves_p,possible_moves_p);
			}
			else
			    bottom_right_loop = false;
		    }
		    
		    if (top_left_loop && (x1-x>=0) && (y1+x<8)){
			if (b->fetch(y1+x,x1-x).piece_type == none){
			    chess_capture_move temp(x1,y1,x1-x,y1+x,b);
			    add_to_array(temp,forced_moves_p,possible_moves_p);
			}
			else if (b->fetch(y1+x,x1-x).piece_color == 
				 capture_color){
			    top_left_loop = false;
			    chess_capture_move temp(x1,y1,x1-x,y1+x,b);
			    add_to_array(temp,forced_moves_p,possible_moves_p);
			}
			else
			    top_left_loop = false;
		    }

		    if (bottom_left_loop && (x1-x>=0) && (y1-x>=0)){
			if (b->fetch(y1-x,x1-x).piece_type == none){
			    chess_capture_move temp(x1,y1,x1-x,y1-x,b);
			    add_to_array(temp,forced_moves_p,possible_moves_p);
			}
			else if (b->fetch(y1-x,x1-x).piece_color == 
				 capture_color) {
			    bottom_left_loop = false;
			    chess_capture_move temp(x1,y1,x1-x,y1-x,b);
			    add_to_array(temp,forced_moves_p,possible_moves_p);
			}
			else
			    bottom_left_loop = false;
		    }		    

		}
		break;
		
	    case king:
		for(y=y1-1;y<=y1+1;y++)
		    for(x=x1-1;x<=x1+1;x++){
			if (((x==x1) && (y==y1)) ||
			    (y < 0) ||
			    (y > 7) ||
			    (x < 0) ||
			    (x > 7))
			    continue;
			if (b->fetch(y,x).piece_color != this_color){
			    chess_capture_move temp(x1,y1,x,y,b);
			    add_to_array(temp,forced_moves_p,possible_moves_p);
			}
		    }
		break;
	    }
	}

    if (forced_moves.length() != 0)
	return new antichess_move_gen(forced_moves_p);
    else
	return new antichess_move_gen(possible_moves_p);
}


