/* GNU Chess 5.0 - input.c - Input thread and related
   Copyright (c) 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
     lukas@debian.org
*/

/*
 * This used to use readline but this does not work well with gnuchess
 * looking for input while searching. 
 * Since these days console mode is only used for debugging readline is
 * no longer a priority.
 * Eliminated readline. If you want readline use "rlwrap".
 *
 * We also suppressed prompts as with the current setup they spring up at 
 * unpredictable places.
 *
 *
 */

#include <windows.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <ctype.h>

#include "util.h"
#include "log.h"
#include "input.h"
#include "protocol.h"

/*
 * Status variable used by the input thread to signal
 * pending input. Thought about using flags for this
 * but this can be refined and is conceptually different
 * from flags.
 */
enum {
  INPUT_NONE,
  INPUT_AVAILABLE
};


static volatile int input_status = INPUT_NONE;
  
/*
 * Function to wake up the input thread, should be called after
 * input has been parsed.
 */
static void input_wakeup(void);


static char inputstr[MAXSTR];


/* The generic input routine */

static void getline_(){
  if(!fgets(inputstr,sizeof(inputstr), stdin)){
      /* Hack: pretend user has typed "quit" on EOF */
    strncpy(inputstr,"quit",sizeof(inputstr));
    inputstr[sizeof(inputstr)-1]='\0';
  }
}

HANDLE input_thread;

/* Mutex and condition variable for thread communication */

CRITICAL_SECTION input_mutex;
HANDLE input_cond;
//CRITICAL_SECTION wakeup_mutex;
HANDLE wakeup_cond;

static DWORD WINAPI input_func(LPVOID lpParametr){
    while (!(Protocol->state_flags & QUIT)) {
	EnterCriticalSection(&input_mutex);
	getline_();
	input_status = INPUT_AVAILABLE;
	/*
	 * Hack to make sure we don't get stuck at the above getline_()!
	 */
	split_input(inputstr);

	if(tokeneq(token[0],"quit")){
	    SET(Protocol->state_flags,QUIT);
	}

	SetEvent(input_cond);
	LeaveCriticalSection(&input_mutex);

	if(Protocol->state_flags&QUIT){
	    break;
	}	


	WaitForSingleObject(wakeup_cond,INFINITE);

    }
    return 0;
}

static void input_wakeup(void){
    EnterCriticalSection(&input_mutex);
    input_status = INPUT_NONE;
    // XXX Next thing shouldn't be there
    ResetEvent(input_cond);
    // YYY
    SetEvent(wakeup_cond);
    LeaveCriticalSection(&input_mutex);
}

void InputWakeup(){
    // XXX It would be best to put this in the critical section.
    LogSetNewlinePrefix(LogDefault, "KILL: ");
    Log("%s\n",inputstr);
    LogSetNewlinePrefix(LogDefault,DEFAULT_NEWLINE_PREFIX);
    input_wakeup();
}

char *InputLook(){
    if(input_status==INPUT_AVAILABLE){
	// XXX
	LogSetNewlinePrefix(LogDefault, "PEEK: ");
	Log("%s\n",inputstr);
	LogSetNewlinePrefix(LogDefault,DEFAULT_NEWLINE_PREFIX);
	return inputstr;
    }else{
	return NULL;
    }
}

void InputWait(void){
    if(input_status==INPUT_AVAILABLE){
	return;
    }
    WaitForSingleObject(input_cond,INFINITE);
}

void InputInit(void){
    DWORD dwThreadId;
    InitializeCriticalSection(&input_mutex);
    input_cond=CreateEvent(NULL,           // default security
                       FALSE,          // auto reset
                       FALSE,          // not signaled
                       NULL            // nameless
                       );

    wakeup_cond=CreateEvent(NULL,           // default security
                       FALSE,          // auto reset
                       FALSE,          // not signaled
                       NULL            // nameless
                       );
    input_thread=CreateThread(NULL,         // default security
			      0,            // default stacksize
			      input_func,   // worker function
			      NULL,         // no suplemetary data
			      0,            // run immediately
			      &dwThreadId   // dropped, but needed for the 
			      // call to work in Win9x
			      );          
    //    InitializeCriticalSection(&wakeup_mutex);
}

void InputCleanup(void){
    // What do we do here on windows???
}



