/* Class AbTop */

#include <qpopupmenu.h>
#include <qtimer.h>
#include <qclipboard.h>

#include <kapp.h>
#include <kconfig.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kmenubar.h>
#include <kaccel.h>
#include <kstdaccel.h>
#include <kglobal.h>
#include <kstatusbar.h>
#include <kstdaction.h>
#include <kaction.h>
#include <kedittoolbar.h>
#include <kdebug.h>

#include "AbTop.h"
#include "Board.h"
#include "BoardWidget.h"
#include "Network.h"
#include "version.h"

#include <stdio.h>

// #define MYTRACE 1

AbTop::AbTop()
{
  timerState = noGame;

  myPort = Network::defaultPort;
  net = 0;

  moveNo = 0;
  actValue = 0;
  stop = false;
  editMode = false;
  spyLevel = 0;
  pastePossible = true;

  //  loadPixmaps();
  setupActions();

  // this creates the GUI (menu+toolbar) from the XML definition
  createGUI();
  //  setupMenu();
  //  setupToolBar();

  setupStatusBar();

  timer = new QTimer;
  connect( timer, SIGNAL(timeout()), this, SLOT(timerDone()) );

  board = new Board();
  validState = board->validState();

  connect( board, SIGNAL(searchBreak()), this, SLOT(searchBreak()) );

  CHECK_PTR(board);
  boardWidget = new BoardWidget(*board,this);  

#ifdef SPION
  spy = new Spy(*board);
#endif

  connect( boardWidget, SIGNAL(updateSpy(QString)),
	   this, SLOT(updateSpy(QString)) );

  /* Copy/Pase with Mousebuttons in board area (outside)
   * To easy to get rid of your board -> disable (for now?) 
   connect( boardWidget, SIGNAL(mousePressed(int)),
	   this, SLOT(mousePress(int)) );
  */

  connect( boardWidget, SIGNAL(edited(int)),
	   this, SLOT(edited(int)) );

  connect( board, SIGNAL(updateBestMove(Move&,int)),
	   this, SLOT(updateBestMove(Move&,int)) );

  connect( boardWidget, SIGNAL(moveChoosen(Move&)), 
	   this, SLOT(moveChoosen(Move&)) );

  /* default */
  easy();
  play_red();
  showMoveLong = true;
  showSpy = false;
  renderBalls = true;
  
  setView(boardWidget);
  boardWidget->show();

  setMinimumSize(150,200);

  updateStatus();
  updateToolBar();
}

AbTop::~AbTop()
{
  /* Unregister from other abalone processes */
  if (net)
    delete net;

#ifdef SPION
  delete spy;
#endif
}


/**
 * Create all the actions...
 *
 * The GUI will be built in createGUI using a XML file
 *
 */

