/***************************************************************************
 *   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 "molecule.h"
#include "tokenizer.h"

#include "nwchemparser.h"

NwChemParser::NwChemParser(const char* file)
    : QuantumParser(file) 
{
  m_nsteps=0;
}

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



NwChemParser::~NwChemParser()
{}

bool NwChemParser::ParseFile(std::streampos pos /*=0*/)
{
  std::cout << "Parsing nwchem file" << std::endl;
  m_file->clear();
  m_file->seekg(pos,std::ios::beg);
  return GetGeometry();
}

bool NwChemParser::GetGeometry()
{
  std::streampos orgpos=m_file->tellg();
  std::string line;
  std::vector<std::streampos> pos;
  //Find the step 0
  while (std::getline(*m_file,line))
  {
    if(line.find("Step") != std::string::npos )
      goto lb1;
  }
lb1:
  std::cout << "Starting" << std::endl;
  while(std::getline(*m_file,line))
  {
	  if (line.find("Optimization converged") != std::string::npos ) return true;
    if (line.find("DFT ENERGY GRADIENTS") != std::string::npos)
    {
      if(!GetGeometryBlock() ) return false;
      GetEnergies();

    }
  }
  if (m_molecule->empty())
  {
    std::cout << "Mirar" << std::endl;
    m_file->clear();
    m_file->seekg(orgpos);
    while(std::getline(*m_file,line))
    {
      if( line.find("Atom information") != std::string::npos )
      {
        std::cout << "Aqui" << std::endl;
        std::getline(*m_file,line);
        std::getline(*m_file,line);
        CMolecule molecule;
        while(std::getline(*m_file,line))
        {
          if(line.find("---")!=std::string::npos) break;
          StringTokenizer token(line," \t\r");
          CAtom atom;
          atom.name=token.at(0);
//          atom.label=token.at(1);
          atom.c.x=strtools::atof(token.at(2))/1.889725989;
          atom.c.y=strtools::atof(token.at(3))/1.889725989;
          atom.c.z=strtools::atof(token.at(4))/1.889725989;
//          std::cout << "atom coordinate is " << atom.name << " " << atom.label << " " << atom.c << std::endl;
          molecule.m_atom.push_back(atom);
        }
        molecule.SetConexions();
        m_molecule->push_back(molecule);
        return true;
      }
    }

  }
  return true;
}

bool NwChemParser::GetGeometryBlock()
{
  //skip three lines
  std::string line;
  for(int i=0;i<3;i++)
  {
    std::getline(*m_file,line);
  }
  CMolecule molecule;
  
  while(std::getline(*m_file,line))
  {
    StringTokenizer token(line," \t\r");
    if(token.size())
    {
      std::cout << token.at(0) << " " << token.at(5) <<  std::endl;
      CAtom atom;
//      atom.label=token.at(0);
      atom.name=token.at(1);
      atom.c.x=atof(token.at(2).c_str());
      atom.c.y=atof(token.at(3).c_str());
      atom.c.z=atof(token.at(4).c_str());
      atom.Gradient().x=atof(token.at(5).c_str());
      atom.Gradient().y=atof(token.at(6).c_str());
      atom.Gradient().z=atof(token.at(7).c_str());
      atom.c/=Quantum::angstromtobohr;
      molecule.m_atom.push_back(atom);
    }
    else break;

  }
  molecule.SetConexions();
  m_molecule->push_back(molecule);
  return true;
}

bool NwChemParser::GetEnergies()
{
  std::string line;
  while(std::getline(*m_file,line))
  {
    if (line.find("Step") != std::string::npos && line.find("Energy")!=std::string::npos)
      break;
  }

  std::getline(*m_file,line);
  CMolecule& molecule=m_molecule->back();
  int nsteps=0;
  while(std::getline(*m_file,line))
  {
    StringTokenizer token(line," \t\r");
    if(token.size() >=8 )
    {
      molecule.SetEnergy(atof(token.at(2).c_str()));
      molecule.SetMaximumForce(atof(token.at(4).c_str()));
      molecule.SetRMSForce(atof(token.at(5).c_str()));
      molecule.SetMaximumDisplacement(atof(token.at(6).c_str()));
      molecule.SetRMSDisplacement(atof(token.at(7).c_str()));
    }
    else break;
  }
  return true;
}

