
/*******************************************
****    File generated by Tree2C V1.0   ****
**** (c) 2017-2019, Alessandro Pedretti ****
*******************************************/


#define  VGVLL
#include <vega.h>
#include <graphappz.h>
#include <hdcharge.h>
#include <hdstring.h>
#include <stdio.h>

/**** Window parameters ****/

#define  T2C_ABWWIDTH     300    /* Abort window width  */
#define  T2C_ABWHEIGHT    104    /* Abort window height */
#define  T2C_BTWIDTH       89    /* Button width        */
#define  T2C_BTHEIGHT      25    /* Button height       */

/**** Output values ****/

#define  T2C_RANDOM_TREE_FALSE            0
#define  T2C_RANDOM_TREE_TRUE             1

/**** Values of the attributes ****/

#define  T2C_RANDOM_TREE_FG_CON2_NO       0
#define  T2C_RANDOM_TREE_FG_CON2_YES      1
#define  T2C_RANDOM_TREE_FG_COOH_NO       0
#define  T2C_RANDOM_TREE_FG_COOH_YES      1
#define  T2C_RANDOM_TREE_FG_COOR_NO       0
#define  T2C_RANDOM_TREE_FG_COOR_YES      1
#define  T2C_RANDOM_TREE_FG_F_NO          0
#define  T2C_RANDOM_TREE_FG_F_YES         1
#define  T2C_RANDOM_TREE_FG_PHOH_NO       0
#define  T2C_RANDOM_TREE_FG_PHOH_YES      1

/**** Data types ****/

typedef struct {
  float    Angles;
  float    Atoms;
  float    Bonds;
  float    ChiralAtms;
  float    Dipole;
  float    EzBnds;
  int      FG_CON2;
  int      FG_COOH;
  int      FG_COOR;
  int      FG_F;
  int      FG_PhOH;
  float    FlexTorsions;
  float    Gyrrad;
  float    HbAcc;
  float    HbDon;
  float    HeavyAtoms;
  float    Lipole;
  float    Mass;
  float    Ovality;
  float    Psa;
  float    Rings;
  float    Sas;
  float    Sav;
  float    Sdiam;
  float    Torsions;
  float    Vdiam;
  float    VirtualLogP;
} T2C_RANDOM_TREE_INPUT;

/**** Prototypes ****/

int                 T2C_RANDOM_TREE_Classify(T2C_RANDOM_TREE_INPUT *Input);
int                 T2C_RANDOM_TREE_DomCheck(T2C_RANDOM_TREE_INPUT *Input);
HD_BOOL             T2C_RANDOM_TREE_ClassifyMol(HD_LONG *Class, HD_LONG *Violations, HD_ATOM *Atm, HD_ULONG TotAtm);
HD_VOID             BT_AbortClick(GAZ_BUTTON b);
HD_LONG HD_CALLBACK CalcThread(HD_VOID *Arg);
HD_VOID             Error(const HD_CHAR *Err);
HD_LONG             CountFG(HD_ATOM *Atm, const HD_CHAR *Type, HD_BOOL DetectOnly);
float               CalcGyrrad(HD_ATOM *Atm);
float               VegaGetAtt(const HD_CHAR *Att);

/**** Labels ****/

const HD_CHAR *     MsgAborted          = "Aborted by user";
const HD_CHAR *     MsgBtAbort          = "Abort";
const HD_CHAR *     MsgCsvFile          = " - Classification.csv";
const HD_CHAR *     MsgCsvHdr           = "Molecule;Class;Violations\n";
const HD_CHAR *     MsgCsvSave          = "SaveDlg \"Save classification file...\" "
                                          "\"%a\" \"Comma separates values (*.csv)|*.csv\" 1";
const HD_CHAR *     MsgDbOpen           = "OpenDlg \"Open database...\" \"\" \""
                                          "All supported databases|*.accdb;*.db;*.dsn;*.mdb;*.mol2;*.ml2;*.sdf;*.smi;*.txt;*.zip|"
                                          "Access (*.mdb;*.accdb)|*.mdb;*.accdb|"
                                          "Mol2 (*.mol2;*.ml2)|*.mol2;*.ml2|"
                                          "ODBC data source (*.dsn)|*.dsn|"
                                          "SDF file (*.sdf)|*.sdf|"
                                          "SMILES (*.smi;*.txt)|*.smi;*.txt|"
                                          "SQLite (*.db)|*.db|"
                                          "Zip archive (*.zip)|*.zip"
                                          "\" 1";