void AbTop::setupActions()
{
  (void) new KAction( i18n("&New"), "new", 
		      KStdAccel::key(KStdAccel::New), this,
		      SLOT(newGame()), actionCollection(), "game_new");

  (void) new KAction( i18n("&Stop Search"), "stop", Key_S, this,
		      SLOT(stopSearch()), actionCollection(), "game_stop");

  (void) new KAction( i18n("Take &Back"), "back",
		      KStdAccel::key(KStdAccel::Prior), this,
		      SLOT(back()), actionCollection(), "game_back");

  (void) new KAction( i18n("&Forward"), "forward",
		      KStdAccel::key(KStdAccel::Next), this,
		      SLOT(forward()), actionCollection(), "game_forward");

  (void) new KAction( i18n("&Hint"), "hint", Key_H, this,
		      SLOT(suggestion()), actionCollection(), "game_hint");

  (void) new KAction( i18n("&Quit"), "exit",
		      KStdAccel::key(KStdAccel::Quit), this,
		      SLOT(quit()), actionCollection(), "game_quit");

  KStdAction::copy( this, SLOT(copy()), actionCollection());
  KStdAction::paste( this, SLOT(paste()), actionCollection());

  (void) new KAction( i18n("&Restore Position"),
		      KStdAccel::key(KStdAccel::Open), 
		      this, SLOT(restorePosition()), 
		      actionCollection(), "edit_restore" );

  (void) new KAction( i18n("&Save Position"),
		      KStdAccel::key(KStdAccel::Save), 
		      this, SLOT(savePosition()), 
		      actionCollection(), "edit_save" );

  KToggleAction *ta;

  ta = new KToggleAction( i18n("&Network Play"), "net", Key_N,
			  actionCollection(), "game_net");
  connect(ta, SIGNAL(toggled(bool)), this, SLOT(gameNetwork(bool)));

  ta = new KToggleAction( i18n("&Modify"), "edit",
			  KStdAccel::key(KStdAccel::Insert), 
			  actionCollection(), "edit_modify");
  connect(ta, SIGNAL(toggled(bool)), this, SLOT( editModify(bool)));   

  ta = KStdAction::showToolbar( this, SLOT(dummySlot()), actionCollection());
  connect(ta, SIGNAL(toggled(bool)), this, SLOT(showToolbar(bool)));

  ta =  new KToggleAction( i18n("&Move Slow"), 0,
			   actionCollection(), "option_moveSlow");
  connect(ta, SIGNAL(toggled(bool)), this, SLOT(optionMoveSlow(bool)));

  ta =  new KToggleAction( i18n("&Render Balls"), 0,
			   actionCollection(), "option_renderBalls");
  connect(ta, SIGNAL(toggled(bool)), this, SLOT(optionRenderBalls(bool)));

  ta =  new KToggleAction( i18n("&Spy"), 0,
			   actionCollection(), "option_showSpy");
  connect(ta, SIGNAL(toggled(bool)), this, SLOT(optionShowSpy(bool)));

  KStdAction::configureToolbars(this,SLOT(configureToolbars()),
				actionCollection());

  KStdAction::saveOptions( this, SLOT(writeConfig()), actionCollection());

  KRadioAction *ra;

  ra =  new KRadioAction( i18n("&Easy"), 0,
			  actionCollection(), "level_easy");
  ra->setExclusiveGroup( "Level" );
  ra->setChecked( false );
  connect(ra, SIGNAL(toggled(bool)), this, SLOT(levelEasy(bool)));

  ra =  new KRadioAction( i18n("&Normal"), 0,
			  actionCollection(), "level_normal");
  ra->setExclusiveGroup( "Level" );
  ra->setChecked( true );
  connect(ra, SIGNAL(toggled(bool)), this, SLOT(levelNormal(bool)));

  ra =  new KRadioAction( i18n("&Hard"), 0,
			  actionCollection(), "level_hard");
  ra->setExclusiveGroup( "Level" );
  ra->setChecked( false );
  connect(ra, SIGNAL(toggled(bool)), this, SLOT(levelNormal(bool)));

  ra =  new KRadioAction( i18n("&Challange"), 0,
			  actionCollection(), "level_challange");
  ra->setExclusiveGroup( "Level" );
  ra->setChecked( false );
  connect(ra, SIGNAL(toggled(bool)), this, SLOT(levelChallange(bool)));

  ra =  new KRadioAction( i18n("&Red"), 0,
			  actionCollection(), "iplay_red");
  ra->setExclusiveGroup( "IPlay" );
  ra->setChecked( true );
  connect(ra, SIGNAL(toggled(bool)), this, SLOT(iplayRed(bool)));

  ra =  new KRadioAction( i18n("&Yellow"), 0,
			  actionCollection(), "iplay_yellow");
  ra->setExclusiveGroup( "IPlay" );
  ra->setChecked( false );
  connect(ra, SIGNAL(toggled(bool)), this, SLOT(iplayYellow(bool)));

  ra =  new KRadioAction( i18n("&Both"), 0,
			  actionCollection(), "iplay_both");
  ra->setExclusiveGroup( "IPlay" );
  ra->setChecked( false );
  connect(ra, SIGNAL(toggled(bool)), this, SLOT(iplayBoth(bool)));

  ra =  new KRadioAction( i18n("&None"), 0,
			  actionCollection(), "iplay_none");
  ra->setExclusiveGroup( "IPlay" );
  ra->setChecked( false );
  connect(ra, SIGNAL(toggled(bool)), this, SLOT(iplayNone(bool)));
}


void AbTop::showToolbar(bool on)
{
  toolBar()->enable( on ? KToolBar::Show : KToolBar::Hide );
}          

void AbTop::configureToolbars()
{
  KEditToolbar dlg(actionCollection());
  if (dlg.exec())
    createGUI();
}
  


/* Mouse button pressed in Board area,
 *  but outside of any board position
 */
void AbTop::mousePress(int b)
{
  if (b==QWidget::MidButton) 
    paste();
  else
    copy();
}

/* Read config options
 *
 * menu must already be created!
 */
void AbTop::readConfig()
{
  KConfig* config = kapp->config();
  config->setGroup("Options");
	
  readOptions(config);

  config->setGroup("Appearance");
  int x=215, y=280;
  QString entry;
  if (!(entry = config->readEntry("Geometry")).isNull())
	  sscanf(entry.ascii(),"%dx%d",&x,&y);
  resize(x,y);
  config->setGroup("Rating");
  board->readRating(config);
}