bool NwChemParser::ParseFrequencies(std::streampos pos )
{
  m_file->clear();
  m_file->seekg(pos);
  m_molecule->back().AllocateVectors(true);
  m_counter=0;
  GetVectors();
  GetFrequencies();
}

void NwChemParser::GetVectors()
{
  std::string line;
  while(std::getline(*m_file,line))
  {
    if (line.find("Projected Nuclear Hessian")!=std::string::npos)
      break;
  }
  while(std::getline(*m_file,line))
  {
    if(line.find("P.Frequency") !=std::string::npos)
    {
      StringTokenizer token(line," \t\r");
      GetVectorBlock(token.size()-1);
    }
    if( line.find("Normal Eigenvalue") != std::string::npos) return;
  }


}

bool NwChemParser::GetVectorBlock(int nmodes)
{
  CMolecule& molecule=m_molecule->back();
  //static int counter=0;
  int atom=0;
  std::string line;
  std::getline(*m_file,line);

  while(std::getline(*m_file,line))
  {
    std::cout << line << std::endl;
    StringTokenizer tokenx(line," \t\r");
    if (tokenx.size() < 2 )
    {
      m_counter+=nmodes;
      return true;
    }
    for(int i=0;i<nmodes;i++)
    {
      //std::cout << "atom is " << atom << " mode is " << counter+i << " " << tokenx.at(i+1).c_str() << std::endl;
      molecule.m_atom[atom].mode[m_counter+i].x=atof(tokenx.at(i+1).c_str());
    }
    std::getline(*m_file,line);
     StringTokenizer tokeny(line," \t\r");
    for(int i=0;i<nmodes;i++)
    { 
      molecule.m_atom[atom].mode[m_counter+i].y=atof(tokeny.at(i+1).c_str());
    }
    std::getline(*m_file,line);
    StringTokenizer tokenz(line," \t\r");
    for(int i=0;i<nmodes;i++)
    {
      molecule.m_atom[atom].mode[m_counter+i].z=atof(tokenz.at(i+1).c_str());
    }
    atom++;
  }
  m_counter+=nmodes;
  return true;
}

bool NwChemParser::GetFrequencies()
{
  std::string line;
  while(std::getline(*m_file,line))
  {
    if(line.find("Projected Infra Red Intensities") !=std::string::npos) break;
  }

  std::getline(*m_file,line);
  std::getline(*m_file,line);
  std::vector<frequency>& frequencies=m_molecule->back().GetFrequencies();
  while(std::getline(*m_file,line))
  {
    if(line.find("---") != std::string::npos ) return true;
    StringTokenizer token(line," \t\r");
    frequencies.push_back(frequency(atof(token.at(1).c_str()),atof(token.at(5).c_str())));


  }
}

std::vector<Quantum::jobheader>& NwChemParser::GetJobs()
{
  //lets get the lines beginning with a #
  std::string line;
  std::streampos pos;
  while(std::getline(*m_file,line))
  {

    Quantum::jobtype tjob=Quantum::dens;
    bool bfound=false;

    if(line.find("NWChem Geometry Optimization",0) != std::string::npos)
    {
      tjob=Quantum::opt;
      bfound=true;
    }

    if(line.find(" NWChem Nuclear Hessian and Frequency Analysis",0) != std::string::npos)
    {
      tjob=Quantum::freq;
      bfound=true;
    }

    if (bfound)
    {
      pos=m_file->tellg();
      m_jobpos.push_back(Quantum::jobheader(tjob,pos));
    }
  }

  return m_jobpos;
}
