#include "openbabel/babelconfig.h"
#include <string>
#include <iomanip>
#include <openbabel/mol.h>
#include <openbabel/atom.h>
#include <openbabel/elements.h>
#include "openbabel/obconversion.h"
#include "openbabel/reaction.h"
using namespace std;
namespace OpenBabel
{
class SmiReactFormat : public OBFormat
{
public:
SmiReactFormat()
{
OBConversion::RegisterFormat("rsmi",this);
}
virtual const char* Description()
{
return
"Reaction SMILES format\n"
"Write Options e.g. -xt\n"
" r radicals lower case eg ethyl is Cc\n"
"\n";
}
virtual const char* GetMIMEType()
{ return "chemical/x-daylight-smiles"; };
virtual const char* TargetClassDescription()
{
return OBReaction::ClassDescription();
}
const type_info& GetType()
{
return typeid(OBReaction*);
}
virtual bool ReadMolecule(OBBase* pReact, OBConversion* pConv);
virtual bool WriteMolecule(OBBase* pReact, OBConversion* pConv);
virtual bool ReadChemObject(OBConversion* pConv)
{
OBReaction* pReact = new OBReaction;
bool ret=ReadMolecule(pReact,pConv);
std::string auditMsg = "OpenBabel::Read reaction ";
std::string description(Description());
auditMsg += description.substr(0,description.find('\n'));
obErrorLog.ThrowError(__FUNCTION__,
auditMsg,
obAuditMsg);
if(ret) return pConv->AddChemObject(pReact->DoTransformations(pConv->GetOptions(OBConversion::GENOPTIONS),pConv))!=0;
else
{
pConv->AddChemObject(nullptr);
delete pReact;
pReact=nullptr;
return false;
}
}
virtual bool WriteChemObject(OBConversion* pConv)
{
OBBase* pOb = pConv->GetChemObject();
OBReaction* pReact = dynamic_cast<OBReaction*>(pOb);
if (pReact == nullptr)
return false;
bool ret=false;
ret=WriteMolecule(pReact,pConv);
std::string auditMsg = "OpenBabel::Write reaction ";
std::string description(Description());
auditMsg += description.substr( 0, description.find('\n') );
obErrorLog.ThrowError(__FUNCTION__,
auditMsg,
obAuditMsg);
delete pOb;
return ret;
}
};
SmiReactFormat theSmiReactFormat;
static bool IsNotEndChar(char t)
{
switch (t) {
case '\0':
case '\t':
case ' ':
return false;
}
return true;
}
bool SmiReactFormat::ReadMolecule(OBBase* pOb, OBConversion* pConv)
{
OBReaction* pReact = pOb->CastAndClear<OBReaction>();
istream &ifs = *pConv->GetInStream();
OBConversion sconv; if(!sconv.SetInFormat("smi"))
{
obErrorLog.ThrowError(__FUNCTION__, "Smiles format needed but not found", obError);
return false;
}
string ln, rsmiles, title, s;
string::size_type pos, pos2;
while ((ifs && ifs.peek()=='#') || ifs.peek()=='/')
if(!getline(ifs, ln))
return false;
if(!getline(ifs, ln))
return false;
pos = ln.find_first_of(" \t");
if(pos!=string::npos)
{
rsmiles = ln.substr(0,pos);
title = ln.substr(pos+1);
Trim(title);
pReact->SetTitle(title);
}
else
rsmiles = ln;
pos = rsmiles.find_first_of(",<\"\'!^&_|{}");
if(pos!=string::npos)
{
obErrorLog.ThrowError(__FUNCTION__,
rsmiles + " contained a character '" + rsmiles[pos] + "' which is invalid in SMILES", obError);
return false;
}
pos = rsmiles.find('>');
if(pos==string::npos)
{
obErrorLog.ThrowError(__FUNCTION__, "No > in reaction", obError);
return false;
}
vector<OBMol> mols;
vector<OBMol>::iterator itr;
OBMol jreactants;
s = rsmiles.substr(0,pos);
if(pos > 0 && !sconv.ReadString(&jreactants, s))
{
obErrorLog.ThrowError(__FUNCTION__, "Cannot read reactant", obError);
return false;
}
mols = jreactants.Separate();
for(itr=mols.begin();itr!=mols.end();++itr)
pReact->AddReactant(obsharedptr<OBMol>(new OBMol(*itr)));
pos2 = rsmiles.find('>', pos+1);
if(pos2==string::npos)
{
obErrorLog.ThrowError(__FUNCTION__, "Only one > in reaction", obError);
return false;
}
if(pos2-pos>1)
{
OBMol* pAgent = new OBMol;
s = rsmiles.substr(pos+1,pos2-pos-1);
if(!sconv.ReadString(pAgent, s))
{
obErrorLog.ThrowError(__FUNCTION__, "Cannot read agent", obError);
delete pAgent;
return false;
}
pReact->AddAgent(obsharedptr<OBMol>(pAgent));
}
OBMol jproducts;
s = rsmiles.substr(pos2+1);
if(IsNotEndChar(s[0]) && !sconv.ReadString(&jproducts, s))
{
obErrorLog.ThrowError(__FUNCTION__, "Cannot read product", obError);
return false;
}
mols.clear();
mols = jproducts.Separate();
for(itr=mols.begin();itr!=mols.end();++itr)
pReact->AddProduct(obsharedptr<OBMol>(new OBMol(*itr)));
return true;
}
bool SmiReactFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv)
{
OBReaction* pReact = dynamic_cast<OBReaction*>(pOb);
if (pReact == nullptr)
return false;
ostream &ofs = *pConv->GetOutStream();
OBFormat* pSmiFormat = OBConversion::FindFormat("SMI");
if(!pSmiFormat)
return false;
pConv->AddOption("smilesonly",OBConversion::OUTOPTIONS); pConv->AddOption("c",OBConversion::OUTOPTIONS);
OBMol jReactants;
for(int i=0;i<pReact->NumReactants();++i)
jReactants += *(pReact->GetReactant(i));
if(!pSmiFormat->WriteMolecule(&jReactants, pConv))
return false;
ofs << '>';
OBMol jAgents;
for (int i = 0; i<pReact->NumAgents(); ++i)
jAgents += *(pReact->GetAgent(i));
if(!pSmiFormat->WriteMolecule(&jAgents, pConv))
return false;
ofs << '>';
OBMol jProducts;
for(int i=0;i<pReact->NumProducts();++i)
jProducts += *(pReact->GetProduct(i));
if(!pSmiFormat->WriteMolecule(&jProducts, pConv))
return false;
if(!pReact->GetTitle().empty())
ofs << '\t' << pReact->GetTitle();
ofs << endl;
return true;
}
}