#include "comment.header"

/* Generated by Interface Builder */

/* $Id: GoApp.m,v 1.3 1997/07/06 19:37:57 ergo Exp $ */

/*
 * $Log: GoApp.m,v $
 * Revision 1.3  1997/07/06 19:37:57  ergo
 * actual version
 *
 * Revision 1.5  1997/06/03 23:00:58  ergo
 * changed the appearance of the windows
 *
 * Revision 1.4  1997/05/30 18:44:15  ergo
 * Added an Inspector
 *
 * Revision 1.3  1997/05/04 18:56:53  ergo
 * added time control for moves
 *
 */

#import <appkit/appkit.h>
#import <appkit/PrintInfo.h>

#include <string.h>
#import "GoApp.h"
#import "Board.h"
#import "ClickCell.h"
#import "MatrixScrollView.h"
#import "GoServer.h"
#import "ServerList.h"
#include "igs.h"
#include "godict.h"

#define CURRENT_VERSION	"Version 2.7"

unsigned char p[19][19], l[19][19], ma[19][19], ml[19][19];
char special_characters[19][19], sgComment[2000], sgNodeName[200];
int hist[19][19], currentMoveNumber;
int rd, lib, play, pass, handicap, whiteSide, blackSide, MAXX, MAXY;
int currentStone, opposingStone, blackCaptured, whiteCaptured;
int blackTerritory, whiteTerritory, SmartGoGameFlag, initialization;
float black_Score, white_Score;
int blackCapturedKoI, blackCapturedKoJ, whiteCapturedKoI, whiteCapturedKoJ;
int bothSides, neitherSide, blackPassed, whitePassed, manualScoring, manScoreTemp;
int typeOfScoring, AGAScoring;
int opn[9];                               // opening pattern flag
int gameType;
BOOL finished, printBold;
gameHistory gameMoves[500];
int lastMove, boardChanged;
node *SGgameMoves, *currentNode, *rootNode;
FILE *smartGoInputFile;
char *SGfile, *currentSGfilePosition;
char *IGSStatusText, IGSPasswordText[20], IGSLoginText[20];
GODICT *godict;

char *getpassword(void) {
	return IGSPasswordText;
}

char *getloginname(void) {
	return IGSLoginText;
}

void checkingNetTraffic(DPSTimedEntry timedEntry, double timeNow, void *data) {
	[(id)data checkNetTraffic];
}

void IGSSendString(char *s) {

	sendstr(s);
	printBold = YES;
	[NXApp SetIGSStatus:s];

}

void stripChar(char *s, char c) {
	int i, j;

	i = 0;
	while (i < strlen(s)) {
		if (s[i] == c) {
	  		for (j = i; j < strlen(s) - 1; j++)
	    		s[j] = s[j+1];
	  		s[strlen(s) - 1] = 0;
		}
      	else {
	  		i++;
		}
    }
}

int saveNeXTGoFile(const char *fileName)
{
  FILE *NGoFile;
  int i, j;

  if ((NGoFile = fopen(fileName, "w")) == NULL)
    return 1;

  fprintf(NGoFile, "%d\n", handicap);
  fprintf(NGoFile, "%d\n", whiteSide);
  fprintf(NGoFile, "%d\n", blackSide);
  fprintf(NGoFile, "%d\n", MAXX);
  fprintf(NGoFile, "%d\n", MAXY);
  fprintf(NGoFile, "%d\n", currentStone);
  fprintf(NGoFile, "%d\n", opposingStone);
  fprintf(NGoFile, "%d\n", blackCaptured);
  fprintf(NGoFile, "%d\n", whiteCaptured);
  fprintf(NGoFile, "%d\n", blackCapturedKoI);
  fprintf(NGoFile, "%d\n", blackCapturedKoJ);
  fprintf(NGoFile, "%d\n", whiteCapturedKoI);
  fprintf(NGoFile, "%d\n", whiteCapturedKoJ);
  fprintf(NGoFile, "%d\n", bothSides);
  fprintf(NGoFile, "%d\n", neitherSide);
  fprintf(NGoFile, "%d\n", blackPassed);
  fprintf(NGoFile, "%d\n", whitePassed);
  fprintf(NGoFile, "%d\n", lastMove);
  for (i = 0; i < 9; i++)
    fprintf(NGoFile, "%d\n", opn[i]);
  for (i = 0; i < lastMove; i++)
    {
      fprintf(NGoFile, "%d\n", gameMoves[i].numchanges);
      fprintf(NGoFile, "%d\n", gameMoves[i].blackCaptured);
      fprintf(NGoFile, "%d\n", gameMoves[i].whiteCaptured);
      for (j = 0; j < gameMoves[i].numchanges; j++)
	{
	  fprintf(NGoFile, "%d\n", gameMoves[i].changes[j].added);
	  fprintf(NGoFile, "%d\n", gameMoves[i].changes[j].color);
	  fprintf(NGoFile, "%d\n", gameMoves[i].changes[j].x);
	  fprintf(NGoFile, "%d\n", gameMoves[i].changes[j].y);
	}
    }

  fclose(NGoFile);

  return 0;
}

