/***************************************************************************
 *   Copyright (C) 2005 by Armando Navarro-Vazquez                         *
 *   armando@linux                                                         *
 *                                                                         *
 *   This program 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.                                   *
 *                                                                         *
 *   This program 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 this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "cpmdparser.h"
#include "xyzparser.h"
#include "molecule.h"
#include "tokenizer.h"
const double bohrtoangs=0.529189379;
CPMDParser::CPMDParser ( const char*  file )
		: QuantumParser ( file ) , m_tfile ( NULL ) , m_optcell ( false )
{}

CPMDParser::CPMDParser ( std::istream* stream )
		: QuantumParser ( stream )
{}

CPMDParser::~CPMDParser()
{}

bool CPMDParser::ParseFile ( std::streampos pos )
{
	m_file->clear();
	m_file->seekg ( pos );
	switch ( m_jobpos.back().type )
	{
		case Quantum::opt:
			ParseOptimization ( pos );
			break;
		case Quantum::dyn:
			ParseDynamics ( pos );
			break;
		default:
			return false;
	}
	return true;
}

void CPMDParser::ParseOptimization ( std::streampos pos )
{
	GetGeometry ( pos );
}

void CPMDParser::ParseDynamics ( std::streampos pos )
{
       if ( ! ( *m_tfile ) ) throw Exception("TRAJEC.xyz file does not exist");
	XYZParser* parser= new XYZParser ( m_tfile );
	parser->SetMolecule ( m_molecule );
	parser->ParseFile();
	std::vector<CMolecule>::iterator mt;
	for ( mt=m_molecule->begin();mt!=m_molecule->end();++mt )
	{
		mt->CalculateMassCenter();
	}
}
bool CPMDParser::GetGeometry ( std::streampos pos )
{


	std::string line;
	bool cellfound=false;
	while ( std::getline ( *m_file,line ) )
	{
		if ( !cellfound )
			if ( line.find ( "CELL DIMENSION" ) != std::string::npos )
			{
				std::cout << "supercell" << std::endl;
				if ( line.find ( "REFERENCE" ) != std::string:: npos ) m_optcell=true;
				else
					GetCell();
				cellfound=true;
			}
		if ( line.find ( "ATOM          COORDINATES            GRADIENTS (-FORCES)" ) != std::string::npos )
			GetGeometryBlock();
		if ( line.find ( "END OF GEOMETRY OPTIMIZATION" ) != std::string::npos ) return true;

	}

	return false;
}
bool  CPMDParser::GetCell()
{
	std::cout << "get cell" << std::endl;
	std::string line;
	std::getline ( *m_file,line );
	m_cell.resize ( 3 );
	for ( int i=0;i<3;++i )
	{
		std::getline ( *m_file,line );
		StringTokenizer token ( line );
		StringTokenizer::reverse_iterator it;
		it=token.rbegin();
		m_cell[i].z=atof ( it->c_str() ) /Quantum::angstromtobohr;
		++it;
		m_cell[i].y=atof ( it->c_str() ) /Quantum::angstromtobohr;
		++it;
		m_cell[i].x=atof ( it->c_str() ) /Quantum::angstromtobohr;
		std::cout << "m_cell is " << m_cell[i] << std::endl;
	}

}
void CPMDParser::GetGeometryBlock()
{
	std::cout << "get geometry" << std::endl;
	CMolecule molecule;
	std::string line;
	while ( std::getline ( *m_file,line ) )
	{
		std::cout << line << std::endl;
		if ( line.find ( "***" ) != std::string::npos  || line.find ( "TOTAL" ) != std::string::npos ) break;

		StringTokenizer token ( line," \t\r" );
		if ( token.size() >= 5 )
		{
			CAtom atom;
			atom.name=token.at ( 1 );
			atom.c.x=atof ( token.at ( 2 ).c_str() ) /Quantum::angstromtobohr;
			atom.c.y=atof ( token.at ( 3 ).c_str() ) /Quantum::angstromtobohr;
			atom.c.z=atof ( token.at ( 4 ).c_str() ) /Quantum::angstromtobohr;
			molecule.m_atom.push_back ( atom );
		}
	}
	std::cout << "hola " << std::endl;
	if ( m_optcell )
		GetCellBlock ( molecule );
	else
		molecule.Cell() =m_cell;
	GetEnergyBlock ( molecule );
	molecule.SetConexions();
	molecule.CalculateMassCenter();
	m_molecule->push_back ( molecule );
}

void CPMDParser::GetCellBlock ( CMolecule& molecule )
{
	std::cout << "GetCellBlock" << std::endl;
	std::string line;
	while ( std::getline ( *m_file,line ) )
	{
		if ( line.find ( "CELL PARAMETER" ) != std::string::npos )
			break;
	}
	molecule.Cell().resize ( 3 );
	for ( int i=0;i<3;++i )
	{
		std::getline ( *m_file,line );
		StringTokenizer token ( line,"  \t\r" );
		molecule.Cell().at ( i ).x=atof ( token.at ( 0 ).c_str() ) /Quantum::angstromtobohr;
		molecule.Cell().at ( i ).y=atof ( token.at ( 1 ).c_str() ) /Quantum::angstromtobohr;
		molecule.Cell().at ( i ).z=atof ( token.at ( 2 ).c_str() ) /Quantum::angstromtobohr;
		std::cout << "opt cell is "  << molecule.Cell().at ( i )  << std::endl;
	}


}


std::vector<Quantum::jobheader>& CPMDParser::GetJobs()
{
	m_jobpos.clear();
	Quantum::jobtype j=Quantum::dens;
	std::string line;
	while ( std::getline ( *m_file,line ) )
	{
		if ( line.find ( "GEOMETRY OPTIMIZATION" ) != std::string::npos )
		{
			std::cout << "Found CPMD optimization job" << std::endl;
			j=Quantum::opt;
			goto lb;
		}
		if ( line.find ( "MOLECULAR DYNAMICS" ) != std::string::npos )
		{
			std::cout << "Found CPMD Car-Parrinello job" << std::endl;
			j=Quantum::dyn;
			goto lb;


		}
	}
lb:
	m_file->clear();
	m_file->seekg ( 0 );
	m_jobpos.push_back ( Quantum::jobheader ( j,0 ) );
	return m_jobpos;

}

void CPMDParser::GetEnergyBlock ( CMolecule& molecule )
{
	std::string line;
	while ( std::getline ( *m_file,line ) )
	{
		if ( line.find ( "GNMAX" ) != std::string::npos )
		{
			StringTokenizer token ( line," \t\r*" );
			molecule.SetEnergy ( atof ( token.back().c_str() ) );
			molecule.SetMaximumForce ( atof ( token.at ( 1 ).c_str() ) );
			std::getline ( *m_file,line );
			StringTokenizer tok1 ( line," \t\r*" );
			molecule.SetRMSForce ( atof ( tok1.at ( 1 ).c_str() ) );
			return;
		}
	}
}

void CPMDParser::SetTrajectoryFile ( const char* file )
{
	m_tfile = new std::ifstream ( file,std::ios::binary );
	std::cout << "m_tfile" << m_tfile << std::endl;
	if ( ! ( *m_tfile ) )
		std::cerr << "could not open TRAJEC.xyz file"  << std::endl;
}
