#include "board.h"
#include <stdio.h>
#include <string.h>

// describe value -> buffer (32-byte buffer should do)
void describeValue( i32 val, char *buf, i32 type )
{
    if ( type == 0 )
    {
        if ( val >= -mate + 1000 && val <= mate - 1000 )
            sprintf(buf, "%d (%+0.2lf)", val, (double)val / 1000.0);
        else
        {
            sprintf(buf, "%cmate in %d [%d ply]", val < 0 ? '-' : '+', (mate - (val < 0 ? -val : +val)+1)/2,
                    mate - (val < 0 ? -val : +val) );
        }
    }
    else if ( type == 1 )
    {
        if ( val >= -mate + 1000 && val <= mate - 1000 )
            sprintf(buf, "%+0.2lf", (double)val / 1000.0);
        else
        {
            sprintf(buf, "%cmate in %d", val < 0 ? '-' : '+', (mate - (val < 0 ? -val : +val)+1)/2
                   );
        }
    }
    else
    {
        if ( val >= -mate + 1000 && val <= mate - 1000 )
            sprintf(buf, "%+0.2lf", (double)val / 1000.0);
        else
        {
            sprintf(buf, "%cM%d", val < 0 ? '-' : '+', (mate - (val < 0 ? -val : +val)+1)/2 );
        }
    }
}

static const char * const letters = "abcdefgh";
static const char * const numbers = "87654321";

// describe in uci-compatible format
void Move::describeUCI( char *buf ) const
{
    sprintf( buf, "%c%c%c%c", letters[ from & 7 ], numbers[ from >> 3 ], letters[ to & 7 ], numbers[ to >> 3 ] );
    if ( promo )
    {
        const char * const promosuff = "\0\0nbrq\0\0\0";
        buf[4] = promosuff[ promo ];
        buf[5] = 0;
    }
}

// describe in uci-compatible format
void Move::describeICS( char *buf ) const
{
    sprintf( buf, "%c%c%c%c", letters[ from & 7 ], numbers[ from >> 3 ], letters[ to & 7 ], numbers[ to >> 3 ] );
    if ( promo )
    {
        const char *promosuff = "\0\0NBRQ\0\0\0";
        buf[4] = '=';
        buf[5] = promosuff[ promo ];
        buf[6] = 0;
    }
}

// describe move -> buffer (32-byte buffer should do)
void Move::describe( const Board &b, char *buf ) const
{
    i32 fx = from & 7;
    i32 fy = from >> 3;
    i32 tx = to & 7;
    i32 ty = to >> 3;
    if ( castling /*b.piece[ fy ][ fx ].type == king && !b.piece[ fy ][ fx ].moved*/ )
    {
        // check for castling!
        i32 dx = tx - fx;
        if ( dx < 0 )
            dx = -dx;
        if ( dx > 1 )
        {
            sprintf( buf, "%s", tx < 4 ? "OOO" : "OO" );
            return;
        }
    }
    if ( b.piece[ ty ][ tx ].type != none )
    {
        // capture
        sprintf( buf, "%c%cx%c%c", letters[ fx ], numbers[ fy ], letters[ tx ], numbers[ ty ] );
    }
    else
    {
        sprintf( buf, "%c%c%c%c", letters[ fx ], numbers[ fy ], letters[ tx ], numbers[ ty ] );
    }
}

// returns true if two moves are equal (wrt start/end position)
bool Move::equal( const Move &m ) const
{
    bool res = (m.from == from && m.to == to);
    if ( !res )
        return false;
    if ( m.promo == promo )
        return true;
    // now it seems that we have to resolve a promotion!
    if ( (!m.promo && promo) || (!promo && m.promo) )
    {
        return m.promo == queen || promo == queen;
    }
    return false;
}

// returns true if two moves are equal (wrt PV)
bool Move::equalPV( const Move &m ) const
{
    if ( !equal(m) )
        return false;
    return m.capture == capture && m.cappiece == cappiece && m.castling == castling && m.enpassant == enpassant// &&
           /*m.lastcap == lastcap*/;
}

bool Move::equalUCI( const Move &m ) const
{
    if ( !equal(m) )
        return false;
    return m.promo == promo;
}

