//
//  Copyright (C) 2002-2013 Greg Landrum, Rational Discovery LLC
//
//   @@ All Rights Reserved @@
//  This file is part of the RDKit.
//  The contents are covered by the terms of the BSD license
//  which is included in the file license.txt, found at the root
//  of the RDKit source tree.
//
#ifndef _RD_FILEPARSERS_H
#define _RD_FILEPARSERS_H

#include <RDGeneral/types.h>
#include <GraphMol/RDKitBase.h>

#include <string>
#include <iostream>
#include <vector>
#include <exception>

#include <boost/shared_ptr.hpp>

namespace RDKit{
  const int MOLFILE_MAXLINE=256;
  std::string strip(const std::string &orig);

  //-----
  // mol files
  //-----
  typedef std::vector< RWMOL_SPTR > RWMOL_SPTR_VECT;
  // \brief construct a molecule from MDL mol data in a stream
  /*! 
   *   \param inStream - stream containing the data
   *   \param line     - current line number (used for error reporting)
   *   \param sanitize - toggles sanitization and stereochemistry
   *                     perception of the molecule
   *   \param removeHs - toggles removal of Hs from the molecule. H removal
   *                     is only done if the molecule is sanitized
   *   \param line     - current line number (used for error reporting)
   *   \param strictParsing - if not set, the parser is more lax about correctness
   *                          of the contents.
   *                          
   */
  RWMol *MolDataStreamToMol(std::istream *inStream, unsigned int &line,
			    bool sanitize=true,bool removeHs=true,
                            bool strictParsing=true);
  // \overload
  RWMol *MolDataStreamToMol(std::istream &inStream, unsigned int &line,
			    bool sanitize=true,bool removeHs=true,
                            bool strictParsing=true);
  // \brief construct a molecule from an MDL mol block
  /*! 
   *   \param molBlock - string containing the mol block
   *   \param sanitize - toggles sanitization and stereochemistry
   *                     perception of the molecule
   *   \param removeHs - toggles removal of Hs from the molecule. H removal
   *                     is only done if the molecule is sanitized
   *   \param strictParsing - if set, the parser is more lax about correctness
   *                          of the contents.
   */
  RWMol *MolBlockToMol(const std::string &molBlock, bool sanitize=true,
                       bool removeHs=true,bool strictParsing=true);
  
  // \brief construct a molecule from an MDL mol file
  /*! 
   *   \param fName    - string containing the file name
   *   \param sanitize - toggles sanitization and stereochemistry
   *                     perception of the molecule
   *   \param removeHs - toggles removal of Hs from the molecule. H removal
   *                     is only done if the molecule is sanitized
   *   \param strictParsing - if set, the parser is more lax about correctness
   *                          of the contents.
   */
  RWMol *MolFileToMol(const std::string &fName, bool sanitize=true,
                      bool removeHs=true,bool strictParsing=true);

  // \brief generates an MDL mol block for a molecule
  /*! 
   *   \param mol           - the molecule in question
   *   \param includeStereo - toggles inclusion of stereochemistry information
   *   \param confId        - selects the conformer to be used
   *   \param kekulize      - triggers kekulization of the molecule before it is written
   *   \param forceV3000    - force generation a V3000 mol block (happens automatically with
   *                          more than 999 atoms or bonds)
   */
  std::string MolToMolBlock(const ROMol &mol,bool includeStereo=true,
                            int confId=-1,bool kekulize=true,bool forceV3000=false);
  // \brief Writes a molecule to an MDL mol file
  /*! 
   *   \param mol           - the molecule in question
   *   \param fName         - the name of the file to use
   *   \param includeStereo - toggles inclusion of stereochemistry information
   *   \param confId        - selects the conformer to be used
   *   \param kekulize      - triggers kekulization of the molecule before it is written
   *   \param forceV3000    - force generation a V3000 mol block (happens automatically with
   *                          more than 999 atoms or bonds)
   */
  void MolToMolFile(const ROMol &mol,const std::string &fName,bool includeStereo=true,
                    int confId=-1,bool kekulize=true,bool forceV3000=false);


  //-----
  //  TPL handling:
  //-----

  //! \brief translate TPL data (BioCad format) into a multi-conf molecule
  /*!
    \param inStream:      the stream from which to read
    \param line:          used to track the line number of errors
    \param sanitize:      toggles sanitization and stereochemistry
                          perception of the molecule
    \param skipFirstConf: according to the TPL format description, the atomic
                          coords in the atom-information block describe the first
			  conformation and the first conf block describes second 
			  conformation. The CombiCode, on the other hand, writes
			  the first conformation data both to the atom-information 
                          block and to the first conf block. We want to be able to
			  read CombiCode-style tpls, so we'll allow this mis-feature
			  to be parsed when this flag is set.
  */
  RWMol *TPLDataStreamToMol(std::istream *inStream, unsigned int &line,
			    bool sanitize=true,
                            bool skipFirstConf=false);

