/**********************************************************************
 *
 *   FreeDoko a Doppelkopf-Game
 *    
 *   Copyright (C) 2001-2005  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
 *
 ********************************************************************/


/**
 **
 ** Alpha-Version of FreeDoko 
 **
 **   developed since fall 2001
 **
 **/

#include "constants.h"
#include <time.h>
#ifdef WINDOWS
// for 'mkdir'
#include <io.h>
#else
// for 'mkdir'
#include <sys/stat.h>
#endif

#include "class/getopt/getopt.h"

#include "utils/file.h"
#include "utils/string.h"

#include "utils.h"
#include "basistypes.h"

#include "misc/setting.h"
#include "misc/translator.h"
#include "misc/bug_report.h"

#include "party/party.h"

#include "ui/ui.wrap.h"
#include "ui/ui.dummy.h"

#include "os/seed.h"
#include "os/party_points.h"
#include "os/bug_report_replay.h"

UI* ui = NULL;
Translator translator;
Setting setting_default;
Setting setting;
Party party;


#include "player/namegen.h"
#ifndef WINDOWS
int
main(int argc, char* argv[])
#else
  // ToDo: use 'WinMain'
int
main(int argc, char* argv[])
#endif
{
  using DK::Utils::Version;
  using DK::Utils::Date;


  // make an assertion create a bug report
  ::debug_function = &create_assertion_bug_report;

  // list of all Versions
  ::all_versions.push_back(new Version(0, 6, 3,		Date(2004,   5,  5)));
  ::all_versions.push_back(new Version(0, 6, 4,		Date(2004,   6,  1)));
  ::all_versions.push_back(new Version(0, 6, 5, 	Date(2004,   6, 24)));
  ::all_versions.push_back(new Version(0, 6, 5, 'b',	Date(2004,   6, 28)));
  ::all_versions.push_back(new Version(0, 6, 6,		Date(2004,   9, 25)));
  ::all_versions.push_back(new Version(0, 6, 7,		Date(2004,  12, 16)));
  ::all_versions.push_back(new Version(0, 6, 7, 'b',	Date(2004,  12, 20)));
  ::all_versions.push_back(new Version(0, 6, 8,		Date(2005,   4, 11)));

  // initialisation for random functions
  ::srand(static_cast<unsigned>(::time(NULL) % RAND_MAX));

  ui = new UI_Wrap;
#ifndef RELEASE
#ifdef DKNOF
  //static_cast<UI_Wrap*>(ui)->append(new_OS(OS_TYPE::GAMEPLAY));
#endif
#endif
#ifndef RELEASE
  static_cast<UI_Wrap*>(ui)->append(new_OS(OS_TYPE::CHATTER));
#endif


#ifndef RELEASE
  // output of the seed each game
  static_cast<UI_Wrap*>(ui)->append(new OS_NS::Seed(new ofstream((::setting(Setting::PRIVATE_DATA_DIRECTORY) + "/seed").c_str(),
								 ios::app)));
#endif
#ifndef RELEASE
  // output of the party points
  static_cast<UI_Wrap*>(ui)->append(new OS_NS::PartyPoints(new ofstream("FreeDoko.party_points")));
#endif

  // set the default ui
#if defined(USE_UI_GTKMM)
  UI* ui_tmp = new_UI(UI_TYPE::GTKMM_DOKO);
#elif defined(USE_UI_AATEXT)
  UI* ui_tmp = new_UI(UI_TYPE::AATEXT);
#elif defined(USE_UI_TEXT)
  UI* ui_tmp = new_UI(UI_TYPE::TEXT);
#else
  UI* ui_tmp = new_UI(UI_TYPE::DUMMY);
#endif
  { // parse options

    // This file contains the help you get calling the program with '-?'.
    // It includes what arguments you can use.
#ifdef WINDOWS
#include "text/gpl.dos.string"
#include "text/help.dos.string"
#else
#include "text/gpl.string"
#include "text/help.string"
#endif

    // load the settings
    setting.load();

    // parse the options
    GetOpt::Option option;
    while (option =
	   GetOpt::getopt(argc, argv,
			  "help", '?', GetOpt::Syntax::BOOL,
			  "hilfe", 'h', GetOpt::Syntax::BOOL,
			  "version", 'v', GetOpt::Syntax::BOOL,
			  "license", 'L', GetOpt::Syntax::BOOL,
			  "ui", 'u', GetOpt::Syntax::BSTRING,
			  "settings", '\0', GetOpt::Syntax::BSTRING,
			  "name", 'n', GetOpt::Syntax::BSTRING,
			  "language", 'l', GetOpt::Syntax::BSTRING,
			  "seed", 's', GetOpt::Syntax::UNSIGNED,
			  "startplayer", 'p', GetOpt::Syntax::UNSIGNED,
			  "cardset", 'C', GetOpt::Syntax::BSTRING,
			  "cards_height", 'H', GetOpt::Syntax::UNSIGNED,
			  "bug_report", 'b', GetOpt::Syntax::BSTRING,
#ifndef RELEASE
			  "fast_play", 'F', GetOpt::Syntax::BOOL,
#endif
			  // end of arguments
			  "", 0, GetOpt::Syntax::END)) {

      if (option.fail()
	  || (option.name() == "")) {
	if (option.name() == "")
	  option.error_v = GetOpt::Option::FALSE_ARGUMENT;
	// wrong usage
	cerr << argv[0] << "\n"
	  << "wrong usage: "
	  << option.error() << " " << option.value_string() << "\n"
	  << "For the syntax type '" << argv[0] << " -?'"
	  << endl;

	return EXIT_FAILURE;
      } // if (option.fail())

      if ((option.name() == "help") 
	  || (option.name() == "hilfe")) {
	// output of the help
	cout << help_string << endl;
	return EXIT_SUCCESS;
      } else if (option.name() == "version") {
	// output of the version
	cout << "FreeDoko " << ::version << "\n"
	  << "\n"
	  << GPL_string;
	return EXIT_SUCCESS;
      } else if (option.name() == "license") {
	// output of the license (GPL)
	cout << "FreeDoko -- License:\n\n"
	  << GPL
	  << '\n'
	  << '\n'
	  << "----------\n"
	  << '\n'
	  << "Cardset '" << ::setting(Setting::CARDSET) << "' license:\n"
	  << cardset_license
	  << endl;
	return EXIT_SUCCESS;
      } else if (option.name() == "ui") {
	delete ui_tmp;
	if (option.value_string() == "none")
	  ui_tmp = new_UI(UI_TYPE::DUMMY);
#ifdef USE_UI_TEXT
	else if (option.value_string() == "text")
	  ui_tmp = new_UI(UI_TYPE::TEXT);
#endif
#ifdef USE_UI_GTKMM
	else if (option.value_string() == "gtkmm")
	  ui_tmp = new_UI(UI_TYPE::GTKMM_DOKO);
#endif
	else {
	  cerr << "ui '" << option.value_string() << "' not implemented.\n"
	    << "exiting";
	  return 1;
	} // if (option.value_string() == "...")
      } else if (option.name() == "settings") {
	setting.load(option.value_string());
      } else if (option.name() == "name") {
	setting.set(Setting::NAME, option.value_string());
      } else if (option.name() == "language") {
	setting.set(Setting::LANGUAGE, option.value_string());
      } else if (option.name() == "seed") {
	::party.set_seed_first(option.value(GetOpt::Option::UNSIGNED));
      } else if (option.name() == "startplayer") {
	unsigned const no = option.value(GetOpt::Option::UNSIGNED);
	if ( !( (no >= 1)
		&& (no <= ::party.playerno()) ) ) {
	  cerr << "startplayer number '" << no << "' not valid.\n"
	    << "must be between '1' and '" << ::party.playerno() << "'.\n"
	    << "ignoring the value\n"
	    << endl;
	  continue;
	}
	::party.set_startplayer_first(no - 1);
      } else if (option.name() == "graphic_size") {
	setting.set(Setting::CARDS_HEIGHT,
		    option.value(GetOpt::Option::UNSIGNED));
      } else if (option.name() == "cardset") {
	setting.set(Setting::CARDSET, option.value_string());
      } else if (option.name() == "bug_report") {
	static_cast<UI_Wrap*>(::ui)->append(new (OS_NS::BugReportReplay)(option.value_string()));
      } else if (option.name() == "fast_play") {
	FAST_PLAY = option.value(GetOpt::Option::BOOL);
	// change all humans to ai's
	for (unsigned p = 0; p < ::party.playerno(); p++)
	  if (::party.player(p).type() == Player::HUMAN)
	    ::party.playertype_set(p, Player::AI);
      } else {
	cerr << "Option " << option.name() << " unknown!" << endl;
	exit(1);
      } // if (option.name() == ...)
    } // while (getopt())
  } // parse options

#ifdef RELEASE
  if (FAST_PLAY)
    ::setting.set(Setting::SAVE_PARTY_CHANGES, false);
#endif

  { // set the ui
    static_cast<UI_Wrap*>(::ui)->ui = ui_tmp;

    if (SEED_OUT) {
      delete static_cast<UI_Wrap*>(::ui)->ui;
      static_cast<UI_Wrap*>(::ui)->ui = new_UI(UI_TYPE::DUMMY);
    } // if (SEED_OUT)

    // test, whether the ui is valid
    if ((::ui->type() == UI_TYPE::DUMMY)
	&& !FAST_PLAY) {
      cerr << "Uitype is 'dummy', aborting." << endl;
#ifdef RELEASE
      exit(1);
#endif
    } // if (::ui->type() == UI::NONE)
  } // set the ui

  // add the bug report in the ui.wrap,
  // so it gets the information of the gameplay
  static_cast<UI_Wrap*>(::ui)->append(&::bug_report);

  // init the ui
  ::ui->init(argc = 1, argv);

  { // if this is the first start, create some directories
    vector<string> dirnames;
    dirnames.push_back(::setting(Setting::PRIVATE_DATA_DIRECTORY));
    dirnames.push_back(::setting(Setting::PRIVATE_DATA_DIRECTORY)
		       + "/" + ::setting(Setting::RULES_DIRECTORY));
    dirnames.push_back(::setting(Setting::PRIVATE_DATA_DIRECTORY)
		       + "/" + ::setting(Setting::AI_DIRECTORY));
    Translator::Translation information = ::translator("");

    for (vector<string>::iterator dir = dirnames.begin();
	 dir != dirnames.end();
	 dir++) {
      if (!DK::Utils::File::isdirectory(*dir)) {
	information += (::translator("creating directory \'%sdir%\'",
				     *dir)
			+ "\n");
#ifdef WINDOWS
	mkdir(dir->c_str());
#else
	mkdir(dir->c_str(), 00700);
#endif
      } // if (!isdirectory(*dir))
    } // for (dir \in dirnames)
    if (!information.empty())
      ::ui->information(information);
  } // if this is the first start, create some directories

  { // read the version of the last usage of FreeDoko and write the new version

    // read the old version
    DK::Utils::Version* const version_old
      = DK::Utils::new_Version_from_file(::setting(Setting::PRIVATE_DATA_DIRECTORY)
					 + "/Version");

    { // write the new version
      ofstream ostr((::setting(Setting::PRIVATE_DATA_DIRECTORY)
		     + "/Version").c_str());
      if (!ostr.fail())
	ostr << version;
    } // write the new version

    if (version_old == NULL) {
      // This seems to be the first start -- give some introduction.
      ::ui->information(::translator("_first run_"));
    } else { // if !(version_old == NULL)
      // Compare the old version with the new version and give some output.
      if (*version_old < version) {
	Translator::Translation version_translation
	  = (::translator("_new version %sversion%_",
			  version.number_to_string())
	     + "\n");
	for (vector<Version const*>::reverse_iterator
	     v = ::all_versions.rbegin();
	     ( (v != ::all_versions.rend())
	       && (*version_old < **v) );
	     ++v) {
	  version_translation
	    += ("\n\n"
		+ ::translator("ChangeLog for version %sversion%:",
			       (*v)->number_to_string())
		+ "\n"
		+ ::translator("_ChangeLog " + (*v)->number_to_string() + "_"));
	} // for (v \in ::all_versions
	::ui->information(version_translation);
      } // if (*version_old < version)
#ifndef OUTDATED
      if (*version_old < DK::Utils::Version(0, 6, 3)) {
	::ui->information(::translator("_Adjusting settings time_"));
	// adjust the times in the settings
	::setting.set(Setting::CARD_PLAY_DELAY,
		      100 * ::setting(Setting::CARD_PLAY_DELAY));
	::setting.set(Setting::FULL_TRICK_CLOSE_DELAY,
		      100 * ::setting(Setting::FULL_TRICK_CLOSE_DELAY) );
	::setting.set(Setting::GAMETYPE_WINDOW_CLOSE_DELAY,
		      100 * ::setting(Setting::GAMETYPE_WINDOW_CLOSE_DELAY));
	::setting.set(Setting::MARRIAGE_WINDOW_CLOSE_DELAY,
		      100 * ::setting(Setting::MARRIAGE_WINDOW_CLOSE_DELAY));
	::setting.set(Setting::GENSCHER_WINDOW_CLOSE_DELAY,
		      100 * ::setting(Setting::GENSCHER_WINDOW_CLOSE_DELAY));
	::setting.set(Setting::ANNOUNCEMENT_WINDOW_CLOSE_DELAY,
		      100 * ::setting(Setting::ANNOUNCEMENT_WINDOW_CLOSE_DELAY));
	::setting.set(Setting::SWINES_WINDOW_CLOSE_DELAY,
		      100 * ::setting(Setting::SWINES_WINDOW_CLOSE_DELAY));
      } // if !(version_old == NULL)
#endif

      delete version_old;
    } // if (version_old != NULL)

  } // read the version of the last usage of FreeDoko and write the new version

  // load the default rules from the private data directory
  ::party.rule().load(::setting(Setting::PRIVATE_DATA_DIRECTORY)
		      + "/"
		      + ::setting(Setting::RULES_DIRECTORY)
		      + "/last");

  // now the preparatinos have finished

  while (game_status != GAMESTATUS::QUIT) {
    try {
      ::party.open();
      ::ui->party_open(::party);
      // start playing
      ::game_status = GAMESTATUS::PARTY_PLAY;
      ::party.play();
    } catch (GameStatus const gs) {
      DEBUG_ASSERTION(((gs == GAMESTATUS::PARTY_NEW)
		       || (gs == GAMESTATUS::QUIT)),
		      "main():\n"
		      "  caught gamestatus '" << gs << "'");
      ::game_status = gs;
      ::ui->party_close();
      ::party.close();
    } catch (...) {
      ::party.close();
      ::ui->party_close();
      throw;
    }
    ::ui->party_close();
    ::party.close();
  } // while (game_status != QUIT)

  // when exiting save the settings (once again)
  ::setting.save();

  // clean up
  delete ::ui;

  return EXIT_SUCCESS;
} // int main(argc, argv)
