/***************************************************************************
 *   Copyright (C) 2004 by Armando Navarro-Vázquez                         *
 *   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 "pdbparser.h"
#include "molecule.h"
#include "tokenizer.h"


#ifdef HAVE_OPEN_BABEL
#include <sstream>
#include <openbabel-2.0/openbabel/obconversion.h>
#include "xyzparser.h"
using  namespace OpenBabel;
#endif

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

PDBParser::PDBParser(std::istream* stream) : QuantumParser(stream)
{

}

PDBParser::~PDBParser()
{}

bool PDBParser::ParseFile(std::streampos pos)
{

  m_file->seekg(0,std::ios::beg);


  std::string line;


  std::vector<std::streampos> spos;
  while(std::getline(*m_file,line))
  {
    if( line.find("MODEL") != std::string::npos)
      spos.push_back(m_file->tellg());
  }
  if( spos.empty() )  //only one structure
  { spos.push_back(0); }

  std::vector<std::streampos>::iterator it;
  for(it=spos.begin();it!=spos.end();it++)
  {
    CMolecule molecule;
    int atomnumber=0;
    m_file->clear();
    m_file->seekg(*it,std::ios::beg);
    //First count the atoms
    while(std::getline(*m_file,line))
    {

      StringTokenizer token(line);
      size_t i;
      for(i=0;i<token.size();i++)
      {
        if(token[i]=="HETATM" || token[i]=="ATOM" /*|| token[i]=="TER"*/ ) //Do the stuff
        {
          atomnumber++;
        }


      }
      if( line.find("MODEL") != std::string::npos) break;
    }

    molecule.m_atom.resize(atomnumber);


    bool reorganize=false;  
    bool bconected=false;

lb1:
    m_file->clear();
    m_file->seekg(*it,std::ios::beg);

    //Now parse again, labels will be the same as atom numbering


    int n=-1;

    while(std::getline(*m_file,line))
    {
      StringTokenizer token(line);
      size_t i;
      for(i=0;i<token.size();i++)
      {
        if(token[i]=="HETATM" || token[i]=="ATOM") //Do the stuff
        {
          if(!reorganize)
           n=atoi(token.at(i+1).c_str())-1;
          else
           n++;
          //We cannot deal with gaps in the list
          if ( n >= atomnumber)
          { reorganize=true; 
            goto lb1;
          }
          std::cout << "n=" << n << std::endl;
//          molecule.m_atom[n].label=token.at(i+1);
          std::string name=token.at(i+2);
          std::string nn=ExtractAtomName(RemoveNumbers(name));
          std::cout << "name is " << nn << std::endl;
          molecule.m_atom[n].name=nn;
          //maybe is a columm with aditional information babel files seem to incoporate it
          int c=0;

          while(token[i+3+c].find(".")==std::string::npos)
          {
            c++;
          }

          molecule.m_atom[n].c.x=atof(token.at(i+3+c).c_str());
          molecule.m_atom[n].c.y=atof(token.at(i+4+c).c_str());
          molecule.m_atom[n].c.z=atof(token.at(i+5+c).c_str());

        }

        if(token[i]=="TER")
        {
          //Better do nothing
          /*int n=atoi(token.at(i+1).c_str())-1;
          molecule.m_atom.at(n).label="ter";
          molecule.m_atom.at(n).name="X";
          molecule.m_atom.at(n).c.x=0.0f;
          molecule.m_atom.at(n).c.y=0.0f;
          molecule.m_atom.at(n).c.z=0.0f;*/

        }

      }
      if( line.find("MODEL") != std::string::npos) break;
    }
    std::cout << molecule << std::endl;
    molecule.CalculateMassCenter();
    molecule.SetConexions();

    m_molecule->push_back(molecule);
  }

  return true;

}

std::string PDBParser::ExtractAtomName(const std::string& s)
{
//   PeriodicTable::const_iterator it;
//   //std::vector<PeriodicTable::const_iterator> atomnames;
//    PeriodicTable::const_iterator atomname=GetPeriodicTable().end();
//   //std::vector<size_t> cpos;
//   for(it=GetPeriodicTable().begin();it!=GetPeriodicTable().end();++it)
//   {
//     size_t p;
//     if ( p=s.find(const_cast<std::string&>(it->first),0) == 0 )
//     {
//       //atomnames.push_back(it);
//       if ( atomname != GetPeriodicTable().end() )
//       {
//         if ( it->first.size() > atomname->first.size() )
//          { 
//            atomname=it;
//            goto lb1;
//          }         
//       }
//       else      
//         atomname=it;
// 
//       //cpos.push_back(s.find(p,0));
//     }
// 
//    // if( atomnames.size() == 1 ) break;
//   }
// lb1:
//   //if ( atomnames.size() >= 1 ) return atomnames.at(0)->first;
//  // if ( atomnames.empty() ) return "X";
//      if ( atomname != GetPeriodicTable().end() )
//        return atomname->first;
//      else return "X";


  PeriodicTable::const_iterator it;
  std::vector<PeriodicTable::const_iterator> atomnames;
  std::vector<size_t> cpos;
  for(it=GetPeriodicTable().begin();it!=GetPeriodicTable().end();++it)
  {
    size_t p;
    if ( p=s.find(const_cast<std::string&>(it->first),0) == 0 )
    {
      atomnames.push_back(it);
      cpos.push_back(s.find(p,0));
    }

    if( atomnames.size() == 1 ) break;
  }

  if ( atomnames.size() >= 1 ) return atomnames.at(0)->first;
  if ( atomnames.empty() ) return "X";
}

std::string  PDBParser::RemoveNumbers(std::string& s)
{
    size_t pos=s.find_first_of("0123456789");
    return s.substr(0,pos);
      
}