int saveSmartGoFile(const char *fileName)
{
  FILE *NGoFile;
  int i, j;

  if ((NGoFile = fopen(fileName, "w")) == NULL)
    return 1;
  fprintf(NGoFile, "(\n;\nGaMe[1]\nVieW[]\n");
  fprintf(NGoFile, "SiZe[%d]\nKoMi[%3.1f]\nHAndicap[%d]", MAXX,
	  ((handicap == 0)?KOMI:0.5), handicap);
  fprintf(NGoFile,"\nComment[ A game between ");

  if (gameType != LOCAL)
    {
      fprintf(NGoFile, "two people on the network.\n\n");
    }
  else if (neitherSide)
    {
      fprintf(NGoFile,"two human players.\n\n");
    }
  else if (bothSides)
    {
      fprintf(NGoFile,"two computer players.\n\n");
    }
  else
    {
      fprintf(NGoFile,"the computer and a human player.\n\n");
    }

  if (finished)
    {
      fprintf(NGoFile,"        Result:  %s wins by %8.1f.]\n",
	      (black_Score > white_Score)?"Black":"White",
	      fabs(black_Score - white_Score));
    }
  else
    {
      fprintf(NGoFile, "]\n");
    }

  if (handicap > 1)
    {
      int q, half;

      q = (MAXX < 13)?2:3;
      half = (MAXX + 1)/2 - 1;

      switch (handicap) {
      case 2:
	fprintf(NGoFile, "AddBlack[%c%c][%c%c]\n", q+'a', MAXY-q-1+'a',
		MAXX-q-1+'a', q+'a');
	break;
      case 3:
	fprintf(NGoFile, "AddBlack[%c%c][%c%c][%c%c]\n", q+'a', MAXY-q-1+'a',
		MAXX-q-1+'a', q+'a', q+'a', q+'a');
	break;
      case 4:
	fprintf(NGoFile, "AddBlack[%c%c][%c%c][%c%c][%c%c]\n", q+'a',
		MAXY-q-1+'a', MAXX-q-1+'a', q+'a', q+'a', q+'a', MAXX-q-1+'a',
		MAXY-q-1+'a');
	break;
      case 5:
	fprintf(NGoFile, "AddBlack[%c%c][%c%c][%c%c][%c%c][%c%c]\n", q+'a',
		MAXY-q-1+'a', MAXX-q-1+'a', q+'a', q+'a', q+'a', MAXX-q-1+'a',
		MAXY-q-1+'a', half+'a', half+'a');
	break;
      case 6:
	fprintf(NGoFile, "AddBlack[%c%c][%c%c][%c%c][%c%c][%c%c][%c%c]\n",
		q+'a', MAXY-q-1+'a', MAXX-q-1+'a', q+'a', q+'a', q+'a',
		MAXX-q-1+'a', MAXY-q-1+'a', q+'a', half+'a', MAXX-q-1+'a',
		half+'a');
	break;
      case 7:
	fprintf(NGoFile, "AddBlack[%c%c][%c%c][%c%c][%c%c][%c%c][%c%c][%c%c]\n",
		q+'a', MAXY-q-1+'a', MAXX-q-1+'a', q+'a', q+'a', q+'a',
		MAXX-q-1+'a', MAXY-q-1+'a', q+'a', half+'a', MAXX-q-1+'a',
		half+'a', half+'a', half+'a');
	break;
      case 8:
	fprintf(NGoFile, "AddBlack[%c%c][%c%c][%c%c][%c%c][%c%c][%c%c][%c%c][%c%c]\n",
		q+'a', MAXY-q-1+'a', MAXX-q-1+'a', q+'a', q+'a', q+'a',
		MAXX-q-1+'a', MAXY-q-1+'a', q+'a', half+'a', MAXX-q-1+'a',
		half+'a', half+'a', q+'a', half+'a', MAXY-q-1+'a');
	break;
      case 9:
	fprintf(NGoFile, "AddBlack[%c%c][%c%c][%c%c][%c%c][%c%c][%c%c][%c%c][%c%c][%c%c]\n",
		q+'a', MAXY-q-1+'a', MAXX-q-1+'a', q+'a', q+'a', q+'a',
		MAXX-q-1+'a', MAXY-q-1+'a', q+'a', half+'a', MAXX-q-1+'a',
		half+'a', half+'a', q+'a', half+'a', MAXY-q-1+'a', half+'a',
		half+'a');
	break;
      }
    }

  for (i = 0; i < lastMove; i++)
    {
      for (j = 0; j < gameMoves[i].numchanges; j++)
	{
	  if (gameMoves[i].changes[j].added)
	    switch (gameMoves[i].changes[j].color)
	      {
	      case 1:
		if (gameMoves[i].changes[j].x >= 0)
		  {
		    fprintf(NGoFile,";\nWhite[%c%c]\n",
			    gameMoves[i].changes[j].x+'a',
			    gameMoves[i].changes[j].y+'a');
		  }
		else
		  {
		    fprintf(NGoFile, ";\nWhite[tt]\n");
		  }
		break;
	      case 2:
		if (gameMoves[i].changes[j].x >= 0)
		  {
		    fprintf(NGoFile,";\nBlack[%c%c]\n",
			    gameMoves[i].changes[j].x+'a',
			    gameMoves[i].changes[j].y+'a');
		  }
		else
		  {
		    fprintf(NGoFile, ";\nBlack[tt]\n");
		  }
		break;
	      }
	}
    }

  fprintf(NGoFile,")\n\n");
  fclose(NGoFile);

  return 0;
}

