/*
 * 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 .
 */
/*
 * manipulateAtomsTest.cpp
 *
 *  Created on: Feb 18, 2010
 *      Author: crueger
 */
// include config.h
#ifdef HAVE_CONFIG_H
#include 
#endif
#include 
#include 
#include 
#include 
#include 
#include "Descriptors/AtomDescriptor.hpp"
#include "Descriptors/AtomIdDescriptor.hpp"
#include "Actions/ManipulateAtomsProcess.hpp"
#include "Actions/ActionQueue.hpp"
#include "World.hpp"
#include "Atom/atom.hpp"
#include "stubs/DummyUI.hpp"
#include "ManipulateAtomsUnitTest.hpp"
using namespace MoleCuilder;
#ifdef HAVE_TESTRUNNER
#include "UnitTestMain.hpp"
#endif /*HAVE_TESTRUNNER*/
// Registers the fixture into the 'registry'
CPPUNIT_TEST_SUITE_REGISTRATION( manipulateAtomsTest );
// some stubs
class AtomStub : public atom {
public:
  AtomStub(int _id) :
  atom(),
  manipulated(false),
  id(_id)
  {}
  virtual atomId_t getId(){
    return id;
  }
  virtual void doSomething(){
    manipulated = true;
  }
  bool manipulated;
private:
  atomId_t id;
};
class countObserver : public Observer{
public:
  countObserver() :
    Observer("countObserver"),
    count(0)
    {}
  virtual ~countObserver(){}
  void update(Observable *){
    count++;
  }
  void subjectKilled(Observable *)
  {}
  int count;
};
// set up and tear down
void manipulateAtomsTest::setUp(){
  hasDescriptor = false;
  World::getInstance();
  // setup ActionHistory
  ActionQueue::getInstance();
  // TODO: find a way to really reset the factory to a clean state in tear-down
  if(!hasDescriptor){
    UIFactory::registerFactory(new DummyUIFactory::description());
    hasDescriptor = true;
  }
  UIFactory::makeUserInterface("Dummy");
  for(int i=0;i(_atom);
  CPPUNIT_ASSERT(atom);
  atom->doSomething();
}
void manipulateAtomsTest::testManipulateSimple(){
  ManipulateAtomsProcess *proc = World::getInstance().manipulateAtoms(boost::bind(operation,_1),"FOO",AllAtoms());
  proc->call();
  std::vector allAtoms = World::getInstance().getAllAtoms(AllAtoms());
  std::vector::iterator iter;
  for(iter=allAtoms.begin();iter!=allAtoms.end();++iter){
    AtomStub *atom;
    atom = dynamic_cast(*iter);
    CPPUNIT_ASSERT(atom);
    CPPUNIT_ASSERT(atom->manipulated);
  }
}
void manipulateAtomsTest::testManipulateExcluded(){
  ManipulateAtomsProcess *proc = World::getInstance().manipulateAtoms(boost::bind(operation,_1),"FOO",AllAtoms() && !AtomById(ATOM_COUNT/2));
  proc->call();
  std::vector allAtoms = World::getInstance().getAllAtoms(AllAtoms());
  std::vector::iterator iter;
  for(iter=allAtoms.begin();iter!=allAtoms.end();++iter){
    AtomStub *atom;
    atom = dynamic_cast(*iter);
    CPPUNIT_ASSERT(atom);
    if(atom->getId()!=(int)ATOM_COUNT/2)
      CPPUNIT_ASSERT(atom->manipulated);
    else
      CPPUNIT_ASSERT(!atom->manipulated);
  }
}
void manipulateAtomsTest::testObserver(){
  countObserver *obs = new countObserver();
  World::getInstance().signOn(obs);
  ManipulateAtomsProcess *proc = World::getInstance().manipulateAtoms(boost::bind(operation,_1),"FOO",AllAtoms());
  proc->call();
  CPPUNIT_ASSERT_EQUAL(1,obs->count);
  World::getInstance().signOff(obs);
  delete obs;
}