/***************************************************************************
 *   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 <stdlib.h>

#include "gamessparser.h"
#include "molecule.h"
#include "tokenizer.h"

const double bohrtoangs=0.529189379;

GamessParser::GamessParser ( const char* file )
    : QuantumParser ( file )
{}

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


GamessParser::~GamessParser()
{}

bool GamessParser::ParseFile ( std::streampos pos )
{
  m_file->clear();
  m_file->seekg ( pos,std::ios::beg );
  return GetGeometry();

}

bool GamessParser::GetGeometry()
{
  std::string line;
  std::vector<std::streampos> pos;
  bool bfound=false;
  bool bbohr=true;

  while ( std::getline ( *m_file,line ) )
  {

    if ( line.find ( "COORDINATES",0 ) != std::string::npos && line.find ( "INTERNAL" ) == std::string::npos ) //this is for optimizations
    {
      short skiplines=2;
      if ( line.find ( "BOHR",0 ) != std::string::npos )
      {
        bbohr=true;
        skiplines=1;
      }
      bfound=true;
      // pos=m_file.tellg();
      for ( int i=0;i<skiplines;i++ )
      {
        std::getline ( *m_file,line );

      }
      pos.push_back ( m_file->tellg() );

    }
  }

  if ( !bfound )
    return false;

  std::vector<std::streampos>::iterator pt;
  for ( pt=pos.begin();pt!=pos.end();pt++ )
  {
    m_file->clear();
    m_file->seekg ( *pt,std::ios::beg );
    CMolecule molecule;
    int counter=0;
    std::stringstream s;
    while ( std::getline ( *m_file,line ) )
    {
      StringTokenizer token ( line," " );
      size_t size=token.size();

      if ( size >= 5 )
      {
        CAtom atom;
        s << ++counter;
        //atom.label=s.str();
        atom.name=CMolecule::GetAtomName ( std::atoi ( token.at ( 1 ).c_str() ) );
        atom.c.x=std::atof ( token.at ( size-3 ).c_str() );
        atom.c.y=std::atof ( token.at ( size-2 ).c_str() );
        atom.c.z=std::atof ( token.at ( size-1 ).c_str() );

        if ( bbohr ) std::cerr << "in bohrs" << std::endl;
        if ( bbohr ) atom.c*=bohrtoangs;

        molecule.m_atom.push_back ( atom );



      }

      else
        break;
    }

    /* bool bbreak=false;
     while(std::getline(*m_file,line))
     {
       StringTokenizer token(line," ");
       if( token.size() >= 4 )
       {
         switch(m_level)
    {
    case Quantum::MP2:
    if( token.size() >= 5 )
    if(token[3]=="E(UMP2")
    molecule.SetEnergy(atof(token[4].c_str()));
    break;
    case Quantum::QCISD:

    if( token[2]=="E(CORR)=" )
    {std::cerr << "getting qcisd" << " " << token[3] << " " <<strtools::atof(token[3]) << std::endl;
     molecule.SetEnergy(strtools::atof(token[3]));
     }
    break;

    case Quantum::HF:
    default:
    if( token.size() >= 5 )
         if (token[0]=="SCF" && token[1]=="Done:" )
         {
           molecule.SetEnergy(atof(token[4].c_str()));
           std::cerr << "SCF=" << molecule.GetEnergy() << std::endl;
         }
    break;
    }

         if( token[0]=="Maximum" && token[1] =="Force" )
           molecule.SetMaximumForce(atof(token[2].c_str()));

         if( token[0]=="RMS" && token[1] =="Force" )
           molecule.SetRMSForce(atof(token[2].c_str()));

         if( token[0]=="Maximum" && token[1] =="Displacement" )
           molecule.SetMaximumDisplacement(atof(token[2].c_str()));

         if( token[0]=="RMS" && token[1] =="Displacement" )
         {
           molecule.SetRMSDisplacement(atof(token[2].c_str()));
          bbreak=true;

         }
       }
       if (bbreak) break;



     }*/
    m_molecule->push_back ( molecule );
    m_molecule->back().SetConexions();
  }

  return true;
}

// bool GamessParser::ParseFrequencies(std::streampos pos)
// {
//   m_file->clear();
//   m_file->seekg(pos,std::ios::beg);
//   CMolecule& molecule=m_molecule->back();
//   molecule.AllocateForces();
//   molecule.AllocateHessian();
//   std::string line;
//   while( std::getline(*m_file,line))
//  {
//
//    if( line.find("CARTESIAN FORCE CONSTANT MATRIX")!= std::string::npos) break;
//  }
//
//
//
//   while(std::getline(*m_file,line))
//   {
//     if(line.find("ALPHA POLARIZABILITY") != std::string::npos) break;
//
//     if( line.find("X        Y        Z") != std::string::npos)
//        GetBlock();
//   }
//    IBArray<double>& hessian=molecule.GetHessian();
//  /* for(size_t i=0;i<hessian.rows();i++)
//      for(size_t j=0;j<hessian.columns();j++)
//         std::cout << "hessian(" << i << "," << j << ")=" << hessian(i,j) << std::endl;*/
//   molecule.CalculateFrequencies();
//   return true;
// }