@implementation GoApp

+ initialize
{
	static NXDefaultsVector NeXTGoDefaults = {
		{"Handicap", 		"0"},
		{"BoardSize", 		"19"}, /* MAXX */
		{"BlackSide", 		"1"},
		{"WhiteSide", 		"0"},
		{"ManualScoring", 	"1"},
		{"TypeOfScoring", 	"0"},
		{"AGAScoring",		"0"},
		{"Server0",	"igs.nuri.net 6969 guest guest"},
		{"Server1",	"nngs.cosmic.org 9696 guest guest"},
		{NULL, 				NULL}
	};

	NXRegisterDefaults("NeXTGo", NeXTGoDefaults);

	return self;
}

- appDidInit:app {
	char str[80];

	godict = NULL;
	IGSfont = [Font newFont:"Ohlfs" size:10];
	IGSboldFont = [Font newFont:"Helvetica" size:10];
	[gameWindow setMiniwindowIcon:"NeXTGoFile"];
	strcpy(str, "NeXTGo -- ");
	strcat(str, CURRENT_VERSION);
	[versionString setStringValue:CURRENT_VERSION];
	[gameWindow setTitle:str];
	[[IGSStatus docView] setFont:IGSfont];
	[[smartGoComments docView] setFont:IGSfont];
	[controller initPanel];
	

	lastMove = 0;
	gameType = LOCAL;

	handicap 		= atoi(NXGetDefaultValue("NeXTGo", "Handicap"));
	MAXX 			= atoi(NXGetDefaultValue("NeXTGo", "BoardSize"));
	blackSide 		= atoi(NXGetDefaultValue("NeXTGo", "BlackSide"));
	whiteSide 		= atoi(NXGetDefaultValue("NeXTGo", "WhiteSide"));
	manualScoring 	= atoi(NXGetDefaultValue("NeXTGo", "ManualScoring"));
	typeOfScoring 	= atoi(NXGetDefaultValue("NeXTGo", "TypeOfScoring"));
	AGAScoring		= atoi(NXGetDefaultValue("NeXTGo", "AGAScoring"));

    MAXY = MAXX;
    manScoreTemp = manualScoring;

    [handicapSlider setIntValue:handicap];
    [handicapText setIntValue:handicap];
    [sizeSlider setIntValue:MAXX];
    [sizeText setIntValue:MAXX];
    [BlackPlayer selectCellAt:blackSide:0];
    [WhitePlayer selectCellAt:whiteSide:0];
    [scoringMethod selectCellAt:manualScoring:0];
    [scoringType selectCellAt:typeOfScoring:0];
    [AGAscoringMethodFlag setIntValue:AGAScoring];
    [savePrefsFlag setIntValue:1];

	neitherSide = 0;
	bothSides = 0;
	manScoreTemp = manualScoring;

	if ((blackSide == 0) && (whiteSide == 0))
    	neitherSide++;
	if ((blackSide == 1) && (whiteSide == 1))
    	bothSides++;

	[self NewGame:self];

	[[[NXApp printInfo] setHorizCentered:YES] setVertCentered:YES];

	[gameWindow setFrameAutosaveName:"NeXTGoGameWindow"];
	[gameWindow makeKeyAndOrderFront:self];
	[gameInspector setFrameAutosaveName:"NeXTGoGameInspector"];
	[gameInspector makeKeyAndOrderFront:self];
	[gameWindow makeKeyAndOrderFront:self];
	[IGSPanel setFrameAutosaveName:"NeXTGoIGSPanel"];

	SmartGoGameFlag = 0;
	
	CommandSender = nil;
	
	return self;
}

- showError: (const char *)errorMessage
{
  NXRunAlertPanel("NeXTGo Error", errorMessage,"OK", NULL, NULL);
  return self;
}

- UserPass:sender
{
  if (SmartGoGameFlag)
    return self;

  [MainGoView passMove];

  return self;
}

- stopGame:sender
{
  if (SmartGoGameFlag)
    return self;

  [MainGoView stop:self];

  return self;
}

- startGame:sender {
	
	if (SmartGoGameFlag)
    	return self;

	[MainGoView go:self];

	return self;
}

- NewGame:sender
{
  int resp;

  if (gameType == IGSGAME)
    {
      NXRunAlertPanel("IGS Error", "You must first close your IGS session before\n\
beginning a new game.", "OK", NULL, NULL);
      return self;
    }

  if (SmartGoGameFlag)
    {
      SmartGoGameFlag = 0;
      [smartGoPanel close];
    }

  gameType = LOCAL;

  if ((lastMove > 0) && (!finished))
    {
      resp = NXRunAlertPanel("NeXTGo Warning", "A game is in process.  Do you wish to abandon it?", "Abandon", "Cancel", 0);

      if (resp == NX_ALERTALTERNATE)
	return self;
    }

  [MainGoView startNewGame];
  [MainGoView display];

  lastMove = 0;

  return self;
}

