/***************************************************************************
 *   Copyright (C) 2004 by Armando Navarro-Vazquez                         *
 *   qoajnv@usc.es                                                         *
 *                                                                         *
 *   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 <sstream>

#include "acesparser.h"
#include "tokenizer.h"
#include "molecule.h"
const double bohrtoangs=0.529189379;
AcesParser::AcesParser(const char* file)
    : QuantumParser(file)
{}

AcesParser::AcesParser(std::istream* stream) : QuantumParser(stream)
{
  std::cout << "ACESII Mainz//CFOUR Parser" << std::endl;
}

AcesParser::~AcesParser()
{}

bool AcesParser::ParseFile(std::streampos pos)
{
  m_file->clear();
  m_file->seekg(pos,std::ios::beg);
  m_level=GetLevel();
  std::cerr << "passed get level" << std::endl;
  return GetGeometry();
}

bool AcesParser::GetGeometry()
{

  std::string line;
  bool bfound=false;
  std::vector<std::streampos> pos;
  while(std::getline(*m_file,line))
  {
    StringTokenizer tok(line," ");
    if( tok.size() >= 2)
    {
      if( tok[0]=="Z-matrix" && tok[1]=="Atomic")
      {
        std::cerr << "found" << std::endl;
        bfound=true;
        pos.push_back(m_file->tellg());

      }

    }
  }

  std::cerr << "In Aces Parser" << std::endl;

  if(!bfound) return false;

  std::cerr << "found" << std::endl;
  std::vector<std::streampos>::iterator pt;
  for(pt=pos.begin();pt!=pos.end();pt++)
  {
    m_file->clear();
    m_file->seekg(*pt,std::ios::beg);
    std::getline(*m_file,line);
    std::getline(*m_file,line);
    CMolecule molecule;

    int counter=0;
    while(std::getline(*m_file,line))
    {
      StringTokenizer token(line," ");
      size_t size=token.size();
      //  std::cerr << line  << std::endl;
      if( size == 5  )
      {
	if ( token.at(0) != "X" )
	{
        std::cerr << line  << std::endl;
        CAtom atom;
        std::stringstream l;
        l << ++counter;
//        atom.label=l.str();
        atom.name=token[0];
        //Aces writes all atoms as uppercase
        if(atom.name.size() > 1)
        {
          atom.name.at(1)=std::tolower(atom.name.at(1),std::cout.getloc());
        }
        atom.c.x=atof(token[size-3].c_str())*bohrtoangs;
        atom.c.y=atof(token[size-2].c_str())*bohrtoangs;
        atom.c.z=atof(token[size-1].c_str())*bohrtoangs;
        molecule.m_atom.push_back(atom);
	}	

      }

      else
        break;


    }
    while(std::getline(*m_file,line))
    {
      bool bfound=false;
      StringTokenizer token(line," ");
      switch(m_level)
      {
      case Quantum::HF:
        if(line.find("E(SCF)")!=std::string::npos)
        {
          StringTokenizer token(line," ");
          molecule.SetEnergy(strtools::atof(token.at(1)));
        }
        break;
      case Quantum::CCSD:
         if ( line.find("Total CCSD energy") != std::string::npos )
	 {
		StringTokenizer token(line, " \t\r");
		molecule.SetEnergy(strtools::atof(token.back()));
	 }
	 break;
      case Quantum::CCSDT:
        if( token.size() == 3 )
          if( token.at(0)=="CCSD(T)" &&  ( token.at(1)=="=" || token.at(1)=="energy" ) )
            molecule.SetEnergy(strtools::atof(token.back()));
        break;
      default:
        break;

      }
      if(line.find("Minimum force",0)!=std::string::npos)
      {
        StringTokenizer token(line," ");
        molecule.SetRMSForce(strtools::atof(token.back()));
        if(token.size() > 2 )
          molecule.SetMaximumForce(strtools::atof( token.at(2) ));
        bfound=true;
      }
      if(bfound) break;
    }

    molecule.SetConexions();
    std::cerr << molecule;
    m_molecule->push_back(molecule);


  }

  return true;
}

Quantum::level AcesParser::GetLevel()
{
  std::string line;
  while(std::getline(*m_file,line))
  {
    if(line.find("CALCLEVEL",0)!=std::string::npos)
      break;
  }

  StringTokenizer token(line," []");

  StringTokenizer::reverse_iterator it=token.rbegin();
  it++;

  std::string level;
  if(it!=token.rend())
    level=(*it);


  //leave in a good state
  m_file->clear();
  m_file->seekg(0,std::ios::beg);

  std::cerr << "leaving get level=" << level << std::endl;
  if(level=="22") return Quantum::CCSDT;
  if ( level == "10" ) return Quantum::CCSD;
  if(level=="0") return Quantum::HF;
  if(level=="1") return Quantum::MP2;

  return Quantum::HF;

}


bool AcesParser::ParseFrequencies(std::streampos pos)
{
  m_file->clear();
  m_file->seekg(pos,std::ios::beg);

  CMolecule& molecule=m_molecule->back();
  molecule.AllocateVectors();
  std::vector<frequency>& frequencies=molecule.GetFrequencies();
  //frequencies.reserve(3*molecule.m_atom.size()-5);
  m_counter=0;
  GetFrequencies();

  GetVectors();
}

void AcesParser::GetFrequencies()
{
  CMolecule& molecule=m_molecule->back();
  std::vector<frequency>& frequencies=molecule.GetFrequencies();
  std::string line;

  while(std::getline(*m_file,line))
  {
    if(line.find("Representation       Frequency ") != std::string::npos)
      break;
  }
  for(int i=0;i<3;i++)
    std::getline(*m_file,line);

  while(std::getline(*m_file,line))
  {
    StringTokenizer token(line," \t");
    if ( token.size() < 4 ) break;
    if( token.back() == "VIBRATION")
    {
      frequencies.push_back(frequency( atof(token.at(1).c_str()),atof(token.at(2).c_str()),0));
 //     std::cout << "frequency pushed" << std::endl;
    }
  }

}

void AcesParser::GetVectors()
{
  std::string line;
  while(std::getline(*m_file,line))
  {
   // if(line.find("X       Y       Z") != std::string::npos)
    if ( line.find("VIBRATION") != std::string::npos )
    {
      
      StringTokenizer token(line," \t\r");
      if( !GetVectorBlock(token.size()) ) break;
    }

  }

}

bool AcesParser::GetVectorBlock(int nmodes)
{
  CMolecule& molecule=m_molecule->back();
  int atom=0;
  std::string line;
  //for(size_t k=0;k<molecule.m_atom.size();k++)
   // std::cout << "vector size is " << molecule.m_atom.size() << "  " << molecule.m_atom[k].mode.size() << std::endl;
 
  std::getline(*m_file,line);
  if ( line.find("X       Y       Z") != std::string::npos ) std::getline(*m_file,line); 
do
{
   // std::cout << "the line is " << line << std::endl;
    if (line.find("Gradient vector in normal") != std::string::npos) return false;
    //There is a bug in ACES formatting so insert a space after 12th character
    if(line.size() > 13 ) line.insert(13," ");
    //if(line.empty()) break;
    StringTokenizer token(line," \t");
    if( token.size() < 4) break;
    for(int j=0;j<nmodes;j++)
    {
    //  std::cout << "mode is " << m_counter+j << " " << atom << std::endl;
      molecule.m_atom[atom].mode[m_counter+j].x=atof(token.at(1+3*j).c_str());
      molecule.m_atom[atom].mode[m_counter+j].y=atof(token.at(2+3*j).c_str());
      molecule.m_atom[atom].mode[m_counter+j].z=atof(token.at(3+3*j).c_str());
    }
    atom++;

  } while (std::getline(*m_file,line) );

  m_counter+=nmodes;
  return true;
}

std::vector<Quantum::jobheader>& AcesParser::GetJobs()
{
  //lets get the lines beginning with a #
  std::string line;
  std::streampos pos;
  bool secondev=false;
  bool bsp=false;
  Quantum::jobtype tjob=Quantum::dens;
  while(std::getline(*m_file,line))
  {
    if(line.find("DERIV_LEV")!=std::string::npos)
    {
      StringTokenizer token(line," \t");
      if( token.at(2) == "SECOND" ) secondev=true;
    }
#ifdef __GNUC__
#warning Is this really true
#endif
    if( line.find("GEO_METHOD") != std::string::npos)
    {
  
      bsp= ( line.find( "SINGLE_POINT" ) != std::string::npos ); 
      if(!bsp)
        tjob=Quantum::opt;
      else
        if(secondev==true) tjob=Quantum::freq;

      m_jobpos.push_back(Quantum::jobheader(tjob,0));

    }
    
    if( !m_jobpos.empty() ) break;
  }

  return m_jobpos;
}