const HD_CHAR *     MsgDone             = "Done";
const HD_CHAR *     MsgError            = "ERROR";
const HD_CHAR *     MsgInit             = "Initializing...";
const HD_CHAR *     MsgPred             = "  Predicted class....: %d\n"
                                          "  Domain violations..: %d (0 for a better prediction)\n\n";
const HD_CHAR *     MsgPredMol          = "Classifying molecule %u/%u";
const HD_CHAR *     MsgProg             = "* Performing the classification\n";
const HD_CHAR *     MsgProgTitle        = "Database classification";
const HD_CHAR *     MsgWaiting          = "Waiting for the next iteration...";

const HD_CHAR *     MsgWarnNoPred       = "  WARNING: There are %u/%u molecules not classified.\n"
                                          "           For more detail, see the output file.\n";

const HD_CHAR *     MsgErrCalc          = "A calculation is already running";
const HD_CHAR *     MsgErrCsvCreate     = "Can't create the output file";
const HD_CHAR *     MsgErrCsvHdr        = "Can't write the header";
const HD_CHAR *     MsgErrCsvWrt        = "Can't write the output file";
const HD_CHAR *     MsgErrDbEmpty       = "Empty database";
const HD_CHAR *     MsgErrDbNotFound    = "Database not found";

/**** Global  variables ****/

GAZ_LABEL           LBL_Abort;
GAZ_WINDOW          hAbort;
HD_LONG             Mols;

FILE *              FH        = NULL;
GAZ_APPLICATION     AppHandle = NULL;
HD_BOOL             Running   = TRUE;
HD_STRING           hDb       = NULL;
HD_THREAD           hThread   = NULL;
HD_ULONG            Errors    = 0;


/**** Main code ****/

