#include "util.h"
#include <string.h>
#include <ctype.h>

static int indentlevel;

void indent(){++indentlevel;};
void tab(){
  for(int i=0;i<indentlevel;++i) printf(" ");
}

void unindent(){
  indentlevel--;
  if(!indentlevel)indentlevel=0;
}
  

bool util::signedIntValue(char*s,int*val){
  if (s==NULL||s[0]==0) return false;
  bool negate=false;
  char*next=s;
  if (next[0]=='-'){
    next++;
    negate=true;
  }
  if(!positiveIntValue(next,val))
    return false;
  if(negate) *val= -*val;
  return true;
}
    
  
bool util::positiveIntValue(char * s,int*val){
  if(!s||!*s)return false;
  int sum=0;
  char c;
  while((c=*s++)!=0){
    if (c>='0'&&c<='9'){
      sum*=10;
      sum+= c - '0';
    }
    else return false;
  }
  *val=sum;
  return true;
}


string util::game_to_string(Game*game){
  TextBuffer* tbuffer=new TextBuffer;
  tbuffer->SetBufferSize(105000);
  game->WriteToPGN_CQL(tbuffer);
  char * buf=tbuffer->GetBuffer();
  uassert(buf,"game_to_string internal");
  string ret(buf); //Not absolutely certain is 0 terminated, hopefully it is
  uassert(strlen(buf)==ret.size(),"game_to_string size");
  tbuffer->Free();
  return ret;
}

void util::printgame(FILE* stream,Game* game){
  TextBuffer * tbuffer=new TextBuffer;
  tbuffer->SetBufferSize(100000);
  game->WriteToPGN_CQL(tbuffer);
  tbuffer->DumpToFile(stream);
  tbuffer->Free();
}


void util::my_dump_board(boardT board){
  FILE * fp=stdout;
  squareT s;
  printf("Side To move is: %c\n",board[COLOR_SQUARE]);
  for (int i=7; i>=0; i--) {
    fputs ("   ", fp);
    for (int j=0; j<8; j++) {
      s = (i*8) + j;
      char c=PIECE_CHAR[board[s]];
      if (c=='.'){
	if (i%2==j%2)
	  putc('+',fp);
	else
	  putc('-',fp);
      }
      else 
	putc (c, fp);
      putc (' ', fp);
    }
    putc ('\n', fp);
  }
}

int util::squareShiftDirection(int sq, directionT direction){
  uassert(sq>=0&&sq<64&&direction<=DOWN_RIGHT);
  int s=square_Move(sq,direction);
  if (s>=64) s=-1;
  return s;
}

bool util::directionCompatible(pieceT piece, directionT direction){
  pieceT newp=piece_Type(piece);
  if (newp==ROOK||newp==QUEEN) return directionOrthogonal(direction);
  else if (newp==BISHOP||newp==QUEEN) return directionDiagonal(direction);
  else return false;
}
bool util::directionOrthogonal(directionT direction){
  return direction==UP||direction==DOWN||direction==LEFT||direction==RIGHT;
}

bool util::directionDiagonal(directionT direction){
  return direction==UP_LEFT||direction==DOWN_LEFT||direction==UP_RIGHT||direction==DOWN_RIGHT;
}

void util::printgame(Game*g){
  if(!g){printf("NULL GAME\n");}
  my_dump_board(g->GetCurrentPos()->GetBoard());
}
    
const char * util::string_append (const char* a, const char*b){
  uassert(a&&b,"string_append args");
  char buffer[500];
  uassert(strlen(a)+strlen(b)<sizeof(buffer)-5,"too long string append");
  sprintf(buffer,"%s%s",a,b);
  return util::copy(buffer);
}

char * util::copy(const char * buffer){
  int len=strlen(buffer);
  if (len>100000){
    fprintf(stderr,"Unfortunately, CQL cannot handle so many comments: game output of %d bytes\n",len);
    fprintf(stderr,"Try modifying the .cql file to print fewer comments, for instance by using the 'silent' keyword.\n");
    fprintf(stderr,"Typically these comments are automatically generated by next or previous.\n");
    fprintf(stderr,"Try putting the keyword 'silent' in front of these keywords\n");
    fprintf(stderr,"or see the documentation for 'silent' for more options\n\n");
    fprintf(stderr,"Also consider the 'nestban' keyword if inside of a 'next' filter");
    fprintf(stderr,"Unable to handle so many comments, exiting\n");
    uassert(false);
  }
  char * nb=(char *) new char[len+1];
  for (int i=0;i<len;++i){
    nb[i]=buffer[i];
    nb[len]=0;
  }
  return nb;
}