void AbTop::readOptions(KConfig* config)
{	
  QString entry;
  if (!(entry = config->readEntry("Level")).isNull()) {
    if (entry == "Easy")  easy();
    else if (entry == "Normal") normal();
    else if (entry == "Hard") hard();
    else if (entry == "Challange") challange();
  }

  if (!(entry = config->readEntry("Computer")).isNull()) {
    if (entry == "Red") play_red();
    else if (entry == "Yellow") play_yellow();
    else if (entry == "Both") play_both();
    else if (entry == "None") play_none();
  }

  showMoveLong = false; // default
  if (!(entry = config->readEntry("MoveSlow")).isNull()) 
    showMoveLong = (entry == "Yes");
  ((KToggleAction*) actionCollection()->action("option_moveSlow"))
    ->setChecked( showMoveLong );

  renderBalls = true; // default  
  if (!(entry = config->readEntry("RenderBalls")).isNull()) 
    renderBalls = (entry == "Yes");
  boardWidget->renderBalls(renderBalls);
  ((KToggleAction*) actionCollection()->action("option_renderBalls"))
    ->setChecked( renderBalls );

  showSpy = true; // default
  if (!(entry = config->readEntry("ShowSpy")).isNull()) 
    showSpy = (entry == "Yes");
  board->updateSpy(showSpy);
  ((KToggleAction*) actionCollection()->action("option_showSpy"))
    ->setChecked( showSpy );
}

void AbTop::readProperties(KConfig *config)
{
  QString entry;
	
  readOptions(config);
  board->readRating(config);
	
  if (!(entry = config->readEntry("TimerState")).isNull())
    timerState = entry.toInt();
  if (timerState == noGame) return;

  if (!(entry = config->readEntry("GameStopped")).isNull())  
    stop = (entry == "Yes");

  moveNo = 0;
  if (!(entry = config->readEntry("Position")).isNull()) {
    moveNo = board->setState(entry);
    boardWidget->copyPosition();
    boardWidget->draw();
  }
  updateStatus();
  updateToolBar();
  show();
  playGame();
}

void AbTop::writeConfig()
{
  KConfig* config = kapp->config();
  config->setGroup("Options");

  writeOptions(config);

  QString entry;
  config->setGroup("Appearance");
  config->writeEntry("Geometry", entry.sprintf("%dx%d",width(),height()) );
  config->setGroup("Rating");
  board->saveRating(config);
  config->sync();
}


void AbTop::writeOptions(KConfig *config)
{
  QString entry;

  if (((KRadioAction*) actionCollection()->action("level_easy"))
      ->isChecked()) {
    entry = "Easy";
  }
  else if (((KRadioAction*) actionCollection()->action("level_normal"))
	   ->isChecked()) {
    entry = "Normal";
  }
  else if (((KRadioAction*) actionCollection()->action("level_hard"))
	   ->isChecked()) {
    entry = "Hard";
  }
  else
    entry = "Challange";

  config->writeEntry("Level",entry);

  if (((KRadioAction*) actionCollection()->action("iplay_red"))
      ->isChecked()) {
    entry = "Red";
  }
  else if (((KRadioAction*) actionCollection()->action("iplay_yellow"))
	   ->isChecked()) {
    entry = "Yellow";
  }
  else if (((KRadioAction*) actionCollection()->action("iplay_both"))
	   ->isChecked()) {
    entry = "Both";
  }
  else
    entry = "None";

  config->writeEntry("Computer",entry);

  entry = showMoveLong ? "Yes" : "No";
  config->writeEntry("MoveSlow",entry);

  entry = renderBalls ? "Yes" : "No";
  config->writeEntry("RenderBalls",entry);
	
  entry = showSpy ? "Yes" : "No";
  config->writeEntry("ShowSpy",entry);
}

void AbTop::saveProperties(KConfig *config)
{
  QString entry;
  
  writeOptions(config);
  board->saveRating(config);
	
  config->writeEntry("TimerState",entry.setNum(timerState));

  if (timerState == noGame) return;

  config->writeEntry("GameStopped", stop ? "Yes":"No");
  config->writeEntry("Position", board->getState(moveNo));
}

void AbTop::closeEvent(QCloseEvent *)
{
  quit();
}

void AbTop::savePosition()
{
  KConfig* config = kapp->config();
  config->setGroup("SavedPosition");
  config->writeEntry("Position", board->getState(moveNo));
}