int VllMain(VGP_VEGAINFO *VegaInfo)
{
  HD_LONG           Class, Violations;
  HD_STRING         Result;

  HD_STRING         DbFile  = NULL;
  HD_STRING         OutFile = NULL;

  /**** Translate the labels ****/

  if (!strcmp(VgLanguage, "italiano")) {
    MsgAborted          = "Arrestato dall'utente";
    MsgBtAbort          = "Arresta";
    MsgCsvFile          = " - Classificazione.csv";
    MsgCsvHdr           = "Molecola;Classe;Violazioni\n";
    MsgCsvSave          = "SaveDlg \"Salva il file della classificazione...\" "
                          "\"%a\" \"Valori separati da virgola (*.csv)|*.csv\" 1";
    MsgDbOpen           = "OpenDlg \"Apri il database...\" \"\" \""
                          "Tutti i database supportati|*.accdb;*.db;*.dsn;*.mdb;*.mol2;*.ml2;*.sdf;*.smi;*.txt;*.zip|"
                          "Access (*.mdb;*.accdb)|*.mdb;*.accdb|"
                          "Mol2 (*.mol2;*.ml2)|*.mol2;*.ml2|"
                          "ODBC data source (*.dsn)|*.dsn|"
                          "SDF file (*.sdf)|*.sdf|"
                          "SMILES (*.smi;*.txt)|*.smi;*.txt|"
                          "SQLite (*.db)|*.db|"
                          "Archivio Zip (*.zip)|*.zip"
                          "\" 1";
    MsgDone             = "Fatto";
    MsgError            = "ERRORE";
    MsgInit             = "Inizializzazione...";
    MsgPred             = "  Classe predetta....: %d\n"
                          "  Violazioni dominio.: %d (0 per una migliore predizione)\n\n";
    MsgPredMol          = "Classifico la molecola %u/%u";
    MsgProg             = "* Eseguo la classificazione\n";
    MsgProgTitle        = "Classificazione del database";
    MsgWaiting          = "Attendo la prossima iterazione...";

    MsgWarnNoPred       = "  ATTENZIONE: Non sono state classificate %u/%u molecole.\n"
                          "              Per maggiori informazioni, vedi il file di output.\n";

    MsgErrCalc          = "E' già in esecuzione un calcolo";
    MsgErrCsvCreate     = "Impossibile creare il file di output";
    MsgErrCsvHdr        = "Impossibile scrivere l'intestazione del file";
    MsgErrCsvWrt        = "Impossibile scrivere il file di output";
    MsgErrDbEmpty       = "Il database è vuoto";
    MsgErrDbNotFound    = "Database non trovato";
  }

  /**** Check if a calculation is already running ****/

  if (VegaIsCalc()) {
    Error(MsgErrCalc);
    return 0;
  }
  Result = HD_StrNew();

  /*
   * If there is a molecule in the workspace, a single classification is performed,
   * otherwise a file requester is shown to select an input database. In this case,
   * the classification is performed for all molecules of the database.
   */

  if (VegaIsEmpty()) {
    DbFile = HD_StrNew();
    VegaCmdSafe(DbFile, MsgDbOpen);
    if (HD_StrIsEmpty(DbFile)) goto ExitErr;

    /**** Open the database ****/

    hDb = HD_StrNew();
    VegaCmdSafe(hDb, "DbOpen \"%a\"", DbFile);
    if (*hDb -> Cstr == '0') {
      Error(MsgErrDbNotFound);
      goto ExitErr;
    }

    /**** Check the number of molecules ****/

    VegaCmdSafe(Result, "DbInfo %a Molecules", hDb);
    if ((Mols = HD_Str2Uint(Result)) == 0) {
      Error(MsgErrDbEmpty);
      goto ExitErr;
    }

    /**** Ask for the output file ****/

    OutFile = HD_StrCpy(NULL, DbFile);
    HD_StrChangeExtC(OutFile, NULL);
    HD_StrCatC(OutFile, MsgCsvFile);
    VegaCmdSafe(OutFile, MsgCsvSave, OutFile);
    if (HD_StrIsEmpty(OutFile)) goto ExitErr;

    /**** Create the output file ****/

    if ((FH = fopen(OutFile -> Cstr + 2, "w")) == NULL) {
      Error(MsgErrCsvCreate);
      goto ExitErr;
    }

    /**** Write the header ****/

    if (fprintf(FH, MsgCsvHdr) <= 0) {
      Error(MsgErrCsvHdr);
      goto ExitErr;
    }
  }

  VegaCmdSafe(NULL, "Cursor Busy");
  VegaCmdSafe(NULL, "WksLock");
  VegaPrint(MsgProg);

  /**** Perform the classification ****/

  if (FH) {
    GAZ_FONT      f;
    GAZ_PANEL     p;
    GAZ_RECT      r;

    /**** Create the abort window ****/

    r.x             = 0;
    r.y             = 0;
    r.width         = T2C_ABWWIDTH;
    r.height        = T2C_ABWHEIGHT;
    f               = gazFontNew("MS Sans Serif", GAZ_FS_PLAIN, -11);
    hAbort          = gazWindowNew(MsgProgTitle, r,
                                   GAZ_WIN_CENTERED|GAZ_WIN_MAGFIELD|GAZ_WIN_TOOLWIN|
                                   GAZ_WIN_ALPHA|GAZ_WIN_ALPHAOVERLAP|GAZ_WIN_TITLEBAR|
                                   GAZ_WIN_TEXBACK);
    r.x             = 4;
    r.y             = 4;
    r.width        -= 14;
    r.height        = T2C_ABWHEIGHT - T2C_BTHEIGHT - 44;
    p               = gazPanelNew(hAbort, NULL, r, GAZ_PANEL_BEVIN_RAISED|GAZ_PANEL_BEVKING_NONE|GAZ_PANEL_BEVOUT_LOW);
    r               = gazRect(8, 8, T2C_ABWWIDTH - 30, 18);
    LBL_Abort       = gazLabelNew(p, MsgInit, r, GAZ_ALIGN_CENTER); gazSetFont(LBL_Abort, f);

    /**** Abort button ****/

    gazButtonNew(hAbort, MsgBtAbort, gazRect((T2C_ABWWIDTH  - T2C_BTWIDTH ) >> 1,
                                              T2C_ABWHEIGHT - T2C_BTHEIGHT - 32,
                                              T2C_BTWIDTH, T2C_BTHEIGHT), BT_AbortClick);

    /**** Show the window ****/

    gazWindowShow(hAbort);

    VegaCmdSafe(NULL, "UndoEnable 0");
    VegaCmdSafe(NULL, "Turbo 1");

    /**** Start the calculation thread ****/

    hThread = HD_MthCreateThread(CalcThread, NULL);

    /**** Wait loop ****/

    gazAppRun(&AppHandle);
    if (hThread) {
      HD_MthWaitThread(hThread);
      HD_MthCloseThread(hThread);
      if (Errors)
        VegaPrint(MsgWarnNoPred, Errors, Mols);

      VegaPrint("* %s\n", Running ? MsgDone : MsgAborted);
    }
    gazAppTerminate(AppHandle);

    VegaCmdSafe(NULL, "New");
    VegaCmdSafe(NULL, "Turbo 0");
    VegaCmdSafe(NULL, "UndoEnable 1");
  } else {
    if (T2C_RANDOM_TREE_ClassifyMol(&Class, &Violations, VegaFirstAtom, VegaTotAtom)) {
      VegaPrint(MsgPred, Class, Violations);
    }
  }

  VegaCmdSafe(NULL, "WksUnLock");
  VegaCmdSafe(NULL, "Cursor Default");

ExitErr:
  if (FH) fclose(FH);
  if (!HD_StrIsEmpty(hDb)) VegaCmdSafe(NULL, "DbClose %a", hDb);
  HD_StrFree(DbFile);
  HD_StrFree(hDb);
  HD_StrFree(OutFile);
  HD_StrFree(Result);

  return 0;
}


