/* 
(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.
*/
//*****************************************************************************
//* Utility to load a previously generated MMP index
//*  and use the transformations discovered to alter a second set of structures
//* ---------------------------------------------------------------------------
//* MatchedPairTransform mmp_index input_mols output_mols
//*
//* mmp_index: filename of matched pair index
//* input_mols: filename of molecules to transform based on analysis
//* output_mols: filename to collect transformed molecules
//*****************************************************************************
#include <openeye.h>
#include <oesystem.h>
#include <oechem.h>
#include <oemedchem.h>
#include "MatchedPairTransform.itf"

using namespace std;
using namespace OESystem;
using namespace OEPlatform;
using namespace OEChem;
using namespace OEMedChem;

int main(int argc, char *argv[])
{
  OEInterface itf(InterfaceData);

  if(!OEParseCommandLine(itf, argc, argv))
    OEThrow.Fatal("Unable to interpret command line!");

  // input structure(s) to process
  oemolistream ifsmols;
  if (!ifsmols.open(itf.Get<string>("-input")))
    OEThrow.Fatal("Unable to open %s for reading", itf.Get<string>("-input").c_str());

  // check MMP index
  std::string mmpimport = itf.Get<string>("-mmpindex");
  if (!OEIsMatchedPairAnalyzerFileType(mmpimport))
    OEThrow.Fatal("Not a valid matched pair index input file, %s", mmpimport.c_str());

  // load MMP index
  OEMatchedPairAnalyzer mmp;
  if (!OEReadMatchedPairAnalyzer(mmpimport, mmp))
    OEThrow.Fatal("Unable to load index %s", mmpimport.c_str());

  // output (transformed) structure(s)
  oemolostream ofs;
  if (!ofs.open(itf.Get<string>("-output")))
    OEThrow.Fatal("Unable to open %s for writing",  itf.Get<string>("-output").c_str());

  // request a specific context for the transform activity, here 0-bonds;
  int chemctxt = OEMatchedPairContext::Bond0;
  std::string askcontext = itf.Get<std::string>("-context");
  char ctxt = askcontext.at(0);
  switch (ctxt)
  {
  case '0':
    chemctxt = OEMatchedPairContext::Bond0;
    break;
  case '1':
    chemctxt = OEMatchedPairContext::Bond1;
    break;
  case '2':
    chemctxt = OEMatchedPairContext::Bond2;
    break;
  case '3':
    chemctxt = OEMatchedPairContext::Bond3;
    break;
  case 'a':
  case 'A':
    chemctxt = OEMatchedPairContext::AllBonds;
    break;
  default:
    OEThrow.Fatal("Invalid context specified:%c, only 0|1|2|3|A allowed",ctxt);
    break;
  }

  bool verbose = itf.Get<bool>("-verbose");

  if (!mmp.NumMols())
    OEThrow.Fatal("No records in loaded MMP index file: %s", mmpimport.c_str());

  if (!mmp.NumMatchedPairs())
    OEThrow.Fatal("No matched pairs found from indexing, use -fragGe,-fragLe options to extend indexable range");

  // return some status information
  if (verbose)
    OEThrow.Info("%s: molecules: %d, matched pairs: %d", mmpimport.c_str(), mmp.NumMols(), mmp.NumMatchedPairs());

  unsigned int minpairs = (unsigned int)itf.Get<int>("-minpairs");
  if (minpairs > 1)
    OEThrow.Info("Requiring at least %d matched pairs to apply transformations", minpairs);

  oeosstream errs;
  bool nowarnings = itf.Get<bool>("-nowarnings");
  if (nowarnings)
    OEThrow.SetOutputStream(errs);

  int orec = 0;
  int ocnt = 0;
  int ototal = 0;
  OEGraphMol mol;
  while(OEReadMolecule(ifsmols,mol))
  {
    ++orec ;
    ocnt = 0;
    OEIter<OEMolBase> outmol = OEMatchedPairApplyTransforms(mol, mmp, chemctxt, minpairs);
    if (!outmol)
    {
      if (verbose)
      {
        // as minpairs increases, fewer transformed mols are generated - output if requested
        string name = mol.GetTitle();
        if (name.empty())
          name = string("Record ") + OENumberToString(orec);
        OEThrow.Info("%s did not produce any output", name.c_str());
      }
      continue;
    }
    if (nowarnings)
      errs.clear();

    for (; outmol; ++outmol)
    {
      ++ocnt ;
      OEWriteMolecule(ofs, outmol);
    }
    ototal += ocnt;

    if (nowarnings)
      errs.clear();
  }

  if (nowarnings)
    OEThrow.SetOutputStream(oeout);

  if (orec == 0)
    OEThrow.Fatal("No records in input structure file to transform");

  if (ototal == 0)
    OEThrow.Fatal("No transformed structures generated");

  OEThrow.Info("Input molecules=%d Output molecules=%d\n", orec, ototal);
  return 0;
}