- SetPreferences:sender {
	char str[80];

	handicap = [handicapSlider intValue];
	MAXX = MAXY = [sizeSlider intValue];
	blackSide = [BlackPlayer selectedRow];
	whiteSide = [WhitePlayer selectedRow];
	manualScoring = [scoringMethod selectedRow];
	typeOfScoring = [scoringType selectedRow];
	AGAScoring = [AGAscoringMethodFlag intValue];

	neitherSide = 0;
	bothSides = 0;
	manScoreTemp = manualScoring;

	if ((blackSide == 0) && (whiteSide == 0))
    	neitherSide++;
	if ((blackSide == 1) && (whiteSide == 1))
    	bothSides++;

	[self NewGame:self];

	[prefPanel close];

	if ([savePrefsFlag intValue]) {
		sprintf(str, "%d", handicap);
		NXWriteDefault("NeXTGo", "Handicap", str);
    	sprintf(str, "%d", MAXX);
		NXWriteDefault("NeXTGo", "BoardSize", str);
    	sprintf(str, "%d", blackSide);
		NXWriteDefault("NeXTGo", "BlackSide", str);
    	sprintf(str, "%d", whiteSide);
		NXWriteDefault("NeXTGo", "WhiteSide", str);
    	sprintf(str, "%d", manualScoring);
		NXWriteDefault("NeXTGo", "ManualScoring", str);
    	sprintf(str, "%d", typeOfScoring);
		NXWriteDefault("NeXTGo", "TypeOfScoring", str);
    	sprintf(str, "%d", AGAScoring);
		NXWriteDefault("NeXTGo", "AGAScoring", str);
	}

	return self;
}

- displayNewSGNode
{
  node *var_list, *current_var;

  [smartGoNodeNumber setIntValue:currentNode->nodenum];
  [[smartGoComments docView] setText:""];
  [[smartgoVariants docView] setText:""];
  [self AddSGComment:sgComment];
  [self SetSGNodeName:sgNodeName];

  [MainGoView display];
  [MainGoView setblacksPrisoners:blackCaptured];
  [MainGoView setwhitesPrisoners:whiteCaptured];

  for (var_list = currentNode->variants; var_list != NULL;
       var_list = var_list->next_var)
    {
      char var_name[80];

      current_var = var_list;
      while (current_var->properties == NULL)
	{
	  current_var = forwardOneNode(current_var);
	}

      sgNodeName[0] = 0;
      buildToNode(current_var);
      if (boardChanged)
	[MainGoView doClick];
      sprintf(var_name, "%d: %s", current_var->nodenum, sgNodeName);
      [self AddSGVariantName:var_name];
    }

  if (currentNode->variants != NULL)
    {
      sgNodeName[0] = 0;
      sgComment[0] = 0;
      buildToNode(currentNode);
      if (boardChanged)
	[MainGoView doClick];
    }

  return self;
}

- stepSmartGoFile:sender
{
  sgComment[0] = 0;
  sgNodeName[0] = 0;

  currentNode = stepForward(currentNode);

  [self displayNewSGNode];

  return self;
}

- stepBackSmartGoFile:sender
{
  sgComment[0] = 0;
  sgNodeName[0] = 0;

  currentNode = stepBackward(currentNode);

  [self displayNewSGNode];

  return self;
}

- jumpSmartGoFile:sender
{
  sgComment[0] = 0;
  sgNodeName[0] = 0;

  currentNode = jumpForward(currentNode);

  [self displayNewSGNode];

  return self;
}

- jumpBackSmartGoFile:sender
{
  sgComment[0] = 0;
  sgNodeName[0] = 0;

  currentNode = jumpBackward(currentNode);

  [self displayNewSGNode];

  return self;
}

- AddSGComment:(char *)s
{
  Text *docView = [smartGoComments docView];
  int dvLen;
  char retstr[5];

  strcpy(retstr, "\n");

  dvLen = [docView textLength];
  [docView setSel:dvLen :dvLen];
  [docView replaceSel: s];

  [docView setSel:[docView textLength] :[docView textLength]];

  [docView scrollSelToVisible];

  return self;
}

- AddSGVariantName:(char *)s
{
  Text *docView = [smartgoVariants docView];
  int dvLen;
  char retstr[5];

  strcpy(retstr, "\n");

  dvLen = [docView textLength];
  [docView setSel:dvLen :dvLen];
  [docView replaceSel: s];

  [docView setSel:[docView textLength] :[docView textLength]];

  [docView replaceSel: retstr];
  [docView setSel:[docView textLength] :[docView textLength]];

  [docView scrollSelToVisible];

  return self;
}

- SetSGNodeName:(char *)s
{
  [smartGoNodeName setStringValue:s];
  [smartGoNodeName display];

  return self;
}