bool GamessParser::ParseFrequencies ( std::streampos pos )
{

  m_file->clear();
  m_file->seekg ( pos/*pos,std::ios::beg*/ );
  CMolecule& molecule=m_molecule->back();
  molecule.AllocateVectors ( true );
  std::vector<frequency>& frequencies=molecule.GetFrequencies();
  std::string line;
  while ( std::getline ( *m_file,line ) )
  {
    if ( line.find ( "IR INTENSITIES IN DEBYE" ) != std::string::npos ) break;
  }
  std::streampos fpos=m_file->tellg();
  int counter=0;
  m_counter=0;
  while ( std::getline ( *m_file,line ) )
  {
    if ( line.find ( "FREQUENCY" ) != std::string::npos )
    {
      StringTokenizer tok ( line," \t\n\r" );
      StringTokenizer::iterator tt;
      for ( tt=tok.begin() +1;tt!=tok.end();++tt )
      {
        frequencies.push_back ( frequency ( atof ( tt->c_str() ),0 ) );
      }
    }
    if ( line.find ( "IR INTENSITY" ) != std::string::npos )
    {
      StringTokenizer tok ( line," \t\n\r" );
      StringTokenizer::iterator tt;
      for ( tt=tok.begin() +2;tt!=tok.end();++tt )
      {
        frequencies.at ( counter++ ).y=atof ( tt->c_str() );
      }
      std::getline ( *m_file,line );
      GetVectorsBlock();
    }

    if ( line.find ( "REFERENCE ON SAYVETZ CONDITIONS" ) != std::string::npos )
    {
      GetVectorsBlock();
      return true;
    }
  }

  return false;
}

void GamessParser::GetVectorsBlock()
{
  std::string line;
  int i=0;
  int natom=0;
  CMolecule& molecule=m_molecule->back();

  int nfreq=0;
  while ( std::getline ( *m_file,line ) )
  {
    if ( line.find ( "X" ) == std::string::npos && line.find ( "Y" ) == std::string::npos && line.find ( "Z" ) == std::string::npos )
    {
      m_counter+=nfreq;
      return;
    }

    if ( i == 3 )
    { i=0; natom++; }


    StringTokenizer tok ( line," \t\n\r" );

    if ( i== 0 )
    {
      nfreq=tok.size()-3;
    }
    else
      nfreq=tok.size()-1;

    int scounter=m_counter;
    for ( int j=0;j<nfreq;j++ )
    {

      //double d=atof(tok.at(j+3).c_str());
      switch ( i )
      {
        case 0:
          molecule.m_atom.at ( natom ).mode.at ( scounter++ ).x=atof ( tok.at ( j+3 ).c_str() );
          break;
        case 1:
          molecule.m_atom.at ( natom ).mode.at ( scounter++ ).y=atof ( tok.at ( j+1 ).c_str() );
          break;
        case 2:
          molecule.m_atom.at ( natom ).mode.at ( scounter++ ).z=atof ( tok.at ( j+1 ).c_str() );
          break;
        default:
          break;
      }
    }
    i++;
    //counter++;
  }
}



// void GamessParser::GetBlock()
// {
//   CMolecule& molecule=m_molecule->back();
//   IBArray<double>& hessian=molecule.GetHessian();
//
//   static int rowatom=0;
//   static int colatom=0;
//   int row=0;
//   int col=0;
//   std::string line;
//   while(std::getline(*m_file,line))
//   {
//     if( line.size() < 5 ) break;
//     size_t pos=20;
//     for(int i=0;i<6;i++,pos+=10)
//       line.insert(pos," ");
//     StringTokenizer token(line," \t");
//     StringTokenizer::iterator it;
//     for(it=token.begin()+3;it!=token.end();it++,col++)
//     {
//       hessian(rowatom*3+row,colatom*3+col)=atof(it->c_str());
//       std::cout << "hessian(" << rowatom*3+row << "," << colatom*3+col << ")=" << hessian(rowatom*3+row,colatom*3+col) << std::endl;
//
//     }
//     row++;
//     col=0;
//
//   }
//
//   colatom+=2;
//   rowatom+=row/3;
// }

std::vector<Quantum::jobheader>& GamessParser::GetJobs()
{
  std::string line;
  Quantum::jobtype tjob=Quantum::dens;
  while ( std::getline ( *m_file,line ) )
  {
    if ( line.find ( "$CONTRL OPTIONS" ) != std::string::npos )
      break;
  }

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

  if ( line.find ( "RUNTYP=HESSIAN" ) != std::string::npos )
    tjob=Quantum::freq;
  if ( line.find ( "RUNTYP=OPTIMIZE" ) != std::string::npos )
    tjob=Quantum::opt;

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

  return m_jobpos;

}

