/* 
(C) 2022 Cadence Design Systems, Inc. (Cadence) 
All rights reserved.
TERMS FOR USE OF SAMPLE CODE The software below ("Sample Code") is
provided to current licensees or subscribers of Cadence products or
SaaS offerings (each a "Customer").
Customer is hereby permitted to use, copy, and modify the Sample Code,
subject to these terms. Cadence claims no rights to Customer's
modifications. Modification of Sample Code is at Customer's sole and
exclusive risk. Sample Code may require Customer to have a then
current license or subscription to the applicable Cadence offering.
THE SAMPLE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED.  OPENEYE DISCLAIMS ALL WARRANTIES, INCLUDING, BUT
NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. In no event shall Cadence be
liable for any damages or liability in connection with the Sample Code
or its use.
*/
#include "openeye.h"
#include "oefastrocs.h"
#include "oechem.h"
#include "oesystem.h"

using namespace OEFastROCS;
using namespace OEChem;
using namespace OESystem;
using namespace std;

int main(int argc, char *argv[]) 
{
  if(argc < 3) 
  {
    OEThrow.Usage("%s <database> [<queries. ... ]", argv[0]);
    return 0;
  }

  // read in database
  string dbname = argv[1];
  if (OEIsGZip(dbname.c_str()))
    OEThrow.Fatal("%s is an unsupported database file format as it is gzipped.\n"
    "Preferred formats are .oeb, .sdf or .oez", dbname.c_str());

  oemolistream ifs;
  if(!ifs.open(dbname))
    OEThrow.Fatal("Unable to open '" + dbname + "'");

  OEThrow.Info("Opening database file " + dbname);
  OEWallTimer timer;
  OEShapeDatabase dbase;
  OEMolDatabase moldb;

  if(!moldb.Open(ifs))
    OEThrow.Fatal("Unable to open '" + dbname + "'");

  OEThreadedDots dots(10000, 200, "conformers");
  if(!dbase.Open(moldb, dots))
    OEThrow.Fatal("Unable to initialize OEShapeDatabase on '" + dbname + "'");

  dots.Total();
  OEThrow.Info("%f seconds to load database" , timer.Elapsed());

  OEShapeDatabaseOptions opts;
  opts.SetSimFunc(OEShapeSimFuncType::Tversky);
  unsigned int numHits = moldb.NumMols();
  opts.SetLimit(numHits);

  for(int i = 2; i < argc; ++i) 
  {
    // read in query
    string qfname = argv[i];

    oemolistream qfs;
    if(!qfs.open(qfname.c_str()))
      OEThrow.Fatal("Unable to open '" + qfname + "'");

    OEGraphMol query;
    if(!OEReadMolecule(qfs, query))
      OEThrow.Fatal("Unable to read query from '" + qfname + "'");

    string ext = OEGetFileExtension(qfname.c_str());
    string base = qfname.substr(0, (qfname.length() - ext.length() - 1));

    // write out everything to a similarly named file
    oemolostream ofs;
    string ofname = base + "_results." + ext;
    if(!ofs.open(ofname))
      OEThrow.Fatal("Unable to open '" + ofname + "'");

    OEThrow.Info("Searching for " + qfname);
    OEIter<OEShapeDatabaseScore> score = dbase.GetSortedScores(query, opts);
    for(; score; ++score) 
    {
      OEMol dbmol;
      unsigned int molidx = (unsigned) score->GetMolIdx();
      if(!moldb.GetMolecule(dbmol, molidx)) 
      {
        OEThrow.Warning("Unable to retrieve molecule %u from the database", molidx);
        continue;
      }

      OEGraphMol mol(*dbmol.GetConf(OEHasConfIdx(score->GetConfIdx())));
      OESetSDData(mol, "ShapeTversky", OENumberToString(score->GetShapeTversky()));
      OESetSDData(mol, "ColorTversky", OENumberToString(score->GetColorTversky()));
      OESetSDData(mol, "TverskyCombo", OENumberToString(score->GetTverskyCombo()));
      score->Transform(mol);

      OEWriteMolecule(ofs, mol);
    }

    OEThrow.Info("Wrote results to " + ofname);
    ofs.close();
  }

  return 0;
}