/**** Abort button click ****/

HD_VOID BT_AbortClick(GAZ_BUTTON b)
{
  gazSetText(LBL_Abort, MsgWaiting);
  gazEnabled(b, FALSE);
  Running = FALSE;
}


/**** Database classification ****/

HD_LONG HD_CALLBACK CalcThread(HD_VOID *Arg)
{
  HD_LONG           Class, Ret, Violations;
  HD_ULONG          k;

  HD_STRING         MolName = HD_StrNew();

  for(k = 0; (k < Mols) && (Running); ++k) {

    /**** Update the progress ****/

    HD_StrPrintC(MolName, MsgPredMol, k + 1, Mols);
    gazSetText(LBL_Abort, MolName -> Cstr);

    VegaCmdSafe(NULL   , "DbGetID %a %u Replace", hDb, k);
    VegaCmdSafe(MolName, "DbInfo %a CurMolName" , hDb);
    HD_StrTrim(MolName);

    /**** Write the molecule name ****/

    if (fprintf(FH, (HD_StrFindChar(MolName, ';', 0) == -1) ?
                "%s" : "\"%s\"", MolName -> Cstr) <= 0) {
      Error(MsgErrCsvWrt);
      break;
    }

    /**** Perform the classification ****/

    if (T2C_RANDOM_TREE_ClassifyMol(&Class, &Violations, VegaFirstAtom, VegaTotAtom))
      Ret = fprintf(FH, ";%d;%d\n", Class, Violations);
    else {
      Ret = fprintf(FH, ";ERR;ERR\n");
      ++Errors;
    }

    if (Ret <= 0) {
      Error(MsgErrCsvWrt);
      break;
    }
  } /* End of for (k) */

  /**** Free the resources ****/

  HD_StrFree(MolName);

  /**** Close the application ****/

  gazAppTerminate(AppHandle);

  return 0;
}


/**** Show an error message ****/

HD_VOID Error(const HD_CHAR *Err)
{
  VegaCmdSafe(NULL, "MessageBox \"%s.\" \"%s\" 16", Err, MsgError);
}


/**** Calculate the gyration radius ****/

float CalcGyrrad(HD_ATOM *Atm)
{
  HD_XYZF        Center;

  HD_AtmsCalcMassCent(Atm, &Center, FALSE);

  return HD_AtmsCalcGyrRad(Atm, &Center, FALSE);
}


