/*
 * Project: MoleCuilder
 * Description: creates and alters molecular systems
 * Copyright (C)  2010-2012 University of Bonn. All rights reserved.
 * 
 *
 *   This file is part of MoleCuilder.
 *
 *    MoleCuilder 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.
 *
 *    MoleCuilder 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 should have received a copy of the GNU General Public License
 *    along with MoleCuilder.  If not, see .
 */
/*
 * QtUIFactory.cpp
 *
 *  Created on: Jan 14, 2010
 *      Author: crueger
 */
// include config.h
#ifdef HAVE_CONFIG_H
#include 
#endif
#include 
#include 
#include 
#include 
#include 
#include 
#include "UIElements/Qt4/QtUIFactory.hpp"
#include "UIElements/Qt4/QtMainWindow.hpp"
#include "UIElements/Qt4/QtDialog.hpp"
// boost::python uses placement new which is incompatible with MemDebug.
#ifdef HAVE_PYTHON
#include "Python/PythonScripting.hpp"
#endif
#include "CodePatterns/MemDebug.hpp"
#include "Actions/ActionQueue.hpp"
#include "Helpers/defs.hpp"
using namespace std;
QtUIFactory::QtUIFactory(int _argc, char **_argv) :
    argc(1),
    argv(new char*[1]),
    testlauncher_Interrupted(false),
    testlauncher_thread(NULL)
{
  // check whether we are in test mode
  if ((_argc > 1) && (isTestMode(_argv[1]))) {
#ifdef HAVE_BOOST_THREAD_HPP
    std::vector scripts;
    scripts.reserve(_argc-1);
    for (int i=2;i<_argc;++i)
      scripts.push_back(std::string(_argv[i]));
    // check for line-by-line execution
    const bool SingleLineStepping = (strncmp(&_argv[1][7], "single", 6) == 0);
    // prepare an extra thread
    std::cout << "TESTLAUNCHER: Preparing " << std::endl;
    testlauncher_thread = new boost::thread(
        boost::bind(&QtUIFactory::testrun, this, scripts, SingleLineStepping));
#else
    std::cerr << "Boost::thread support missing! Cannot launch test scripts.\n";
#endif
    // use fake commands to not pass test stuff
    const int length = strlen(_argv[0]);
    argv[0] = new char[length];
    strncpy(argv[0],_argv[0], length);
    app = new QApplication(argc,argv);
  } else {
    const int length = strlen(_argv[0]);
    argv[0] = new char[length];
    strncpy(argv[0],_argv[0], length);
    app = new QApplication(argc,argv);
  }
}
QtUIFactory::~QtUIFactory()
{
  if (testlauncher_thread != NULL) {
    // notify testlauncher_thread thread that we wish to terminate
    testlauncher_thread->interrupt();
    // wait till it ends
    testlauncher_thread->join();
    // and remove
    delete testlauncher_thread;
  }
  // free fake command line argument arrays
  delete[] argv[0];
  delete[] argv;
}
Dialog* QtUIFactory::makeDialog(const std::string &_title) {
  return new QtDialog(_title);
}
MainWindow* QtUIFactory::makeMainWindow() {
  MainWindow * const mainwindow = new QtMainWindow(app);
  UIFactory::doneInitializing = true;
  return mainwindow;
}
QtUIFactory::description::description(int _argc, char **_argv) :
    UIFactory::factoryDescription("Qt4"),
    argc(_argc),
    argv(_argv)
{}
QtUIFactory::description::~description()
{}
UIFactory* QtUIFactory::description::makeFactory(){
  return new QtUIFactory(argc, argv);
}
bool QtUIFactory::isTestMode(const char *_argument)
{
  return (strncmp(_argument,"--test", 6) == 0);
}
void QtUIFactory::testrun(const std::vector _scripts, const bool _singleLineStepping) const
{
  std::cout << "TESTLAUNCHER: Waiting for GUI to set up" << std::endl;
  while (!UIFactory::isDoneInitializing())
    testlauncher_sleep(boost::posix_time::seconds(.1));
  std::vector::const_iterator scriptiter = _scripts.begin();
  do {
    // then launch script
    std::cout << "TESTLAUNCHER: Launching script " << *scriptiter
        << (_singleLineStepping ? " line by line." : ".") <processEvents();
          testlauncher_sleep(boost::posix_time::seconds(.5));
        } while (!MoleCuilder::ActionQueue::getInstance().isIdle());
      }
    } else {
      executePythonScriptFile(*scriptiter);
    }
#else
    std::cerr << "Python support not compiled in, cannot execute gui test scripts.\n";
#endif
    ++scriptiter;
    std::cout << "TESTLAUNCHER: Sleeping after script" << std::endl;
    testlauncher_sleep(boost::posix_time::seconds(1.));
  } while ((scriptiter != _scripts.end()) && (!testlauncher_Interrupted));
  // send quit signal
  std::cout << "TESTLAUNCHER: Quitting" << std::endl;
  app->quit(); // exit flag here is not relevant, end of main() sets the return code
}
void QtUIFactory::testlauncher_sleep(const boost::posix_time::time_duration& _period) const
{
  try {
    // first sleep for four seconds
#if BOOST_VERSION < 105000
    testlauncher_thread->sleep(boost::get_system_time() + _period);
#else
    boost::this_thread::sleep_for(boost::chrono::seconds(4));
#endif
  } catch(boost::thread_interrupted &e) {
    LOG(2, "INFO: testlauncher thread has received stop signal.");
  }
}