/**********************************************************************
 *
 *   FreeDoko a Doppelkopf-Game
 *
 *   Copyright (C) 2001-2006  by Diether Knof and Borg Enders
 *
 *   This program 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 of
 *   the License, or (at your option) any later version.
 *
 *   This program 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 can find this license in the file 'gpl.txt'.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *   MA  02111-1307  USA
 *
 *  Contact:
 *    Diether Knof dknof@gmx.de
 *    Borg Enders  borg@borgsoft.de
 *
 *********************************************************************/

#include "constants.h"

#include "ui.h"

#ifndef POSTPHONED
#ifndef RELEASE
#include <unistd.h>
#endif
#endif

#include "ui.dummy.h"
#ifdef USE_UI_TEXT
#include "text/ui.h"
#endif // #ifdef USE_UI_TEXT
#ifdef USE_UI_GTKMM
#include "gtkmm/ui.h"
#endif // #ifdef USE_UI_GTKMM

#include "../card/hand.h"
#include "../misc/setting.h"
#include "../misc/translations.h"
#include "../misc/bug_report.h"
#include "../os/bug_report_replay.h"

using namespace UI_TYPE;


/**
 **
 ** Constructor
 ** (to be called from a child class)
 **
 ** @param	type	the UIType
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
UI::UI(UIType const type) :
type_(type),
  party_(NULL),
  game_(NULL),
  trick_(NULL),
  status_message_(),
  busy_(false),
  progress_(0),
  progress_max_(0)
{ return ; }

#ifdef OUTDATED
/**
 **
 ** Constructor
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
UI::UI() :
type_(UI_TYPE::NONE),
  party_(NULL),
  game_(NULL),
  trick_(NULL),
  status_message_(),
  busy_(false),
  progress_(0),
  progress_max_(0)
{ return ; }

/**
 **
 ** Constructor
 **
 ** @param	ui	the UI
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
UI::UI(UI const& ui) :
type_(ui.type_),
  party_(ui.party_),
  game_(ui.game_),
  trick_(ui.trick_),
  status_message_(ui.status_message_),
  busy_(ui.busy_),
  progress_(ui.progress_),
  progress_max_(ui.progress_max_)
{ return ; }

/**
 **
 ** copy operator
 **
 ** @param	ui	the UI
 **
 ** @return	the ui
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
UI&
UI::operator=(UI const& ui)
{
  this->type_ = ui.type_;
  this->status_message_ = ui.status_message_;
  this->progress_ = ui.progress_;
  this->progress_max_ = ui.progress_max_;
  this->busy_ = ui.busy_;

  return *this;
}
#endif

/**
 **
 ** Destructor
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
UI::~UI()
{ return ; }

/**
 **
 ** create a new ui
 ** (it should just call the new-operator of the child class)
 **
 ** @param	type	type of the UI to create
 **
 ** @return	pointer of UI
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
UI*
UI::new_(UIType const type)
{
  UI* ui;

  switch (type) {
  case DUMMY:
    ui = new UI_Dummy;
    break;
#ifdef USE_UI_TEXT
  case TEXT:
    ui = new UI_Text;
    break;
#endif // #ifdef USE_UI_TEXT
#ifdef USE_UI_GTKMM
  case GTKMM_DOKO:
    ui = new UI_GTKMM_NS::UI_GTKMM;
    break;
#endif // #ifdef USE_UI_GTKMM
  default:
    ui = NULL;
  } // switch(type)

  return ui;
} // static UI* UI::new_(UIType const type)


/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the party
 **
 ** @version	0.6.8
 **
 ** @author	Diether Knof
 **
 **/
Party&
UI::party()
{
  return *this->party_;
}

/**
 **
 ** the party is opened
 **
 ** @param	party	party that is opened
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
UI::party_open(Party& party)
{
  DEBUG_ASSERTION(!this->party_,
		  "UI::party_open(party):\n"
		  "  party already set");
  this->party_ = &party;
  return ;
}

/**
 **
 ** the party will close
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
UI::party_close()
{
  this->party_ = NULL;
  return ;
}

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the game
 **
 ** @version	0.6.8
 **
 ** @author	Diether Knof
 **
 **/
Game&
UI::game()
{
  return *this->game_;
}

/**
 **
 ** a game is opened
 **
 ** @param	game	game that is opened
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
UI::game_open(Game& game)
{
  DEBUG_ASSERTION(!this->game_,
		  "UI::game_open(game):\n"
		  "  game already set");
  this->game_ = &game;
  return ;
}

/**
 **
 ** the game will close
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
UI::game_close()
{
  this->game_ = NULL;
  return ;
}

/**
 **
 ** a new trick is opened
 **
 ** @param	trick	trick that is opened
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
UI::trick_open(Trick const& trick)
{
  DEBUG_ASSERTION(!this->trick_,
		  "UI::trick_open(trick):\n"
		  "  trick already set");
  this->trick_ = &trick;
  return ;
}

/**
 **
 ** the trick is closed
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
UI::trick_close()
{
  this->trick_ = NULL;
  return ;
}

/**
 **
 ** a bug report replay is opened
 **
 ** @param	bug_report_replay	bug report replay that is opened
 **
 ** @return	-
 **
 ** @version	0.6.8
 **
 ** @author	Diether Knof
 **
 **/
