/*******************************************************
 * Typespeed Hacker                                    *
 * (c) 2005-2006 Arnold Noronha                        *
 * You are free to modify and/or redistribute this     *
 * program under the terms of the GNU General Public   *
 * Licence version 2 or above.                         *
 *                                                     *
 *******************************************************/

#include <vector>

#include <getopt.h>
#include <cstdio>
#include <sys/types.h>
#include <cctype>
#include <iostream>
#include <set>
#include <sstream>
#include <string>
#include <cstdlib>
#include <fstream>
#include <stack>

using namespace std;

#define GAME_ENG 5

//a hack to get my name on the top scores at cmi!!!!

int       req=0;  //required score
int       delay=2; //millisecs?
int       score=0;
int       outcount=0;
char      downkey[]="\x1b[B"; //single downkey 
FILE      *fgame_input, *fgame_output;
vector<string> dict;
string      szdicts[] = {
  "words.unix",
  "",
  "",
  "",
  "words.eng",
  "",
  "" 
};




//not the most efficient way ... but should serve our purpose



void load_dictionary(string loc)
{
  cout<<"Loading dictionary: "<<loc<<endl;

  string s;
  ifstream f(loc.c_str());
  
  while ( f >> s){
    //cout<<s<<"\r\n";
    if(s!= "mc" ) dict.push_back(s);
  }

  cout<<"\rDictionary size: " <<dict.size()<<"\r\n";

  //  sleep(1000);
  sort(dict.begin(), dict.end());
  
}

bool isword(string s)
{
  return binary_search(dict.begin(), dict.end(), s);
}

void start_game(int game_type) 
{
  cout<<"Let the games BEGIN!\n";

  //  fprintf(fgame_input, "\n");
  
  for(int i=0 ; i<game_type; i++)
    fputs(downkey, fgame_input);

  
  fprintf(fgame_input, "\n"); // Yep, we're up
  fflush(fgame_input);

  load_dictionary("/usr/share/games/typespeed/"+szdicts[GAME_ENG-1]);
}


//call start game after this...
void setup_head2head()
{
  fprintf(fgame_input, "21");
  fflush(fgame_input);
}

void setup_normalgame()
{

  assert(fgame_input);
  fprintf(fgame_input, "1");
  fflush(fgame_input);

}


void tryword ( string s){
  if(s.size() <= 2) return; //leave it da
  if (isword(s)) {
    fputs(  s.c_str()  , fgame_input); 
    fputs( "\n", fgame_input);
    fflush(fgame_input);
    cout << "\rWORD: "<<s.c_str()<<endl;
  }
  else if(s.size() >=4) {
#if DEBUGLEVEL >= 1
     cerr<< "\rBADWORD: " <<s<<endl;
#endif
  }


}

void trydata(string s){

#if DEBUGLEVEL>=1
  if(s.size() > 20) {
    cout<<"testword:"<<s<<" ( "<<s.size()<<" ) "<<"\r\n";
  }
#endif

  tryword(s);

  if(s.size() <= 1) return;

  tryword(s.substr(1, s.length()-1));
  tryword(s.substr(0, s.length()-1));

  if(s.size() <=2) return;

   tryword(s.substr(1, s.length()-2));
}

bool play(){
  

  string line;
  int bestpos=-1;
  string word="";

  

  FILE * junk = fopen("/tmp/junk", "w");

  int curnum=0;

  for(;!feof(fgame_output);){
    char ch='\0';
    
    ch=fgetc(fgame_output);
    fputc(ch , junk);
    fflush ( junk);

    if(ch=='\0') break;
    
    
    if(isdigit(ch)) curnum=curnum*10+ch-'0';
    else {
      
      
      if(curnum!=3133 and curnum != 1049 and curnum > score){
	              //there's this 3133t status problem 
	score = max(score, curnum);
        printf("\rSCORE is %d\n", score);
      }

      if(score > req)
	return 1;
      curnum=0;
    }

    if(ch=='-' or isalpha(ch) and islower(ch) ) line+=ch;
    else {
      // whatever I have stored in line must be a word (or junk)
      trydata(line);
      line = "";
    }

	 
  }
  
  
  return 0;

}

void show_usage() {
  cout<<"\r\nUsage ts-hack <req-score> <normal|head2head/h2h>\n";
  cout<<"\rAlso set the TSH_MAXSPEED variables\n";
}

int main(int argc, char *argv[]){




  assert(argc >= 3);

  req = atoi(argv[1]);
  string gametype = argv[2];

  string username;
  int maxspeed = atoi(getenv("TSH_MAXSPEED"));


  if(maxspeed == 0 ) {
    show_usage();
    exit(0);
  }

 
  //  const char datapipe[] = "/tmp/tspipe";

#define datapipe "/tmp/tspipe"

  //mknod(datapipe, S_IFIFO,0 );

  // NOTE: I couldn't find a better command for making named pipe,
  // until then this dirty method has to stay
  unlink(datapipe);
  unlink("/tmp/junk");
  system("mkfifo " datapipe);

  fgame_input = popen ( "typespeed >  " datapipe , "w" );  
  assert(fgame_input);

  fgame_output =  fopen( datapipe, "r");
  assert(fgame_output);

  cout<<"Waiting while typespeed starts up...\r\n";
  sleep(5);


  cout<<"Started\r\n";

  
 
  if(gametype == "normal")   {
    cout<<"Starting normal game\r\n";
    setup_normalgame();
  }
  else if(gametype == "h2h" || gametype =="head2head"){
    cout<<"Starting head to head\r\n";
    setup_head2head();
  }
  else{
    show_usage();
    return 1;
  }

  //right now only english supported, supporting the rest is not at all hard
  start_game(GAME_ENG);


  cout<<endl;


  ///////////////////////////////////////////////

  play();

  ///////////////////////////////////////////////

  // terminate

  fflush(fgame_output);

  for(int i =9;i >=0 ;i-- ){
    
    cout<<"\rWaiting "<<i<<" seconds to end the game..."<<flush;
    sleep(1);
    fflush(fgame_output);
  }
  cout<<endl<<endl;;
  

  fprintf(fgame_input, "\n");

  sleep(2);
  

  cout<<"\rTake a look at /tmp/junk and then enter "
    "your name (C-c to exit):"<<flush;

  cin>>username;

  fprintf(fgame_input, "%s\n" , username.c_str());


  
  // how do i quit
  
  fprintf(fgame_input, "666666666\n6666"); //put in a few extra:)
  fflush(fgame_input);

  sleep(2);
  

  // cleanup
  fclose(fgame_input);
  fclose(fgame_output);
  unlink(datapipe);
  return 0;
}