- openNeXTGoFile:(const char*)aFile
{
	FILE *NGoFile;
	int i, j, t;

    if ((NGoFile = fopen(aFile, "r")) == NULL) {
		return self;
	}

    SmartGoGameFlag = 0;
    fscanf(NGoFile, "%d", &handicap);
    fscanf(NGoFile, "%d", &whiteSide);
    fscanf(NGoFile, "%d", &blackSide);
    fscanf(NGoFile, "%d", &MAXX);
    fscanf(NGoFile, "%d", &MAXY);
    [MainGoView startNewGame];
    fscanf(NGoFile, "%d", &opposingStone);
    fscanf(NGoFile, "%d", &currentStone);
    fscanf(NGoFile, "%d", &blackCaptured);
    fscanf(NGoFile, "%d", &whiteCaptured);
    fscanf(NGoFile, "%d", &blackCapturedKoI);
    fscanf(NGoFile, "%d", &blackCapturedKoJ);
    fscanf(NGoFile, "%d", &whiteCapturedKoI);
    fscanf(NGoFile, "%d", &whiteCapturedKoJ);
    fscanf(NGoFile, "%d", &bothSides);
    fscanf(NGoFile, "%d", &neitherSide);
    fscanf(NGoFile, "%d", &blackPassed);
    fscanf(NGoFile, "%d", &whitePassed);
    fscanf(NGoFile, "%d", &lastMove);
    for (i = 0; i < 9; i++)
      {
        fscanf(NGoFile, "%d", &t);
	opn[i] = t;
      }
    for (i = 0; i < MAXX; i++)
      for (j = 0; j < MAXY; j++)
	p[i][j] = hist[i][j] = 0;

    for (i = 0; i < lastMove; i++)
      {
	fscanf(NGoFile, "%d", &gameMoves[i].numchanges);
	fscanf(NGoFile, "%d", &gameMoves[i].blackCaptured);
	fscanf(NGoFile, "%d", &gameMoves[i].whiteCaptured);
	gameMoves[i].changes = (struct change *)
	  malloc((size_t)sizeof(struct change)*gameMoves[i].numchanges);
	for (j = 0; j < gameMoves[i].numchanges; j++)
	  {
	    fscanf(NGoFile, "%d", &gameMoves[i].changes[j].added);
	    fscanf(NGoFile, "%d", &gameMoves[i].changes[j].color);
	    fscanf(NGoFile, "%d", &gameMoves[i].changes[j].x);
	    fscanf(NGoFile, "%d", &gameMoves[i].changes[j].y);
	  }
      }

    for (i = 0; i < lastMove; i++)
      for (j = 0; j < gameMoves[i].numchanges; j++)
	{
	  if (gameMoves[i].changes[j].added)
	    {
	      p[gameMoves[i].changes[j].x][gameMoves[i].changes[j].y] =
		gameMoves[i].changes[j].color;
	      hist[gameMoves[i].changes[j].x][gameMoves[i].changes[j].y] = i;
	    }
	  else
	    {
	      p[gameMoves[i].changes[j].x][gameMoves[i].changes[j].y] = 0;
	    }
	}
    blackCaptured = gameMoves[lastMove-1].blackCaptured;
    whiteCaptured = gameMoves[lastMove-1].whiteCaptured;

    [MainGoView refreshIO];

    [MainGoView resetButtons];

    fclose(NGoFile);

    [MainGoView lockFocus];
    [[MainGoView window] flushWindow];
    [MainGoView display];
    [MainGoView unlockFocus];

	NXPing();

	return self;
}

- initTranslator:sender {
  	char filename[MAXPATHLEN+1];
	NXBundle   *bundle;

	bundle = [NXBundle bundleForClass:[self class]];
	strcpy(filename, [bundle directory] ); 
  strcat(filename,"/");
  strcat(filename,DEFDICT);

  if (godict == NULL)
    {
      godict = load_dict(filename);

      if (godict == NULL)
	{
	  NXRunAlertPanel("Translate Error","There is a problem opening the dictionary file.", "OK", 0, 0);
	  return self;
	}
    }

  [translateWindow makeKeyAndOrderFront:self];
  [translateWindow setMiniwindowIcon:"NeXTGoFile"];
  [translateWindow display];
  [translateTerm setStringValue:""];
  [translateTerm selectText:self];
  [translateButton setEnabled:YES];
  [[translateResults docView] setText:""];

  return self;
}

- performTranslate:sender
{
  GODICT *d;
  char term[80];
  extern int termtypes, languages;

  strcpy(term, [translateTerm stringValue]);
  if (strlen(term) == 0)
    return self;

  termtypes = CD_MISC*[transTypeMISC intValue];
  termtypes += CD_NAME*[transTypeNAME intValue];
  termtypes += CD_CHAM*[transTypeCHAM intValue];
  termtypes += CD_TECH*[transTypeTECH intValue];
  termtypes += CD_POLI*[transTypePOLI intValue];
  termtypes += CD_DIGI*[transTypeDIGI intValue];

  languages = LANG_DG*[transLangDG intValue];
  languages += LANG_CP*[transLangCP intValue];
  languages += LANG_JP*[transLangJP intValue];
  languages += LANG_CH*[transLangCH intValue];
  languages += LANG_RK*[transLangRK intValue];
  languages += LANG_GB*[transLangGB intValue];
  languages += LANG_NL*[transLangNL intValue];
  languages += LANG_GE*[transLangGE intValue];
  languages += LANG_FR*[transLangFR intValue];
  languages += LANG_SV*[transLangSV intValue];

  [[translateResults docView] setText:""];
  d = godict;

  while (d != NULL)
    {
      d = search_dict(d,term);
      if (d != NULL)
	{
	  [self translateOutput:d];
	  d = d->dct_next;
	}
    }
  [translateTerm selectText:self];

  return self;
}