/**** Count the functional groups ****/

HD_LONG CountFG(HD_ATOM *Atm, const HD_CHAR *Type, HD_BOOL DetectOnly)
{
  HD_LONG        k;
  HD_OCHAR       Pot;

  HD_LONG        Num = 0;

  Pot.DL = 0LL;
  for(k = 0; (k < 8) && (Type[k]); ++k)
    Pot.C[k] = Type[k];

  while(Atm) {
    if (Atm -> Pot.DL == Pot.DL) {
      if (DetectOnly) return 1;
      ++Num;
    }

    Atm = Atm -> Ptr;
  } /* End of while */

  return Num;
}


/**** Get a value from VEGA ****/

float VegaGetAtt(const HD_CHAR *Att)
{
  float          Val;
  HD_STRING      Result = HD_StrNew();

  VegaCmdSafe(Result, "Get %s", Att);
  Val = HD_Str2Float(Result);
  HD_StrFree(Result);

  return Val;
}


/***** Calculate the attributes and do the classification ****/

HD_BOOL T2C_RANDOM_TREE_ClassifyMol(HD_LONG *Class, HD_LONG *Violations, HD_ATOM *Atm, HD_ULONG TotAtm)
{
  T2C_RANDOM_TREE_INPUT      Input;

  *Violations = 0;

  /**** Check the atom charges ****/

  if (!HD_ChargeChk(NULL, Atm, FALSE))
      VegaCmdSafe(NULL, "Charge Gasteiger 0");

  /**** Calculate the attributes ****/

  Input.Angles       = (float)HD_CountAngle(Atm);
  Input.Atoms        = (float)TotAtm;
  Input.Bonds        = (float)HD_CountBond(Atm, FALSE);
  Input.ChiralAtms   = VegaGetAtt("TotChiral");
  Input.EzBnds       = VegaGetAtt("TotEz");
  Input.FlexTorsions = VegaGetAtt("FlexTor");
  Input.Gyrrad       = CalcGyrrad(Atm);
  Input.HbAcc        = (float)HD_CountHbondAtm(TRUE, Atm, HD_HBOND_CHK_N|HD_HBOND_CHK_O, FALSE);
  Input.HbDon        = (float)HD_CountHbondAtm(FALSE, Atm, HD_HBOND_CHK_N|HD_HBOND_CHK_O, FALSE);
  Input.HeavyAtoms   = (float)HD_CountHeavy(Atm, FALSE);
  Input.Lipole       = VegaGetAtt("BmLipole");
  Input.Mass         = HD_Mass(Atm);
  Input.Ovality      = VegaGetAtt("Ovality");
  Input.Psa          = VegaGetAtt("Psa");
  Input.Rings        = (float)HD_CountRings(Atm, TotAtm);
  Input.Sas          = VegaGetAtt("Sas");
  Input.Sav          = VegaGetAtt("Sav");
  Input.Sdiam        = VegaGetAtt("Sdiam");
  Input.Torsions     = VegaGetAtt("TotTor");
  Input.Vdiam        = VegaGetAtt("Vdiam");
  Input.VirtualLogP  = VegaGetAtt("VLogP");

  HD_Dipole(&Input.Dipole, NULL, Atm, FALSE);

  VegaCmdSafe(NULL, "ForceField GROUPS_EXT 0 1");

  Input.FG_CON2      = CountFG(VegaFirstAtom, "CON2", TRUE);
  Input.FG_COOH      = CountFG(VegaFirstAtom, "COOH", TRUE);
  Input.FG_COOR      = CountFG(VegaFirstAtom, "COOR", TRUE);
  Input.FG_F         = CountFG(VegaFirstAtom, "F", TRUE);
  Input.FG_PhOH      = CountFG(VegaFirstAtom, "PhOH", TRUE);

  /**** Check the domain of the attributes ****/

  *Violations = T2C_RANDOM_TREE_DomCheck(&Input);

  /**** Perform the classification ****/

  *Class = T2C_RANDOM_TREE_Classify(&Input);

  return TRUE;
}



/**** Classification code ****/

