/*
 * Project: MoleCuilder
 * Description: creates and alters molecular systems
 * Copyright (C)  2012 University of Bonn. All rights reserved.
 * Copyright (C)  2013-2014 Frederik Heber. 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 .
 */
/*
 * UndoRedoHelpers.cpp
 *
 *  Created on: Apr 5, 2012
 *      Author: heber
 */
// include config.h
#ifdef HAVE_CONFIG_H
#include 
#endif
#include "CodePatterns/MemDebug.hpp"
#include "UndoRedoHelpers.hpp"
#include 
#include 
#include 
#include "Atom/atom.hpp"
#include "molecule.hpp"
#include "Descriptors/AtomIdDescriptor.hpp"
#include "Descriptors/MoleculeIdDescriptor.hpp"
#include "CodePatterns/Assert.hpp"
#include "CodePatterns/Log.hpp"
#include "World.hpp"
#include "WorldTime.hpp"
bool MoleCuilder::AddAtomsFromAtomicInfo(std::vector &atoms)
{
  size_t i=0;
  for (; i &atoms)
{
  BOOST_FOREACH(const AtomicInfo &_atom, atoms) {
    World::getInstance().destroyAtom(_atom.getId());
  }
}
void MoleCuilder::StoreBondInformationFromAtoms(
    const std::vector &atoms,
    std::vector< BondInfo > &bonds)
{
  ASSERT( bonds.empty(),
      "StoreBondInformationFromAtoms() - give bonds vector is not empty.");
  bonds.reserve(atoms.size()*4);
  for (std::vector::const_iterator atomiter = atoms.begin();
      atomiter != atoms.end(); ++atomiter) {
    const BondList & _atom_bonds = (*atomiter)->getListOfBonds();
    for(BondList::const_iterator iter = _atom_bonds.begin(); iter != _atom_bonds.end(); ++iter)
      bonds.push_back( BondInfo(*iter) );
  }
}
bool MoleCuilder::AddBondsFromBondInfo(const std::vector< BondInfo > &bonds)
{
  bool status = true;
  for(std::vector< BondInfo >::const_iterator iter = bonds.begin();
      iter != bonds.end(); ++iter)
    if (!(*iter).RecreateBond())
      status = false;
  return status;
}
void MoleCuilder::SetAtomsFromAtomicInfo(const std::vector &_movedatoms)
{
  BOOST_FOREACH( const AtomicInfo &_atominfo, _movedatoms) {
    const atomId_t id = _atominfo.getId();
    atom * const _atom = World::getInstance().getAtom(AtomById(id));
    ASSERT( _atom != NULL,
        "MoleCuilder::SetAtomsFromAtomicInfo() - cannot find atom with id "
        +toString(id)+" in the world.");
    _atominfo.setAtom( *_atom );
  }
}
void MoleCuilder::SelectAtomsFromAtomicInfo(const std::vector &_movedatoms)
{
  BOOST_FOREACH( const AtomicInfo &_atominfo, _movedatoms) {
    const atomId_t id = _atominfo.getId();
    World::getInstance().selectAtom(id);
  }
}
void MoleCuilder::ResetAtomPosition(const std::vector &movedatoms, const std::vector &MovedToVector)
{
  boost::function setter =
      boost::bind(&atom::setPosition, _1, _2);
  ResetByFunction(movedatoms, MovedToVector, setter);
}
void MoleCuilder::ResetAtomVelocity(const std::vector &movedatoms, const std::vector &VelocityVector)
{
  boost::function setter =
      boost::bind(&atom::setAtomicVelocity, _1, _2);
  ResetByFunction(movedatoms, VelocityVector, setter);
}
void MoleCuilder::ResetAtomForce(const std::vector &movedatoms, const std::vector &ForceVector)
{
  boost::function setter =
      boost::bind(&atom::setAtomicForce, _1, _2);
  ResetByFunction(movedatoms, ForceVector, setter);
}
void MoleCuilder::ResetByFunction(
    const std::vector &movedatoms,
    const std::vector &MovedToVector,
    boost::function &setter)
{
  std::vector::const_iterator positer = MovedToVector.begin();
  ASSERT(movedatoms.size() == MovedToVector.size(),
      "MoleCuilder::ResetAtomPosition() -  the number of atoms "
      +toString(movedatoms.size())+" and the number of positions "
      +toString(MovedToVector.size())+" is not the same.");
  BOOST_FOREACH( const AtomicInfo &_atominfo, movedatoms) {
    const atomId_t id = _atominfo.getId();
    atom * const _atom = World::getInstance().getAtom(AtomById(id));
    ASSERT( _atom != NULL,
        "FillSphericalSurfaceAction::performRedo() - cannot find atom with id "
        +toString(id)+" in the world.");
    setter(_atom, *positer );
    ++positer;
  }
}
void MoleCuilder::RemoveMoleculesWithAtomsByIds(const std::vector &ids)
{
  for (std::vector::const_iterator iter = ids.begin();
      iter != ids.end(); ++iter) {
    molecule * const mol = World::getInstance().getMolecule(MoleculeById(*iter));
    if (mol != NULL) {
      mol->removeAtomsinMolecule();
      World::getInstance().destroyMolecule(mol);
    }
  }
}
void MoleCuilder::removeLastStep(const std::vector &_atoms)
{
  for (size_t i=0; i<_atoms.size(); ++i) {
    atom * const _atom = World::getInstance().getAtom(AtomById(_atoms[i]));
    _atom->removeSteps();
  }
}
void MoleCuilder::addNewStep(const std::vector &_movedatoms)
{
  for(size_t i=0; i< _movedatoms.size(); ++i) {
    atom * const _atom = World::getInstance().getAtom(AtomById(_movedatoms[i].getId()));
    _atom->UpdateSteps();
  }
}
void MoleCuilder::addNewStep(const std::vector &_ids)
{
  for(size_t i=0; i< _ids.size(); ++i) {
    atom * const _atom = World::getInstance().getAtom(AtomById(_ids[i]));
    _atom->UpdateSteps();
  }
}
std::vector MoleCuilder::getIdsFromAtomicInfo(const std::vector &movedatoms)
{
  std::vector ids(movedatoms.size(), (size_t)-1);
  std::transform(
      movedatoms.begin(), movedatoms.end(),
      ids.begin(),
      boost::bind(&AtomicInfo::getId, _1));
  return ids;
}