- translateOutput:(GODICT *)d
{
  extern int languages;

  printBold = YES;
  [self addTranslateResults:LB_CD];
  switch(d->dct_type)
    {
    case CD_CHAM:
      [self addTranslateResults:MSG_CHAM];
      break;
    case CD_TECH:
      [self addTranslateResults:MSG_TECH];
      break;
    case CD_NAME:
      [self addTranslateResults:MSG_NAME];
      break;
    case CD_POLI:
      [self addTranslateResults:MSG_POLI];
      break;
    case CD_DIGI:
      [self addTranslateResults:MSG_DIGI];
      break;
    default:
      [self addTranslateResults:MSG_MISC];
      break;
    }

  [self addTranslateResults:"\n"];

  if (d->dct_jp && (languages & (LANG_JP)))
    {
      printBold = YES;
      [self addTranslateResults:LB_JP];
      [self addTranslateResults:d->dct_jp];
      [self addTranslateResults:"\n"];
    }
  if (d->dct_ch && (languages & (LANG_CH)))
    {
      printBold = YES;
      [self addTranslateResults:LB_CH];
      [self addTranslateResults:d->dct_ch];
      [self addTranslateResults:"\n"];
    }
  if (d->dct_rk && (languages & (LANG_RK)))
    {
      printBold = YES;
      [self addTranslateResults:LB_RK];
      [self addTranslateResults:d->dct_rk];
      [self addTranslateResults:"\n"];
    }
  if (d->dct_gb && (languages & (LANG_GB)))
    {
      printBold = YES;
      [self addTranslateResults:LB_GB];
      [self addTranslateResults:d->dct_gb];
      [self addTranslateResults:"\n"];
    }
  if (d->dct_nl && (languages & (LANG_NL)))
    {
      printBold = YES;
      [self addTranslateResults:LB_NL];
      [self addTranslateResults:d->dct_nl];
      [self addTranslateResults:"\n"];
    }
  if (d->dct_ge && (languages & (LANG_GE)))
    {
      printBold = YES;
      [self addTranslateResults:LB_GE];
      [self addTranslateResults:d->dct_ge];
      [self addTranslateResults:"\n"];
    }
  if (d->dct_fr && (languages & (LANG_FR)))
    {
      printBold = YES;
      [self addTranslateResults:LB_FR];
      [self addTranslateResults:d->dct_fr];
      [self addTranslateResults:"\n"];
    }
  if (d->dct_fr && (languages & (LANG_SV)))
    {
      printBold = YES;
      [self addTranslateResults:LB_SV];
      [self addTranslateResults:d->dct_sv];
      [self addTranslateResults:"\n"];
    }
  if (d->dct_dg && (languages & (LANG_DG)))
    {
      printBold = YES;
      [self addTranslateResults:LB_DG];
      [self addTranslateResults:"\n"];
      [self addTranslateResults:d->dct_dg];
      [self addTranslateResults:"\n"];
    }
  if (d->dct_cp && (languages & (LANG_CP)))
    {
      printBold = YES;
      [self addTranslateResults:LB_CP];
      [self addTranslateResults:d->dct_cp];
      [self addTranslateResults:"\n"];
    }

  [self addTranslateResults:"\n\n"];

  return self;
}

- addTranslateResults:(char *)s
{
  Text *docView = [translateResults docView];
  int dvLen;

  dvLen = [docView textLength];
  [docView setSel:dvLen :dvLen];
  [docView setSelFont:IGSfont];
  printBold = NO;
  [docView replaceSel:s];
  [docView setSel:[docView textLength] :[docView textLength]];

  [docView scrollSelToVisible];

  return self;
}

- openSmartGoFile:(const char*)aFile
{
  	char dispFileName[80];
  	int i, j;
  	struct stat statbuf;

  	if (gameType != LOCAL) {
    	NXRunAlertPanel("IGS Error", "You must first close your IGS session before\n\
		 opening a Smart-Go file.", "OK", NULL, NULL);
      	return self;
  	}

    if ((smartGoInputFile = fopen(aFile, "r")) == NULL) {
      		return self;
	}

	SGgameMoves = NULL;
	SmartGoGameFlag = 1;
	initialization = 0;

	[smartGoPanel makeKeyAndOrderFront:self];
    [smartGoPanel setMiniwindowIcon:"NeXTGoFile"];
    [smartGoPanel display];
    [stepForwardButton setEnabled:YES];

	stat(aFile, &statbuf);
		SGfile = (char *) malloc ((size_t)statbuf.st_size+10);
	if (fread(SGfile, statbuf.st_size, 1, smartGoInputFile) != 1) {
			[self showError:"Error on Read"];
			fclose(smartGoInputFile);
			free(SGfile);
			return self;
	}

	fclose(smartGoInputFile);

	[MainGoView startNewGame];
	[MainGoView setMess1:"Smart-Go Playback"];
	j = 0;
	for (i = 0; i < strlen(aFile); i++) {
			if (aFile[i] == '/') {
				j = i;
			}
	}
    for (i = j+1; i < strlen(aFile); i++) {
			dispFileName[i-j-1] = aFile[i];
	}
    dispFileName[strlen(aFile) - j - 1] = 0;

	[MainGoView setMess2:dispFileName];

	rootNode = parse_tree(SGfile);
	MAXX = MAXY = 19;
	currentNode = stepForward(rootNode);
	[self displayNewSGNode];

	NXPing();

	return self;
}

