/*
 * 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 .
 */
/*
 * Action.cpp
 *
 *  Created on: Dec 8, 2009
 *      Author: crueger
 */
// include config.h
#ifdef HAVE_CONFIG_H
#include 
#endif
#include "CodePatterns/MemDebug.hpp"
#include 
#include 
#include 
#include "Actions/Action.hpp"
#include "Actions/ActionExceptions.hpp"
#include "Actions/ActionQueue.hpp"
#include "Actions/ActionRegistry.hpp"
#include "UIElements/Dialog.hpp"
#include "CodePatterns/Assert.hpp"
#include "CodePatterns/MemDebug.hpp"
#include "UIElements/UIFactory.hpp"
#include "CodePatterns/Log.hpp"
#include "CodePatterns/Verbose.hpp"
using namespace MoleCuilder;
ActionState::ptr getEmptyState() {
  return ActionState::ptr(Memory::ignore(new ActionState()));
}
void Action::removeStaticStateEntities()
{
  Action::success.reset();
  Action::failure.reset();
}
void Action::createStaticStateEntities()
{
  Action::success = getEmptyState();
  Action::failure = getEmptyState();
}
// An empty state to indicate success, these are (de)initialized by ActionHistory
ActionState::ptr Action::success;
ActionState::ptr Action::failure;
Action::Action(const ActionTrait &_Traits) :
    Traits(_Traits)
{}
Action::~Action()
{}
const string Action::getName() const
{
  return Traits.getName();
}
const std::string Action::help() const
{
  std::stringstream outputstream;
  outputstream << "Description for Action '" << getName() << "': " << Traits.getDescription()
      << std::endl;
  if (!Traits.hasOption(getName())) {
    outputstream << "\tNote that this Action does not take an argument." << std::endl;
  }
  outputstream << "Options available for action '" << getName() << "':" << std::endl;
  for (ActionTrait::options_const_iterator iter = Traits.getBeginIter();
      iter != Traits.getEndIter();
      ++iter) {
    outputstream << "Option '" << iter->first << "':" << std::endl;
    outputstream << "\tDescription: " << iter->second->getDescription() << "." << std::endl;
    outputstream << "\tArgument's type: " << iter->second->getTypeName() << "." << std::endl;
    outputstream << "\tDefault value: ";
    if (iter->second->hasDefaultValue()) {
      outputstream << "Yes, is '" << iter->second->getDefaultValue() << "'";
    } else {
      outputstream << "None";
    }
    outputstream << "." << std::endl;
  }
  return outputstream.str();
}
void Action::prepare(enum QueryOptions flag)
{
  // fill with
  if (flag == Interactive) {
    Dialog* dialog = createDialog();
    if (dialog->hasQueries()) {
      if (!dialog->display())
        // dialog error or aborted -> throw exception
        throw ActionFailureException() << ActionNameString(getName());
    }
    delete(dialog);
  }
}
Dialog * Action::createDialog(){
  Dialog *dialog = UIFactory::getInstance().makeDialog(Traits.getName());
  return fillDialog(dialog);
}
void Action::call(){
  if(!isActive()){
    return;
  }
  ActionState::ptr state = Action::failure;
  startTimer();
  try {
    state = performCall();
  } catch (ParameterException &e) {
    if( const std::string *name=boost::get_error_info(e) )
      ELOG(1, "The following parameter value is not valid: " << *name << ".");
    state = Action::failure;
  }
  endTimer();
  if(shouldUndo() && state != failure){
    if(canUndo()){
      ActionQueue::getInstance().addElement(this,state);
    }
    else{
      ActionQueue::getInstance().clear();
    }
  }
  // throw an exception that can be caught in case of failure
  if (state == Action::failure)
    throw ActionFailureException() << ActionNameString(getName());
}
ActionState::ptr Action::undo(ActionState::ptr _state) {
  // forward to private virtual
  return performUndo(_state);
}
ActionState::ptr Action::redo(ActionState::ptr _state) {
  // forward to private virtual
  return performRedo(_state);
}
void Action::insertAction(Action *_action, enum Action::QueryOptions state)
{
  ActionQueue::getInstance().insertAction(_action, state);
}
bool Action::isActive(){
  return true;
}
void Action::pushStatus(const std::string& _msg)
{
  ActionQueue::getInstance().pushStatus(_msg);
}