void
UI::bug_report_replay_open(OS_NS::BugReportReplay const& bug_report_replay)
{
#ifdef OUTDATED
  // When a bug report is opened via dnd, a new party is started.
  DEBUG_ASSERTION(!this->game_,
		  "UI::bug_report_replay_open(bug_report_replay):\n"
		  "  'bug_report_replay' already set");
#endif
  this->bug_report_replay_ = &bug_report_replay;
  return ;
}

/**
 **
 ** the bug report replay will close
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.8
 **
 ** @author	Diether Knof
 **
 **/
void
UI::bug_report_replay_close()
{
  this->bug_report_replay_ = NULL;
  return ;
}

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the latest status message
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
Translator::Translation
UI::status_message() const
{
  if (this->status_message_.empty())
    return ::translation("");

  return this->status_message_.back();
} // Translator::Translation UI::status_message() const

/**
 **
 ** adds the status message
 **
 ** @param	status_message	the new status message
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
UI::add_status_message(Translator::Translation const& status_message)
{
  this->status_message_.push_back(status_message);
  this->status_message_changed(status_message);

  return ;
} // void UI::add_status_message(Translator::Translation const& status_message)

/**
 **
 ** remove the status message
 **
 ** @param	status_message	the status message that is to be removed
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
UI::remove_status_message(Translator::Translation const& status_message)
{
  vector<Translator::Translation>::iterator pos
    = std::find(this->status_message_.begin(),
		this->status_message_.end(),
		status_message);

  DEBUG_ASSERTION((pos != this->status_message_.end()),
		  "UI::remove_status_message(status_message):\n"
		  "  message '" << status_message << "' "
		  "not found in the list");

  if (pos != this->status_message_.end())
    pos = this->status_message_.erase(pos);

  if (pos == this->status_message_.end())
    this->status_message_changed(this->status_message());

  return ;
} // void UI::remove_status_message(Translator::Translation const& status_message)

/**
 **
 ** the program is busy
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
UI::set_busy()
{
  this->busy_ = true;
  return ;
}

/**
 **
 ** the program is not busy any more
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
UI::set_not_busy()
{
  this->busy_ = false;
  return ;
}

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the progress
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
double
UI::progress() const
{
  if (this->progress_max_ == 0)
    return 1;

  return (this->progress_ / this->progress_max_);
} // double UI::progress() const

/**
 **
 ** sets the maximal progress
 **
 ** @param	progress_max	the maximal progress
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
UI::set_max_progress(double const progress_max)
{
  DEBUG_ASSERTION((this->progress_max_ == 0),
		  "UI::set_max_progress(progress_max):\n"
		  "  'this->progress_max_' is already set: "
		  << this->progress_max_ << ".");

  this->progress_max_ = progress_max;
  this->progress_ = 0;
  this->progress_changed(this->progress());

  return ;
} // void UI::set_max_progress(double const progress_max)

/**
 **
 ** adds 'progress' to the progress
 **
 ** @param	progress	the progress
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
UI::add_progress(double const progress)
{
  this->progress_ += progress;
#ifdef POSTPHONED
  DEBUG_ASSERTION((this->progress() <= 1.000001),
		  "UI::add_progress(progress):\n"
		  "  'progress' is greater than 1: "
		  << this->progress());
#else
  if (this->progress() > 1.000001)
    cerr << "UI::add_progres():\n"
      << "  progress is " << this->progress() << ", greater than 1" << endl;
  else
#endif
    if (this->progress() > 1 - 0.000001)
      this->progress_ = this->progress_max_;

  this->progress_changed(this->progress());

  return ;
} // void UI::add_progress(double const progress)

/**
 **
 ** the progress is finished
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
UI::finish_progress()
{
#ifndef RELEASE
#ifdef POSTPHONED
  DEBUG_ASSERTION((this->progress() == 1),
		  "UI::finish_progress():\n"
		  "  'progress' is not equal to 1: "
		  << this->progress()
		  << ", diff: " << this->progress() - 1);
#else
  if (this->progress() != 1)
    cerr << "UI::finish_progres():\n"
      << "  progress is " << this->progress() << ", not 1" << endl;
#endif
#endif

  this->progress_finished();
  this->progress_max_ = 0;
  this->progress_ = 0;

  return ;
} // void UI::finish_progress()