void AbTop::restorePosition()
{
  KConfig* config = kapp->config();
  config->setGroup("SavedPosition");
  QString  entry = config->readEntry("Position");
  
  timerState = notStarted;
  timer->stop();	
  board->begin(Board::color1);
  stop = false;
  moveNo = board->setState(entry);

  if (net)
    net->broadcast( board->getASCIIState( moveNo ) );

  boardWidget->copyPosition();
  boardWidget->draw();
  updateStatus();
  updateToolBar();  
  playGame();
}

void AbTop::setupStatusBar()
{
  QString tmp;
  status = new KStatusBar(this);

  // validPixmap, only visible in Modify mode: is position valid ?
  warningPix = BarIcon( "warning" );
  okPix = BarIcon( "ok" );
  validLabel = new QLabel( "", status );
  validLabel->setFixedSize( 18,18 );
  validLabel->setAlignment( AlignCenter );
  validLabel->hide();
  validShown = false;

  QString t = i18n("Press %1 for a new game")
    .arg( KAccel::keyToString(KStdAccel::key(KStdAccel::New)) );
  statusLabel = new QLabel( t, status );
  status->addWidget(statusLabel,1);

  // PERMANENT: Moving side + move No.
  redBall = BarIcon( "redball" );
  yellowBall = BarIcon( "yellowball" );
  noBall = BarIcon( "noball" );  
  ballLabel = new QLabel( "", status );
  ballLabel->setPixmap(noBall);
  ballLabel->setFixedSize( 18,18 );
  ballLabel->setAlignment( AlignCenter );
  status->addWidget(ballLabel, 0, true);

  moveLabel = new QLabel( i18n("Move %1").arg("--"), status );
  status->addWidget(moveLabel, 0, true);

  setStatusBar(status);
}


#if 0
void AbTop::setupToolBar()
{
  toolbar = new KToolBar(this);
  
  toolbar->insertButton(newPix, 0, SIGNAL( clicked() ),
			this, SLOT( newGame() ),
			TRUE, i18n("New Game"));
  
  toolbar->insertSeparator();
  
  toolbar->insertButton(editPix, 12, SIGNAL( toggled(int) ),
			this, SLOT( editToggled(int) ),
			TRUE, i18n("Modify"));
  toolbar->setToggle(12);
  
  toolbar->insertButton(copyPix, 10, SIGNAL( clicked() ),
			this, SLOT( copy() ),
			TRUE, i18n("Copy"));
  
  toolbar->insertButton(pastePix, 11, SIGNAL( clicked() ),
			this, SLOT( paste() ),
			TRUE, i18n("Paste"));
  
  toolbar->insertSeparator();
  
  toolbar->insertButton(stopPix, 20, SIGNAL( clicked() ),
			this, SLOT( stopSearch() ),
			TRUE, i18n("Stop Search"));
  
  toolbar->insertButton(backPix, 21, SIGNAL( clicked() ),
			this, SLOT( back() ),
			TRUE, i18n("Back"));
  
  toolbar->insertButton(forwardPix, 22, SIGNAL( clicked() ),
			this, SLOT( forward() ),
			TRUE, i18n("Forward"));
  
  toolbar->insertButton(hintPix, 23, SIGNAL( clicked() ),
			this, SLOT( suggestion() ),
			TRUE, i18n("Hint"));

  toolbar->insertSeparator();
  
  toolbar->insertButton(netPix, 24, SIGNAL( toggled(int) ),
			this, SLOT( netToggled(int) ),
			TRUE, i18n("Network Play"));
  toolbar->setToggle(24);
  
#ifdef MYTRACE	
  QPopupMenu* spyPopup = new QPopupMenu;
  spy0 = BarIcon( "spy0" );
  spy1 = BarIcon( "spy1" );
  spy2 = BarIcon( "spy2" );
  spy3 = BarIcon( "spy3" );
  spyPopup->insertItem(spy0, 0);
  spyPopup->insertItem(spy1, 1);
  spyPopup->insertItem(spy2, 2);
  spyPopup->insertItem(spy3, 3);	
  connect( spyPopup, SIGNAL(activated(int)), 
	   this, SLOT(setSpy(int)) );
  toolbar->insertButton(spy0, 30, spyPopup,
			TRUE, i18n("Spy"));
#endif
  toolbar->show();	
  addToolBar(toolbar);	
}


