/* GNU Chess 5.0 - util.c - utility routine code
   Copyright (c) 1999-2002 Free Software Foundation, Inc.

   GNU Chess is based on the two research programs 
   Cobalt by Chua Kong-Sian and Gazebo by Stuart Cracraft.

   GNU Chess is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   GNU Chess is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with GNU Chess; see the file COPYING.  If not, write to
   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.

   Contact Info: 
     bug-gnu-chess@gnu.org
     cracraft@ai.mit.edu, cracraft@stanfordalumni.org, cracraft@earthlink.net
*/
/*
 * Endianness checks are now unnecessary
 */

#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <stdarg.h>
#include <errno.h>
#include <ctype.h>
#include <time.h>

#include "util.h"
#include "bitboard.h"
#include "option.h"
#include "eval.h"
#include "log.h"
#include "material.h"
#include "piece.h"
#include "protocol.h"
#include "book.h"
#include "ttable.h"
#include "ptable.h"
#include "search.h"
#include "ini.h"
#include "util.h"

#ifdef _WIN32
#include <windows.h>
#endif

char *token[TOKENS];

// [VdB] Some things borrowed from Polyglot (but simplified)

void my_string_set(const char * * variable, const char string[]) {

   ASSERT(variable!=NULL);
   ASSERT(string!=NULL);

   if (*variable != NULL) free((void*)(*variable));
   *variable = strdup(string);
}

int my_string_case_equal(const char string_1[], const char string_2[]) {

   int c1, c2;

   ASSERT(string_1!=NULL);
   ASSERT(string_2!=NULL);

   while (true) {

      c1 = *string_1++;
      c2 = *string_2++;

      if (tolower(c1) != tolower(c2)) return false;
      if (c1 == '\0') return true;
   }

   return true;
}

int my_string_equal(const char string_1[], const char string_2[]) {

   ASSERT(string_1!=NULL);
   ASSERT(string_2!=NULL);

   return strcmp(string_1,string_2) == 0;
}

void my_string_clear(const char * * variable) {

   ASSERT(variable!=NULL);

   if (*variable != NULL) {
      free((void*)(*variable));
      *variable = NULL;
   }
}

void my_string_append(char **dst, const char *src){
  char *s;
  if(*dst){
    s=malloc(strlen(*dst)+strlen(src)+1);
    sprintf(s,"%s",*dst);
    strcat(s,src);
    free((void *)(*dst));
    *dst=s;
  }else{
      my_string_set((const char **)dst,src);
  }
}


void my_path_join(char *join_path, const char *path, const char *file){
    char separator;
#ifdef _WIN32
    separator='\\';
#else
    separator='/';
#endif
    snprintf(join_path,MAXSTR,"%s%c%s",path,separator,file);
    join_path[MAXSTR-1]='\0';
}

void my_sleep(int msec){
#ifndef _WIN32
  struct timespec tm;
  tm.tv_sec=msec/1000;
  tm.tv_nsec=1000000*(msec%1000);
  nanosleep(&tm,NULL);
#else
  Sleep(msec);
#endif
}

// I can't get this to work right on mingw...
void my_machine(char *hostname){
#ifndef _WIN32
    gethostname(hostname,MAXSTR);
#else 
    //    GetComputerName(hostname,MAXSTR);
    strcpy(hostname,"localhost");
#endif 
}


void Output(char  *fmt, ...){
  va_list ap;
  char buf[MAXSTR];
  va_start(ap, fmt);
  vsnprintf(buf, MAXSTR-1, fmt, ap);
  va_end(ap);
  printf("%s",buf);
  fflush(stdout);
  LogSetNewlinePrefix(LogDefault,"OUT: ");
  Log("%s",buf);
  LogSetNewlinePrefix(LogDefault,DEFAULT_NEWLINE_PREFIX);
}

void OutputConsole(char  *fmt, ...){
  va_list ap;
  char buf[MAXSTR];
  va_start(ap, fmt);
  vsnprintf(buf, MAXSTR-1, fmt, ap);
  va_end(ap);
  if(Protocol->console){
    printf("%s",buf);
    fflush(stdout);
  }
  LogSetNewlinePrefix(LogDefault,"CONSOLE: ");
  Log("%s",buf);
  LogSetNewlinePrefix(LogDefault,DEFAULT_NEWLINE_PREFIX);
}

void split_input(char *inputstr){
    /* r points to the last non-space character */
    char *s, *r;
    int k;

    for (k = 0, s = r = inputstr; k < TOKENS; ++k) {
	/* Skip leading whitespace */
	while (isspace(*s)) s++;
	token[k] = s;
	/* Skip token */
	while (*s && !isspace(*s)) r = s++;
    }
    while (*s) {
	while (isspace(*s)) s++;
	while (*s && !isspace(*s)) r = s++;
    }
    r[1] = '\0';
}

/*
 * Compares two tokens, returns 1 on equality. Tokens
 * are separated by whitespace.
 */
int tokeneq(const char *s, const char *t){
    while (*s && *t && !isspace(*s) && !isspace(*t)) {
	if (*s++ != *t++) return 0;
    }
    return (!*s || isspace(*s)) && (!*t || isspace(*t));
}
  



void gnuchess_set_option(const char *name, const char *value){ 
    if(value){
	Log("Setting %s to %s\n",name,value);
	OptionSet(Option,name,value);
    }else{
	Log("Pushing button %s\n",name);
    }
    if(my_string_case_equal(name,"BookFile")){
	BookSetFile(Book,OptionGetString(Option,"BookFile"));
    }else if(my_string_case_equal(name,"Log")){
	LogSetState(LogDefault,OptionGetBool(Option,"Log"));
    }else if(my_string_case_equal(name,"LogFile")){
	LogSetFile(LogDefault,OptionGetString(Option,"LogFile"));
    }else if(my_string_case_equal(name,"DumpTree")){
	LogSetState(LogDump,OptionGetBool(Option,"DumpTree"));
    }else if(my_string_case_equal(name,"DumpFile")){
	LogSetFile(LogDump,OptionGetString(Option,"DumpFile"));
    }else if(my_string_case_equal(name,"ClearHash")){
	Log("Clearing transposition table\n");
	TTableZero(TTable);
	PTableZero(PTable);
    }else if(my_string_case_equal(name,"Hash")){
	TTableSetSizeMb(TTable,atoi(value));
    }else if(my_string_case_equal(name,"Save")){
	ini_t ini[1];
	const char *config=OptionGetString(Option,"SaveSettingsFile");
	IniInit(ini);
	IniFromOption(ini,Option);
	OutputConsole("Dumped config file to %s...\n",config);
	IniSave(ini,config);
	
    }
    SearchInit(Option);

}