  //! \brief construct a multi-conf molecule from a TPL (BioCad format) file
  /*!
    \param fName:         the name of the file from which to read
    \param sanitize:      toggles sanitization and stereochemistry
                          perception of the molecule
    \param skipFirstConf: according to the TPL format description, the atomic
                          coords in the atom-information block describe the first
			  conformation and the first conf block describes second 
			  conformation. The CombiCode, on the other hand, writes
			  the first conformation data both to the atom-information 
                          block and to the first conf block. We want to be able to
			  read CombiCode-style tpls, so we'll allow this mis-feature
			  to be parsed when this flag is set.
  */
  RWMol *TPLFileToMol(const std::string &fName,bool sanitize=true,
                      bool skipFirstConf=false);

  std::string MolToTPLText(const ROMol &mol,
			   const std::string &partialChargeProp="_GasteigerCharge",
			   bool writeFirstConfTwice=false);
  void MolToTPLFile(const ROMol &mol,const std::string &fName,
		    const std::string &partialChargeProp="_GasteigerCharge",
		    bool writeFirstConfTwice=false);

  //-----
  //  MOL2 handling
  //-----

  typedef enum {
    CORINA=0  //! supports output from Corina and some dbtranslate output
  } Mol2Type;

  // \brief construct a molecule from a Tripos mol2 file
  /*! 
   *
   *   \param fName    - string containing the file name
   *   \param sanitize - toggles sanitization of the molecule
   *   \param removeHs - toggles removal of Hs from the molecule. H removal
   *                     is only done if the molecule is sanitized
   *   \param variant  - the atom type definitions to use
   */
  RWMol *Mol2FileToMol(const std::string &fName,bool sanitize=true,bool removeHs=true,
                       Mol2Type variant=CORINA);

  // \brief construct a molecule from Tripos mol2 data in a stream
  /*!  
   *   \param inStream - stream containing the data
   *   \param sanitize - toggles sanitization of the molecule
   *   \param removeHs - toggles removal of Hs from the molecule. H removal
   *                     is only done if the molecule is sanitized
   *   \param variant  - the atom type definitions to use
   */
  RWMol *Mol2DataStreamToMol(std::istream *inStream,bool sanitize=true,bool removeHs=true,
                             Mol2Type variant=CORINA);
  // \overload 
  RWMol *Mol2DataStreamToMol(std::istream &inStream,bool sanitize=true,bool removeHs=true,
                             Mol2Type variant=CORINA);

  // \brief construct a molecule from a Tripos mol2 block
  /*! 
   *   \param molBlock - string containing the mol block
   *   \param sanitize - toggles sanitization of the molecule
   *   \param removeHs - toggles removal of Hs from the molecule. H removal
   *                     is only done if the molecule is sanitized
   *   \param variant  - the atom type definitions to use
   */
  RWMol *Mol2BlockToMol(const std::string &molBlock,bool sanitize=true,bool removeHs=true,
                        Mol2Type variant=CORINA);

  RWMol *PDBBlockToMol(const char *str, bool sanitize=true,
                       bool removeHs=true, unsigned int flavor=0);

  RWMol *PDBBlockToMol(const std::string &str, bool sanitize=true,
                       bool removeHs=true, unsigned int flavor=0);
  RWMol *PDBDataStreamToMol(std::istream *inStream, bool sanitize=true,
                            bool removeHs=true, unsigned int flavor=0);
  RWMol *PDBDataStreamToMol(std::istream &inStream, bool sanitize=true,
                            bool removeHs=true, unsigned int flavor=0);
  RWMol *PDBFileToMol(const std::string &fname, bool sanitize=true,
                      bool removeHs=true, unsigned int flavor=0);

  // \brief generates an PDB block for a molecule
  /*! 
   *   \param mol           - the molecule in question
   *   \param confId        - selects the conformer to be used
   *   \param flavor        - controls what gets written:
   *         flavor & 1 : Write MODEL/ENDMDL lines around each record
   *         flavor & 2 : Don't write any CONECT records
   *         flavor & 4 : Write CONECT records in both directions
   *         flavor & 8 : Don't use multiple CONECTs to encode bond order
   *         flavor & 16 : Write MASTER record
   *         flavor & 32 : Write TER record
   */
  std::string MolToPDBBlock(const ROMol &mol, int confId=-1, unsigned int flavor=0);
  // \brief Writes a molecule to an MDL mol file
  /*! 
   *   \param mol           - the molecule in question
   *   \param fName         - the name of the file to use
   *   \param confId        - selects the conformer to be used
   *   \param flavor        - controls what gets written:
   *         flavor & 1 : Write MODEL/ENDMDL lines around each record
   *         flavor & 2 : Don't write any CONECT records
   *         flavor & 4 : Write CONECT records in both directions
   *         flavor & 8 : Don't use multiple CONECTs to encode bond order
   *         flavor & 16 : Write MASTER record
   *         flavor & 32 : Write TER record
   */
  void MolToPDBFile(const ROMol &mol,const std::string &fname, int confId=-1, unsigned int flavor=0);
}

#endif