void AbTop::setupMenu()
{
  KMenuBar* menu;

  _file = new QPopupMenu;
  CHECK_PTR( _file );
  _file->insertItem( newPix, i18n("New Game"), 
		   this, SLOT(newGame()), Key_F2 );
  _file->insertSeparator();

  stop_id = _file->insertItem( stopPix, i18n("Stop Search"),
			     this, SLOT(stopSearch()), Key_S );
  //  file->insertItem( "Stop", this, SLOT(stopGame()) );
  //  file->insertItem( "Continue", this, SLOT(continueGame()) );
  back_id = _file->insertItem( backPix, i18n("Take back"),
				 this, SLOT(back()), KStdAccel::key(KStdAccel::Prior) );
  forward_id = _file->insertItem( forwardPix, i18n("Forward"),
				 this, SLOT(forward()), KStdAccel::key(KStdAccel::Next) );

  hint_id = _file->insertItem( hintPix, i18n("Hint"),
			     this, SLOT(suggestion()), Key_H );

  _file->insertSeparator();

  net_id = _file->insertItem( netPix, i18n("Network"),
		         this, SLOT(toggleNet()), Key_N );
  _file->setCheckable( TRUE );
  
  _file->insertSeparator();
  _file->insertItem( i18n("&Quit"), 
				 this, SLOT(quit()), KStdAccel::key(KStdAccel::Quit) );


  _edit = new QPopupMenu;
  CHECK_PTR( _edit );

  edit_id = _edit->insertItem( editPix, i18n("Modify"), 
				  this, SLOT(toggleEdit()), KStdAccel::key(KStdAccel::Insert) );
  _edit->setCheckable( TRUE );

  _edit->insertItem( copyPix, i18n("Copy"), 
				this, SLOT(copy()), KStdAccel::key(KStdAccel::Copy) );
  paste_id = _edit->insertItem( pastePix, i18n("Paste"), 
			    this, SLOT(paste()), KStdAccel::key(KStdAccel::Paste) );

  _edit->insertSeparator();

  _edit->insertItem( i18n("Restore Position"), 
			this, SLOT(restorePosition()), KStdAccel::key(KStdAccel::Open) );
  _edit->insertItem( i18n("Save Position"), 
			this, SLOT(savePosition()), KStdAccel::key(KStdAccel::Save) );


  _level = new QPopupMenu;
  CHECK_PTR( _level );
  easy_id = _level->insertItem( i18n("Easy"),
			       this, SLOT(easy()) );
  normal_id = _level->insertItem( i18n("Normal"),
				 this, SLOT(normal()) );
  hard_id = _level->insertItem( i18n("Hard"),
			       this, SLOT(hard()) );
  challange_id = _level->insertItem( i18n("Challange"),
				    this, SLOT(challange()) );
  _level->setCheckable( TRUE );

  _iplay = new QPopupMenu;
  CHECK_PTR( _iplay );
  red_id = _iplay->insertItem( i18n("Red"),
			      this, SLOT(play_red()) );
  yellow_id = _iplay->insertItem( i18n("Yellow"),
				 this, SLOT(play_yellow()) );
  both_id = _iplay->insertItem( i18n("Both"), 
			       this, SLOT(play_both()) );
  none_id = _iplay->insertItem( i18n("None"), 
			       this, SLOT(play_none()) );
  _iplay->setCheckable( TRUE );

  _options = new QPopupMenu;
  CHECK_PTR( _options );
  _options->insertItem( i18n("Level"), _level );
  _options->insertItem( i18n("Computer plays"), _iplay );
  _options->insertSeparator();
  slow_id = _options->insertItem( i18n("Move slow"),
				  this, SLOT(changeShowMove()) );
  render_id = _options->insertItem( i18n("Render balls"),
				  this, SLOT(toggleRender()) );
  spy_id = _options->insertItem( i18n("Spy"),
				  this, SLOT(toggleSpy()) );
  _options->insertSeparator();
  _options->insertItem( i18n("Save"),
				  this, SLOT(writeConfig()) );	
  _options->setCheckable( TRUE );

  QPopupMenu *help = helpMenu(QString(i18n("Abalone"))
                                    + " " + KABALONE_VERSION
                                    + i18n("\n\nby Josef Weidendorfer")
                                    + " (Josef.Weidendorfer@in.tum.de)"); 

  menu  = new KMenuBar(this);
  CHECK_PTR( menu );
  menu->insertItem( i18n("&File"), _file);
  menu->insertItem( i18n("&Edit"), _edit);
  menu->insertItem( i18n("&Options"), _options);
  menu->insertSeparator();
  menu->insertItem( i18n("&Help"), help);
  menu->show();

  setMenu(menu);
}
#endif // replaced with createGUI()


void AbTop::updateSpy(QString s)
{
  if (showSpy) {
    if (s.isEmpty()) {      
      updateStatus();
      //      status->clear();
    }
    else
      statusLabel->setText(s);
  }
}

void AbTop::updateBestMove(Move& m, int value)
{
  if (showSpy) {
    board->showMove(m,3);
    boardWidget->copyPosition();
    boardWidget->draw();
    board->showMove(m,0);

    QString tmp;
    tmp.sprintf("%s : %+d", (const char*) m.name(), value-actValue);
    updateSpy(tmp);
    kapp->processEvents();
  }
}