- IGSSendCommand:sender {

	/* first we catch all commands which have a special implementation */
	id aString = [[MiscString alloc] initString:[IGSCommand stringValue]];
	
	if (strstr((char *)[IGSCommand stringValue], "done") &&
		([aString numOf:" "] + strlen("done")) == 
		 [aString length]){
		[IGSCommand selectText:self];  
		[self IGSdone:self];
	}
	
	else 
		if (strstr((char *)[IGSCommand stringValue], "unobserve") &&
			([aString numOf:" "] + strlen("unobserve")) == 
			 [aString length]){
			[self IGSunobserve:self];
			[IGSCommand selectText:self];  
		}
	
		else 
			if (strstr((char *)[IGSCommand stringValue], "observe") &&
				([aString numOf:" "] + strlen("observe")) == 
			 	 [aString length]){
				[self IGSobserve:self];
				[IGSCommand selectText:self];  
			}
	
			else 
				if (strstr((char *)[IGSCommand stringValue], "load") &&
					([aString numOf:" "] + strlen("load")) == 
					 [aString length]){
					[self IGSOpenLoadGame:self];
					[IGSCommand selectText:self];  
	 			}
				
				else 
					if (strstr((char *)[IGSCommand stringValue], "quit") &&
						([aString numOf:" "]+strlen("quit")) 
						== [aString length]){
				   		[self IGSquit:self];
						[IGSCommand selectText:self];  
					}
					else {
						IGSSendString((char *)[IGSCommand stringValue]);
 						IGSSendString("\n");
					}
	if (CommandSender != nil) {
		[CommandSender makeKeyAndOrderFront:self];
		CommandSender = nil;
	}
		

	return self;
}

- connect:(GoServer*)server {
	char s[80];

	sethost((char*)[server name]);
	setport([server port]);
	strcpy(IGSLoginText, (char *)[server login]);
	strcpy(IGSPasswordText,[server password]);

	if (SmartGoGameFlag) {
		SmartGoGameFlag = 0;
		[smartGoPanel close];
	}

	[[IGSStatus docView] setText:""];
	[IGSPanel makeKeyAndOrderFront:self];
	[IGSPanel setMiniwindowIcon:"NeXTGoFile"];
	[IGSCommand selectText:self];

  if (open_connection())
    {
      [self SetIGSStatus:"Unable to make a connection.\n"];
      gameType = LOCAL;

      NXRunAlertPanel("IGS Error", "I was unable to make a connection.", "OK", 0, 0);
      [IGSPanel close];

      return self;
    }

  [self SetIGSStatus:"Connection established."];
  sprintf(s, "Logging in as %s\n", IGSLoginText);
  [self SetIGSStatus:s];

  timer = DPSAddTimedEntry(0.25, &checkingNetTraffic, self, NX_BASETHRESHOLD);

  gameType = IGSGAME;
  finished = YES;
  idle = 1;
  [loadMenuCell setEnabled:YES];
  [observeMenuCell setEnabled:YES];

  initparser();

  return self;
}

- checkNetTraffic
{
  fd_set readers;
  struct timeval to;
  int sel;

  to.tv_sec = 0;
  to.tv_usec = 0;

  FD_ZERO(&readers);
  FD_SET(sock, &readers);

  sel = select(sock + 1, &readers, NULL, NULL, &to);
  if (FD_ISSET(sock, &readers))
    incomingserver();

  return self;
}

- SetIGSStatus:(char *)s {
	Text *docView = [IGSStatus docView];
	int dvLen;
	char retstr[5];

	strcpy(retstr, "\n");

	dvLen = [docView textLength];
	[docView setSel:dvLen :dvLen];
	[docView setSelFont:IGSfont];
	[docView replaceSel: s];
	if (printBold) {
		[docView setSel:dvLen :[docView textLength]];
      	[docView setSelFont:IGSboldFont];
      	[docView setSelFontStyle:NX_BOLD];
      	printBold = NO;
    }
  	else
		[docView setSel:[docView textLength] :[docView textLength]];

  	if (s[strlen(s) - 1] != '\n') {
		[docView setSel:[docView textLength] :0];
		[docView replaceSel: retstr];
		[docView scrollSelToVisible];
	}

	[docView scrollSelToVisible];

	[IGSCommand selectText:self];  

	return self;
}

- getGoView{
	return MainGoView;
}

- open:sender {

	const char* const types[] = {"nextgo", "mgt",  NULL};

	id open = [OpenPanel new];

	[open allowMultipleFiles:NO];

	if (NX_OKTAG == [open runModalForTypes:types]) {
		char * cc = rindex([open filename],'.');
		cc++;
		if (strcmp(cc,types[0])) {
			[self openSmartGoFile:[open filename] ];
		}
		else {
			[self openNeXTGoFile:[open filename] ];
		}
		return self;
	}
	return self;
}