// describe move using SAN (short algebraic notation)
// checks: use '+' and '#' suffices for check/checkmate
void Move::describeSAN( i32 turn, const Board &b, char *buf, bool checks ) const
{
    Move m = *this;

    if ( m.castling )
    {
        if ( m.castling == 2 )
        {
            strcpy( buf, "O-O-O");
        }
        else
        {
            strcpy( buf, "O-O");
        }
        return;
    }

    Move mv[ maxMoves ];
    i32 nm = b.moves( mv, turn );
    const Piece &p = b.pieces[ m.from ];
    const char *prefix = "  NBRQK ";
    char pr = prefix[ p.type ];
    char *ch = buf;
    if ( pr != 32 )
        *ch++ = pr;
    i32 i;
    i32 startx = 0, starty = 0;
    for (i=0; i<nm; i++)
    {
        if ( m.equal( mv[i] ) )
        {
            if ( m.promo != mv[i].promo )
                continue;
            m = mv[i];
            continue;
        }
        if ( b.pieces[ mv[i].from ].type != p.type )
            continue;
        if ( mv[i].to != m.to )
            continue;
        if ( (mv[i].from & 7) != (m.from & 7) )
            startx++;
        else if ( (mv[i].from >> 3) != (m.from >> 3) )		// TODO/FIXME: is this else ok?!
            starty++;
    }
    if ( !startx && !starty && pr == 32 && m.capture )
        startx = 1;			// because of pawns
    if ( startx )
    {
        *ch++ = 'a' + (m.from & 7);
    }
    if ( starty )
        *ch++ = '8' - (m.from >> 3);
    if ( m.capture )
        *ch++ = 'x';
    *ch++ = 'a' + (m.to & 7);
    *ch++ = '8' - (m.to >> 3);

    if ( p.type == pawn && m.promo )
    {
        *ch++ = '=';
        *ch++ = prefix[ m.promo ];
    }

    if ( checks )
    {
        Board tb( b );
        tb.move( m );
////		tb.update( turn ^ 1 );
        u8 kp = tb.kingPosition( turn ^ 1 );
        if ( tb.check( kp ) )
        {
////			bool tmp = tb.check( kp.x, kp.y );
            nm = tb.moves( mv, turn ^ 1 );
            *ch++ = nm ? '+' : '#';
        }
    }

    *ch = 0;
}

void Move::parse( const char *&lan )
{
    packed = 0;
    i32 s = 0;			// state (0 = from, 1 =to)
    while ( lan && *lan && s < 2 )
    {
        i32 c = *lan;
        if ( c >= 'A' && c <= 'H' )
            c |= 32;
        if ( c >= 'a' && c <= 'h' )
        {
            if ( !s )
            {
                from &= ~7;
                from |= c - 'a';
            }
            else
            {
                to &= ~7;
                to |= c - 'a';
            }
        }
        if ( c >= '1' && c <= '8' )
        {
            if ( !s )
            {
                from &= 7;
                from |= (7 - (c - '1')) << 3;
                s = 1;
            }
            else
            {
                to &= 7;
                to |= (7 - (c - '1')) << 3;
                s = 2;
            }
        }
        lan++;
    }
}

// move eval bonus (because of castling!)
i32 Move::eval( i32 turn, const Board *b ) const
{
    if ( !castling )
    {
        /*		if ( capture && cappiece == queen )
        		{
        			return 100;			// bonus for getting rid of queens
        		}*/
        if ( capture && b )
        {
            const Piece &p = b->pieces[ from ];
            i8 what = p.type;
            if ( what == cappiece )
            {
                i8 c = p.color;
                i32 val = 50 + 5*(what - cappiece);
                if ( b->dmat == 0 )
                {
                    // good capture		//exchange
                    return val;
                }
                else if ( c == white )
                {
                    // c == white
                    return b->dmat > 0 ? 2*val : -2*val;
                }
                else
                {
                    // assume c == black
                    return b->dmat < 0 ? 2*val : -2*val;
                }
            }
        }
        return 0;
    }
    return 300;
}

// returns true if valid move
bool Move::valid() const
{
    return from != to;
}

// returns true if 'null move'
bool Move::isNull() const
{
    return from == to;
}