void AbTop::updateStatus()
{
  QString tmp;
  bool showValid = false;

  if (!editMode && timerState == noGame) {
    tmp = i18n("Move %1").arg("--");
    ballLabel->setPixmap(noBall);
  }
  else {
    tmp = i18n("Move %1").arg(moveNo/2 + 1);
    ballLabel->setPixmap( ((moveNo%2)==0) ? redBall : yellowBall);
  }
  moveLabel->setText(tmp);

  if (editMode) {
    tmp = QString("%1: %2 %3 - %4 %5")
      .arg( i18n("Edit") )
      .arg( i18n("Red") ).arg(boardWidget->getColor1Count())
      .arg( i18n("Yellow") ).arg(boardWidget->getColor2Count());
    validLabel->setPixmap( (validState == Board::invalid) ? warningPix:okPix );
    showValid = true;
  }
  else if (timerState == noGame) {
    tmp = i18n("Press %1 for a new game")
      .arg( KAccel::keyToString(KStdAccel::key(KStdAccel::New)) );
  }
  else {
    if (timerState == gameOver) {
      tmp = QString("%1 %2 !")
	.arg( (board->actColor() == Board::color2) ? 
	      i18n("Red"):i18n("Yellow"))
	.arg( i18n("won") );
      validLabel->setPixmap( warningPix );
      showValid = true;
    }
    else {
      tmp = QString("%1 - %2")
	.arg( (board->actColor() == Board::color1) ? 
	      i18n("Red"):i18n("Yellow") )
	.arg( iPlayNow() ?
	      i18n("I am thinking...") : i18n("It's your turn !") );
    }
  }
  statusLabel->setText(tmp);
  if (validShown != showValid) {
    if (showValid) {
      status->addWidget(validLabel);
      validLabel->show();
    }
    else {
      status->removeWidget(validLabel);
      validLabel->hide();
    }
    validShown = showValid;
  }
  status->clear();
  status->repaint();
}

void AbTop::edited(int vState)
{
  validState = vState;
  if (validState == Board::empty)
    timerState = noGame;

  updateStatus();
}

/* only <stop search>, <hint>, <take back> have to be updated */
void AbTop::updateToolBar()
{
  bool iPlay = iPlayNow();

  /* New && Copy always on */

  /* Paste */
  pastePossible = !iPlay;
  ((KAction*)actionCollection()->action("edit_paste"))->setEnabled(!iPlay);
  
  /* Edit */
  ((KAction*)actionCollection()->action("edit_modify"))->setEnabled(!iPlay);

  /* Stop search */
  ((KAction*)actionCollection()->action("game_stop"))->setEnabled(iPlay);

  /* Back */
  bool bBack = (editMode && moveNo>0) || 
    (board->movesStored() >=2 && !iPlay);
  ((KAction*)actionCollection()->action("game_back"))->setEnabled(bBack);
	
  /* Forward */
  bool bForward = editMode && moveNo<999;
  ((KAction*)actionCollection()->action("game_forward"))->setEnabled(bForward);

  /* Hint */
  bool bHint = !editMode && !iPlay && (haveHint().type != Move::none);
  ((KAction*)actionCollection()->action("game_hint"))->setEnabled(bHint);
}

/* let the program be responsive even in a long search... */
void AbTop::searchBreak()
{
  kapp->processEvents();
}


void AbTop::setSpy(int id)
{
  toolbar->setButtonPixmap(30, (id==0)?spy0:(id==1)?spy1:(id==2)?spy2:spy3 );
  spyLevel = id;
  board->setSpyLevel(spyLevel);
}

void AbTop::timerDone()
{
  int interval = 400;

  switch(timerState) {
  case noGame:
  case notStarted:
    return;
  case showMove:
  case showMove+2:
  case showSugg:
  case showSugg+2:
  case showSugg+4:
    board->showMove(actMove, 2);
    interval = 200;
    break;
  case showMove+1:
  case showMove+3:
  case showSugg+1:
  case showSugg+3:
    board->showMove(actMove, 3);
    break;
  case showSugg+5:
    interval = 800;
  case showMove+4:
    board->showMove(actMove, 4);
    break;
  case showMove+5:
    board->showMove(actMove, 0);
    timerState = moveShown;
    playGame();
    return;
  case showSugg+6:
    board->showMove(actMove, 0);
    timerState = notStarted;
    boardWidget->copyPosition();
    boardWidget->draw();
    return;
  }
  boardWidget->copyPosition();
  boardWidget->draw();
  timerState++;
  timer->start(interval,TRUE);
}