/*
 * Return the class code
 */

int T2C_RANDOM_TREE_Classify(T2C_RANDOM_TREE_INPUT *Input)
{
  int     Res;

  if (Input -> HbDon < 0.5000f) {
    if (Input -> Sas < 756.1100f) {
      if (Input -> FG_COOR == T2C_RANDOM_TREE_FG_COOR_YES) {
        if (Input -> Angles < 106.5000f) {
          if (Input -> Atoms < 48.0000f) {
            Res = T2C_RANDOM_TREE_TRUE;
          } else {
            if (Input -> Atoms < 51.0000f) {
              Res = T2C_RANDOM_TREE_FALSE;
            } else {
              Res = T2C_RANDOM_TREE_TRUE;
            }
          }
        } else {
          Res = T2C_RANDOM_TREE_FALSE;
        }
      } else {
        if (Input -> HeavyAtoms < 13.5000f) {
          if (Input -> Gyrrad < 2.8500f) {
            Res = T2C_RANDOM_TREE_TRUE;
          } else {
            Res = T2C_RANDOM_TREE_FALSE;
          }
        } else {
          Res = T2C_RANDOM_TREE_TRUE;
        }
      }
    } else {
      Res = T2C_RANDOM_TREE_FALSE;
    }
  } else {
    if (Input -> Angles < 92.5000f) {
      if (Input -> Gyrrad < 3.6800f) {
        if (Input -> Torsions < 17.5000f) {
          if (Input -> Sas < 283.4200f) {
            Res = T2C_RANDOM_TREE_TRUE;
          } else {
            if (Input -> FlexTorsions < 0.5000f) {
              if (Input -> Sas < 301.9000f) {
                Res = T2C_RANDOM_TREE_FALSE;
              } else {
                Res = T2C_RANDOM_TREE_TRUE;
              }
            } else {
              if (Input -> FG_CON2 == T2C_RANDOM_TREE_FG_CON2_YES) {
                if (Input -> Lipole < 2.1200f) {
                  Res = T2C_RANDOM_TREE_TRUE;
                } else {
                  Res = T2C_RANDOM_TREE_FALSE;
                }
              } else {
                if (Input -> HbAcc < 2.5000f) {
                  if (Input -> Rings < 1.5000f) {
                    if (Input -> Sav < 575.0000f) {
                      Res = T2C_RANDOM_TREE_TRUE;
                    } else {
                      if (Input -> Sdiam < 8.5700f) {
                        Res = T2C_RANDOM_TREE_FALSE;
                      } else {
                        Res = T2C_RANDOM_TREE_TRUE;
                      }
                    }
                  } else {
                    if (Input -> Torsions < 15.5000f) {
                      Res = T2C_RANDOM_TREE_FALSE;
                    } else {
                      if (Input -> HeavyAtoms < 15.5000f) {
                        Res = T2C_RANDOM_TREE_TRUE;
                      } else {
                        Res = T2C_RANDOM_TREE_FALSE;
                      }
                    }
                  }
                } else {
                  if (Input -> HeavyAtoms < 12.5000f) {
                    Res = T2C_RANDOM_TREE_FALSE;
                  } else {
                    if (Input -> Angles < 39.5000f) {
                      Res = T2C_RANDOM_TREE_TRUE;
                    } else {
                      if (Input -> Torsions < 14.5000f) {
                        Res = T2C_RANDOM_TREE_FALSE;
                      } else {
                        if (Input -> HeavyAtoms < 16.5000f) {
                          if (Input -> ChiralAtms < 1.5000f) {
                            Res = T2C_RANDOM_TREE_FALSE;
                          } else {
                            Res = T2C_RANDOM_TREE_TRUE;
                          }
                        } else {
                          Res = T2C_RANDOM_TREE_TRUE;
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        } else {
          if (Input -> Vdiam < 7.3000f) {
            Res = T2C_RANDOM_TREE_FALSE;
          } else {
            if (Input -> Sas < 561.9500f) {
              if (Input -> HeavyAtoms < 19.5000f) {
                if (Input -> Torsions < 19.5000f) {
                  if (Input -> FG_COOH == T2C_RANDOM_TREE_FG_COOH_YES) {
                    Res = T2C_RANDOM_TREE_FALSE;
                  } else {
                    Res = T2C_RANDOM_TREE_TRUE;
                  }
                } else {
                  Res = T2C_RANDOM_TREE_TRUE;
                }
              } else {
                Res = T2C_RANDOM_TREE_TRUE;
              }
            } else {
              Res = T2C_RANDOM_TREE_FALSE;
            }
          }
        }
      } else {
        if (Input -> Ovality < 1.6900f) {
          if (Input -> HbAcc < 3.5000f) {
            if (Input -> Rings < 1.5000f) {
              Res = T2C_RANDOM_TREE_FALSE;
            } else {
              if (Input -> Mass < 303.4100f) {
                if (Input -> Ovality < 1.5900f) {
                  Res = T2C_RANDOM_TREE_FALSE;
                } else {
                  Res = T2C_RANDOM_TREE_TRUE;
                }
              } else {
                Res = T2C_RANDOM_TREE_FALSE;
              }
            }
          } else {
            if (Input -> Mass < 356.3800f) {
              Res = T2C_RANDOM_TREE_FALSE;
            } else {
              if (Input -> EzBnds < 0.5000f) {
                Res = T2C_RANDOM_TREE_FALSE;
              } else {
                if (Input -> Mass < 362.3900f) {
                  Res = T2C_RANDOM_TREE_TRUE;
                } else {
                  Res = T2C_RANDOM_TREE_FALSE;
                }
              }
            }
          }
        } else {
          if (Input -> Sdiam < 10.9700f) {
            if (Input -> Lipole < 2.3800f) {
              if (Input -> HbAcc < 3.5000f) {
                Res = T2C_RANDOM_TREE_TRUE;
              } else {
                Res = T2C_RANDOM_TREE_FALSE;
              }
            } else {
              Res = T2C_RANDOM_TREE_FALSE;
            }
          } else {
            if (Input -> VirtualLogP < 3.4100f) {
              if (Input -> Dipole < 2.8300f) {
                Res = T2C_RANDOM_TREE_FALSE;
              } else {
                Res = T2C_RANDOM_TREE_TRUE;
              }
            } else {
              Res = T2C_RANDOM_TREE_TRUE;
            }
          }
        }
      }
    } else {
      if (Input -> FlexTorsions < 1.0000f) {
        Res = T2C_RANDOM_TREE_TRUE;
      } else {
        if (Input -> Ovality < 1.7300f) {
          Res = T2C_RANDOM_TREE_FALSE;
        } else {
          if (Input -> Psa < 59.6600f) {
            if (Input -> HeavyAtoms < 31.0000f) {
              if (Input -> Bonds < 51.5000f) {
                Res = T2C_RANDOM_TREE_FALSE;
              } else {
                Res = T2C_RANDOM_TREE_TRUE;
              }
            } else {
              if (Input -> FlexTorsions < 9.0000f) {
                Res = T2C_RANDOM_TREE_FALSE;
              } else {
                Res = T2C_RANDOM_TREE_TRUE;
              }
            }
          } else {
            if (Input -> FG_PhOH == T2C_RANDOM_TREE_FG_PHOH_YES) {
              if (Input -> Angles < 119.5000f) {
                Res = T2C_RANDOM_TREE_TRUE;
              } else {
                if (Input -> Angles < 230.0000f) {
                  Res = T2C_RANDOM_TREE_FALSE;
                } else {
                  if (Input -> ChiralAtms < 21.5000f) {
                    Res = T2C_RANDOM_TREE_FALSE;
                  } else {
                    Res = T2C_RANDOM_TREE_TRUE;
                  }
                }
              }
            } else {
              if (Input -> FG_F == T2C_RANDOM_TREE_FG_F_YES) {
                if (Input -> ChiralAtms < 1.5000f) {
                  Res = T2C_RANDOM_TREE_TRUE;
                } else {
                  if (Input -> Vdiam < 9.0700f) {
                    Res = T2C_RANDOM_TREE_FALSE;
                  } else {
                    Res = T2C_RANDOM_TREE_TRUE;
                  }
                }
              } else {
                if (Input -> Lipole < 2.3100f) {
                  if (Input -> FlexTorsions < 8.5000f) {
                    if (Input -> Sas < 977.1200f) {
                      if (Input -> EzBnds < 0.5000f) {
                        if (Input -> ChiralAtms < 0.5000f) {
                          if (Input -> Mass < 441.2400f) {
                            Res = T2C_RANDOM_TREE_TRUE;
                          } else {
                            Res = T2C_RANDOM_TREE_FALSE;
                          }
                        } else {
                          Res = T2C_RANDOM_TREE_FALSE;
                        }
                      } else {
                        if (Input -> Bonds < 59.0000f) {
                          Res = T2C_RANDOM_TREE_FALSE;
                        } else {
                          Res = T2C_RANDOM_TREE_TRUE;
                        }
                      }
                    } else {
                      Res = T2C_RANDOM_TREE_TRUE;
                    }
                  } else {
                    Res = T2C_RANDOM_TREE_FALSE;
                  }
                } else {
                  Res = T2C_RANDOM_TREE_FALSE;
                }
              }
            }
          }
        }
      }
    }
  }

  return Res;
}


/**** Domain check code ****/

/*
 * Return the number of domain violations
 */

int T2C_RANDOM_TREE_DomCheck(T2C_RANDOM_TREE_INPUT *Input)
{
  int     Violations = 0;

  if ((Input -> Angles < 6.00000000f) || (Input -> Angles > 374.00000000f)) ++Violations;
  if ((Input -> Atoms < 5.00000000f) || (Input -> Atoms > 203.00000000f)) ++Violations;
  if ((Input -> Bonds < 4.00000000f) || (Input -> Bonds > 206.00000000f)) ++Violations;
  if ((Input -> ChiralAtms < 0.00000000f) || (Input -> ChiralAtms > 25.00000000f)) ++Violations;
  if ((Input -> Dipole < 0.00001200f) || (Input -> Dipole > 22.36607000f)) ++Violations;
  if ((Input -> EzBnds < 0.00000000f) || (Input -> EzBnds > 7.00000000f)) ++Violations;
  if ((Input -> FlexTorsions < 0.00000000f) || (Input -> FlexTorsions > 28.00000000f)) ++Violations;
  if ((Input -> Gyrrad < 1.41856400f) || (Input -> Gyrrad > 10.56297000f)) ++Violations;
  if ((Input -> HbAcc < 0.00000000f) || (Input -> HbAcc > 26.00000000f)) ++Violations;
  if ((Input -> HbDon < 0.00000000f) || (Input -> HbDon > 21.00000000f)) ++Violations;
  if ((Input -> HeavyAtoms < 3.00000000f) || (Input -> HeavyAtoms > 101.00000000f)) ++Violations;
  if ((Input -> Lipole < 0.00000300f) || (Input -> Lipole > 6.34667600f)) ++Violations;
  if ((Input -> Mass < 70.08984000f) || (Input -> Mass > 1449.25400000f)) ++Violations;
  if ((Input -> Ovality < 1.16274900f) || (Input -> Ovality > 2.74024100f)) ++Violations;
  if ((Input -> Psa < 0.00000000f) || (Input -> Psa > 544.81690000f)) ++Violations;
  if ((Input -> Rings < 0.00000000f) || (Input -> Rings > 10.00000000f)) ++Violations;
  if ((Input -> Sas < 203.40610000f) || (Input -> Sas > 2006.11400000f)) ++Violations;
  if ((Input -> Sav < 252.97150000f) || (Input -> Sav > 3811.29900000f)) ++Violations;
  if ((Input -> Sdiam < 5.14906200f) || (Input -> Sdiam > 22.48208000f)) ++Violations;
  if ((Input -> Torsions < 0.00000000f) || (Input -> Torsions > 94.00000000f)) ++Violations;
  if ((Input -> Vdiam < 4.77512900f) || (Input -> Vdiam > 13.58132000f)) ++Violations;
  if ((Input -> VirtualLogP < -7.13032600f) || (Input -> VirtualLogP > 9.48374900f)) ++Violations;

  return Violations;
}