- save:sender {
	char  aString[256] = "";
	id save = [SavePanel new];

	strcpy(aString, [gameWindow title]);
	stripChar(aString, ' ');
	stripChar(aString, '(');
	stripChar(aString, ')');
	stripChar(aString, '*');
		

	/* set the initial format */

	[self setFormat:formatMatrix];

	/* put format box in view */
	[save setAccessoryView:formatMatrix];

	if ((1 == [save runModalForDirectory: [save directory] file:aString])) {
		if (!strcmp([ [formatMatrix selectedCell] title], "NeXTGo")) {
      		saveNeXTGoFile([save filename]);
  			NXPing();
		}
		else {
      		saveSmartGoFile([save filename]);
  			NXPing();
		}
	}
	return self;
}

- setFormat:sender
{
	const char *const types[] = {"nextgo", "mgt", NULL};

	if (!strcmp([ [sender selectedCell] title],"NeXTGo")) {
		[ [SavePanel new] setRequiredFileType:types[0]];
	}
	else {
 		[ [SavePanel new] setRequiredFileType:types[1]];
	}
	return self;
}

 
/*
  The following methods are the various commands for the Internet Go Server
  */

- IGSobserve:sender
{
  message mess;
  NXRect frameRect = {15, 30, 497, 226}, scrollRect = {0, 0, 497, 226};
  NXSize cellSize = {470, 30};
  char str[80];
  int i;

  idle = 0;

  getgames(&mess);
  observeMatrix = [[Matrix alloc] initFrame:&frameRect mode:NX_RADIOMODE
		 cellClass:[ClickCell class] numRows:0 numCols:1];
  [observeMatrix setCellSize:&cellSize];

  for (i = 0; i < mess.gamecount; i++)
    {
      sprintf(str, "%3d -- %12s [%3s] vs. %12s [%3s] (%3d %d %d %3.1f)",
	      mess.gamelist[i].gnum, mess.gamelist[i].white,
	      mess.gamelist[i].wrank, mess.gamelist[i].black,
	      mess.gamelist[i].brank, mess.gamelist[i].mnum,
	      mess.gamelist[i].bsize, mess.gamelist[i].hcap,
	      mess.gamelist[i].komi);
      [observeMatrix addRow];
      observeCell = [observeMatrix cellAt:i :0];
      [observeCell setStringValue:str];
      [observeCell setAlignment:NX_LEFTALIGNED];
    }
  [observeMatrix sizeToCells];

  observeScrollView = [[ScrollView alloc] initFrame:&scrollRect];
  [observeScrollView setVertScrollerRequired:YES];
  [observeScrollView setBorderType:NX_BEZEL];
  [observeScrollView setBackgroundGray:NX_LTGRAY];
  [observeScrollView setDocView:observeMatrix];
  [observeBox addSubview:observeScrollView];
  [observeMatrix scrollCellToVisible:0 :0];
  [observeBox display];

  [observeSelPanel makeKeyAndOrderFront:self];

  [IGSCommand selectText:self];
  idle = 1;

  return self;
}

- cellClicked:theCell
{
  char str[80];
  int n;

  strcpy(str, [theCell stringValue]);
  sscanf(str, "%3d", &n);

  idle = 0;
  observegame(n);
  idle = 1;

  [unobserveMenuCell setEnabled: YES];
  [observeMenuCell setEnabled:NO];
  [loadMenuCell setEnabled:NO];
  [observeSelPanel close];

  return self;
}

- IGSunobserve:sender {
	
	sendstr("unobserve\n");
	[self SetIGSStatus:"Removing observe\n"];
	[unobserveMenuCell setEnabled: NO];
	[observeMenuCell setEnabled:YES];
	[loadMenuCell setEnabled:YES];
	[MainGoView gameCompleted];
	[MainGoView removeTE];
	
	return self;
}

- IGSOpenLoadGame:sender
{
  [LoadGameWindow makeKeyAndOrderFront:self];
  [LoadGameText selectText:self];

  return self;
}

- IGSLoadGame:sender
{
  idle = 0;
  loadgame((char *)[LoadGameText stringValue]);
  idle = 1;

  [LoadGameWindow close];

  return self;
}

- IGSdone:sender {
	
	int q;
	
	q = NXRunAlertPanel("Save", "Save the current game to disk ?", "Save...",
						"Dont't save",0);
	
	if (1==q) 
		[self save:self];
	
	IGSSendString("done\n");
	
	return self;
}

- IGSquit:sender {

	IGSSendString("quit");
	IGSSendString("\n");
	[self IGSunobserve:self];

	DPSRemoveTimedEntry(timer);
  
	[loadMenuCell setEnabled:NO];
	[observeMenuCell setEnabled:NO];
	[unobserveMenuCell setEnabled:NO];
	[MainGoView removeTE];

	gameType = LOCAL;
	[IGSPanel close];

	return self;
}

- sendCommand:sender {
	char buf[256];

	strcpy(buf, [ [sender selectedCell]  title]);
	buf[strlen([ [sender selectedCell]  title])] = '\n';
	buf[strlen([ [sender selectedCell]  title])+1] = '\0';	
	IGSSendString(buf);

	return self;
}

- gameCompleted {
	
	[MainGoView gameCompleted];
	
	return self;
}

- setCommandSender:(id)aSender {
	CommandSender = aSender;
	return self;
}

@end