void AbTop::userMove()
{
    /* User has to move */
    static MoveList list;
    
    list.clear();
    board->generateMoves(list);
    boardWidget->choseMove(&list);
}

bool AbTop::iPlayNow()
{
  if (editMode ||
      validState != Board::valid ||
      timerState == gameOver)
    return false;

  int c = board->actColor();
    
  /* color1 is red */
  return ((iplay == cBoth) || 
	  ((c == Board::color1) && (iplay == cRed) ) ||
	  ((c == Board::color2) && (iplay == cYellow) ));
}

void AbTop::playGame()
{
  if (timerState == moveShown) {
    if (actMove.type != Move::none) {
      board->playMove(actMove);
      moveNo++;

      if (net)
	net->broadcast( board->getASCIIState( moveNo ) );
    }
    actValue = - board->calcValue();
    boardWidget->copyPosition();
    boardWidget->draw();
    timerState = notStarted;
  }
  if (!board->isValid()) { 
    stop = true;
    timerState = gameOver;
  }

  updateStatus();
  updateToolBar();
  if (stop) return;


  if (!iPlayNow()) {
    userMove();
    return;
  }
	
  kapp->processEvents();

  if (moveNo <4) {
    /* Chose a random move making the position better for actual color */

    /* If comparing ratings among color1/2 on move, we have to negate one */
    int v = -board->calcValue(), vv;
    do {
      actMove = board->randomMove();
      board->playMove(actMove);
      vv = board->calcValue();
      board->takeBack();
    } while( (board->actColor() == Board::color1) ? (vv<v) : (vv>v) );
  }
  else
    actMove = (board->bestMove());

  timerState = showMoveLong ? showMove : showMove+3;
  timerDone();
}

void AbTop::moveChoosen(Move& m)
{
  actMove = m;
  timerState = moveShown;
  playGame();
}

void AbTop::newGame()
{
  /* stop a running animation */
  timerState = notStarted;
  timer->stop();	

  /* reset board */
  board->begin(Board::color1);
  boardWidget->copyPosition();
  boardWidget->draw();
  moveNo = 0;
  validState = board->validState();

  if (net)
    net->broadcast( board->getASCIIState( moveNo ) );

  updateStatus();
  updateToolBar();

  /* if not in EditMode, start Game immediately */
  if (!editMode) {
    stop = false;	
    playGame();
  }
}

/* Copy ASCII representation into Clipboard */
void AbTop::copy()
{
  QClipboard *cb = QApplication::clipboard();
  cb->setText( board->getASCIIState( moveNo ) );
}

void AbTop::paste()
{
  if (!pastePossible) return;

  QClipboard *cb = QApplication::clipboard();
  pastePosition( cb->text() );
  /* don't do this in pastePosition: RECURSION !! */

  if (net)
    net->broadcast( board->getASCIIState( moveNo ) );
}

void AbTop::pastePosition(const char* text)
{
  if (!pastePossible) return;
  if ( text ) {
    timerState = notStarted;
    timer->stop();	
    board->begin(Board::color1);
    stop = false;

    int no = board->setASCIIState(text);
    moveNo = (no>=0) ? no : 0;
    board->setActColor( ((moveNo%2)==0) ? Board::color1 : Board::color2 );

    validState = board->validState();    
    boardWidget->copyPosition();
    validState = boardWidget->validState();    
    boardWidget->draw();

    if (validState==Board::invalid && !editMode) {
      toolbar->toggleButton(12);
      return;
    }
    updateStatus();
    updateToolBar();  
    playGame();
  }
}


void AbTop::gameNetwork(bool on)
{
  if (!on) {
    if (net != 0) {
      delete net;
      net = 0;
    }
    return;
  }

  if (myPort == 0) myPort = Network::defaultPort;
  net = new Network(myPort);
  char *h, h2[100];
  int p, i;
  for(h = hosts.first(); h!=0; h=hosts.next()) {
    for(i=0;h[i]!=0 && h[i]!=':';i++);
    if (h[i]==':')
      p = atoi(h+i+1);
    else
      p = 0;

    if (p == 0) p = Network::defaultPort;
    strncpy(h2,h,i);
    h2[i]=0;
    net->addListener(h2, p);
  }
  QObject::connect(net, SIGNAL(gotPosition(const char*)),
		   this, SLOT(pastePosition(const char*)) );
}
  

