/*
 * Project: MoleCuilder
 * Description: creates and alters molecular systems
 * Copyright (C)  2010-2012 University of Bonn. All rights reserved.
 * Copyright (C)  2013 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 .
 */
/*
 * ParserXyzUnitTest.cpp
 *
 *  Created on: Mar 3, 2010
 *      Author: metzler
 */
// include config.h
#ifdef HAVE_CONFIG_H
#include 
#endif
#include "ParserXyzUnitTest.hpp"
#include 
#include 
#include 
#include "Atom/atom.hpp"
#include "Atom/AtomObserver.hpp"
#include "CodePatterns/Log.hpp"
#include "Descriptors/AtomTypeDescriptor.hpp"
#include "Element/element.hpp"
#include "Element/periodentafel.hpp"
#include "Parser/ChangeTracker.hpp"
#include "Parser/XyzParser.hpp"
#include "World.hpp"
#ifdef HAVE_TESTRUNNER
#include "UnitTestMain.hpp"
#endif /*HAVE_TESTRUNNER*/
using namespace std;
// Registers the fixture into the 'registry'
CPPUNIT_TEST_SUITE_REGISTRATION( ParserXyzUnitTest );
static string waterXyz = "\
3\n\
\tH2O: water molecule\n\
O\t0\t0\t0\n\
H\t0.758602\t0\t0.504284\n\
H\t0.758602\t0\t-0.504284\n";
static string waterMultiXyz = "\
3\n\
\tH2O: water molecule, time step 0\n\
O\t0\t0\t0\n\
H\t0.758602\t0\t0.504284\n\
H\t0.758602\t0\t-0.504284\n\
3\n\
\tH2O: water molecule, time step 1\n\
O\t0\t0\t0\n\
H\t0.76\t0\t0.504284\n\
H\t0.756\t0\t-0.504284\n";
void ParserXyzUnitTest::setUp() {
  World::getInstance();
  parser = new FormatParser();
  setVerbosity(2);
  // we need hydrogens and oxygens in the following tests
  CPPUNIT_ASSERT(World::getInstance().getPeriode()->FindElement(1) != NULL);
  CPPUNIT_ASSERT(World::getInstance().getPeriode()->FindElement(8) != NULL);
}
void ParserXyzUnitTest::tearDown() 
{
  delete parser;
  ChangeTracker::purgeInstance();
  World::purgeInstance();
  AtomObserver::purgeInstance();
}
/************************************ tests ***********************************/
void ParserXyzUnitTest::rewriteAnXyzTest() {
  cout << "Testing the XYZ parser." << endl;
  stringstream input;
  input << waterXyz;
  parser->load(&input);
  input.clear();
  CPPUNIT_ASSERT_EQUAL(3, World::getInstance().numAtoms());
  // store and parse in again
  {
    stringstream output;
    std::vector atoms = World::getInstance().getAllAtoms();
    parser->save(&output, atoms);
    input << output.str();
    parser->load(&input);
  }
  // now twice as many
  CPPUNIT_ASSERT_EQUAL(6, World::getInstance().numAtoms());
  // check every atom
  std::vector atoms = World::getInstance().getAllAtoms();
  std::vector::const_iterator firstiter = atoms.begin();
  std::vector::const_iterator seconditer = atoms.begin();
  for (size_t i=0;i<3;i++)
    ++seconditer;
  for (;
      seconditer != atoms.end();
      ++firstiter,++seconditer) {
    // check position and type (only stuff xyz stores)
    CPPUNIT_ASSERT_EQUAL((*firstiter)->getPosition(),(*seconditer)->getPosition());
    CPPUNIT_ASSERT_EQUAL((*firstiter)->getType(),(*seconditer)->getType());
  }
}
void ParserXyzUnitTest::readMultiXyzTest() {
  cout << "Testing the multi time step XYZ parser." << endl;
  stringstream input;
  input << waterMultiXyz;
  parser->load(&input);
  input.clear();
  // 3 not 6 atoms!
  CPPUNIT_ASSERT_EQUAL(3, World::getInstance().numAtoms());
  // check for trajectory size
  BOOST_FOREACH (atom *_atom, World::getInstance().getAllAtoms())
    CPPUNIT_ASSERT_EQUAL((size_t) 2, _atom->getTrajectorySize());
}
void ParserXyzUnitTest::writeMultiXyzTest() {
  stringstream input;
  input << waterMultiXyz;
  parser->load(&input);
  input.clear();
  // 3 not 6 atoms!
  CPPUNIT_ASSERT_EQUAL(3, World::getInstance().numAtoms());
  // store and parse in again
  {
    stringstream output;
    std::vector atoms = World::getInstance().getAllAtoms();
    parser->save(&output, atoms);
    input << output.str();
    parser->load(&input);
  }
  // now twice as many
  CPPUNIT_ASSERT_EQUAL(6, World::getInstance().numAtoms());
  // check for trajectory size of all 6! atoms
  BOOST_FOREACH (atom *_atom, World::getInstance().getAllAtoms())
    CPPUNIT_ASSERT_EQUAL((size_t) 2, _atom->getTrajectorySize());
  // check every atom
  std::vector atoms = World::getInstance().getAllAtoms();
  std::vector::const_iterator firstiter = atoms.begin();
  std::vector::const_iterator seconditer = atoms.begin();
  for (size_t i=0;i<3;i++)
    ++seconditer;
  for (;
      seconditer != atoms.end();
      ++firstiter,++seconditer) {
    CPPUNIT_ASSERT_EQUAL((*firstiter)->getType(),(*seconditer)->getType());
    for (unsigned int step = 0; step < 2; ++step) {
      // check position and type (only stuff xyz stores)
      CPPUNIT_ASSERT_EQUAL(
          (*firstiter)->getPositionAtStep(step),
          (*seconditer)->getPositionAtStep(step));
    }
  }
}