void AbTop::editModify(bool on)
{
  editMode = boardWidget->setEditMode( on );
  validState = boardWidget->validState();

  if (validState != Board::valid)
    timerState = noGame;

  updateToolBar();
  updateStatus();
  if (!editMode && validState == Board::valid) {
    board->setActColor( ((moveNo%2)==0) ? Board::color1 : Board::color2 );
    actMove.type = Move::none;
    timerState = moveShown;
    playGame();
  }  
}

void AbTop::stopGame()
{
  stop = true;
  board->stopSearch();
}

void AbTop::stopSearch()
{
  // When computer plays both, switch back to human for next color
  if (iplay == cBoth)
    iplay = (board->actColor() == Board::color1) ? cRed:cYellow;

  board->stopSearch();
}

void AbTop::quit()
{
  board->stopSearch();
  kapp->quit();
}

void AbTop::continueGame()
{
  if (timerState != noGame && timerState != gameOver) {
    stop = false;
    if (timerState == notStarted)
	    playGame();
  }
}

void AbTop::back()
{
  if (editMode) {
    if (moveNo > 0) moveNo--;
    updateStatus();
    updateToolBar();
    return;
  }

  if (moveNo < 2) return;

  if (timerState == gameOver)
    timerState = notStarted;
  if (timerState != notStarted) return;

  board->takeBack();
  board->takeBack();
  boardWidget->copyPosition();
  boardWidget->draw();
  moveNo -=2;
  updateStatus();
  updateToolBar();
  userMove();
}

/* Only for edit Mode */
void AbTop::forward()
{
  if (editMode) {
    if (moveNo < 999) moveNo++;
    updateStatus();
    updateToolBar();
    return;
  }
}

Move AbTop::haveHint()
{
  static Move m;
  static int oldMoveNo = 0;

  if (timerState != notStarted) {
    m.type = Move::none;
  }
  else if (moveNo != oldMoveNo) {
    MoveList list;
    
    oldMoveNo = moveNo;
    m = board->nextMove();
    board->generateMoves(list);
    if (!list.isElement(m,0))
      m.type = Move::none;
  }
  return m;
}


void AbTop::suggestion()
{
  if (timerState != notStarted) return;
  Move m = haveHint();
  if (m.type == Move::none) return;

  actMove = m;

  timerState = showSugg;
  timerDone();
}

void AbTop::setLevel(int d)
{
  depth = d;
  board->setDepth(depth);
  //  qDebug("Level set to %d",d);
}

void AbTop::levelEasy(bool on)      { if (on) setLevel(2); }
void AbTop::levelNormal(bool on)    { if (on) setLevel(3); }
void AbTop::levelHard(bool on)      { if (on) setLevel(4); }
void AbTop::levelChallange(bool on) { if (on) setLevel(5); }

void AbTop::easy()
{  
  ((KRadioAction*) actionCollection()->action("level_easy"))
    ->setChecked( true );
}

void AbTop::normal()
{  
  ((KRadioAction*) actionCollection()->action("level_normal"))
    ->setChecked( true );
}

void AbTop::hard()
{  
  ((KRadioAction*) actionCollection()->action("level_hard"))
    ->setChecked( true );
}

void AbTop::challange()
{  
  ((KRadioAction*) actionCollection()->action("level_challange"))
    ->setChecked( true );
}

void AbTop::setIplay(int v)
{
  iplay = v;
  continueGame();
}

void AbTop::iplayRed(bool on)    { if (on) setIplay(cRed); }
void AbTop::iplayYellow(bool on) { if (on) setIplay(cYellow); }
void AbTop::iplayBoth(bool on)   { if (on) setIplay(cBoth); }
void AbTop::iplayNone(bool on)   { if (on) setIplay(cNone); }

void AbTop::play_red()
{
  ((KRadioAction*) actionCollection()->action("iplay_red"))
    ->setChecked( true );
}

void AbTop::play_yellow()
{
  ((KRadioAction*) actionCollection()->action("iplay_yellow"))
    ->setChecked( true );
}

void AbTop::play_both()
{
  ((KRadioAction*) actionCollection()->action("iplay_both"))
    ->setChecked( true );
}

void AbTop::play_none()
{
  ((KRadioAction*) actionCollection()->action("iplay_none"))
    ->setChecked( true );
}

void AbTop::optionMoveSlow(bool on)
{
  showMoveLong = on;
}

void AbTop::optionRenderBalls(bool on)
{
  renderBalls = on;
  boardWidget->renderBalls(renderBalls);
}

void AbTop::optionShowSpy(bool on)
{
  showSpy = on;
  board->updateSpy(showSpy);

#ifdef SPION
  if (showSpy)
    spy->show();
  else {
    spy->nextStep();
    spy->hide();
  }
#endif

}


void AbTop::help()
{
  kapp->invokeHelp();
}



