/* -*-C++-*-

**********************************************************************

Copyright (C) 2007,2008 by Sergei V. Trepalin sergey_trepalin@chemical-block.com
Copyright (C) 2007,2008 by Andrei Gakh andrei.gakh@nnsa.doe.gov

This file is part of the Open Babel project.
For more information, see <http://openbabel.org/>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation version 2 of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
***********************************************************************
*/
#include <openbabel/babelconfig.h>
#include <openbabel/mol.h>
#include <openbabel/atom.h>
#include <openbabel/bond.h>
#include <openbabel/mcdlutil.h>
#include <openbabel/data.h>
#include <openbabel/obconversion.h>
#include <openbabel/stereo/stereo.h>
#include <openbabel/stereo/cistrans.h>

#include <memory>

#ifndef WIN32
#include <cmath>
#endif
#ifdef __MINGW32__
#include <cmath>
#endif

using namespace std;

namespace OpenBabel {

#define CONNMAX 15

  // Forward declarations
  class TEditedMolecule;

  typedef struct adjustedlist{
    int nb;
    int adjusted[CONNMAX];
  } adjustedlist;

  typedef adjustedlist neighbourlist;

#define PI 3.141592653589793238462
#define blDenominator 4.0   //Controls bond legth in bondEnlarge
#define nRotBondsMax 10     //Determines no. rotating bonds that are systematically searched in correctOverlapped

  //Hydrogen valencies. Zero dummy element is the first
	const int hVal[NELEMMCDL] = {
    0,1,0,0,0,3,4,3,2,1,
    0,0,0,3,4,3,2,1,0,0,
    0,0,0,0,0,0,0,0,0,0,
    0,0,4,3,2,1,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,
    2,3,2,1,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,
    0,0,2,0,2,1,0,1,2,0,
    0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,1,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0};

	const int maxVal[NELEMMCDL] = {
    0,1,0,1,2,4,4,5,3,1,
    0,1,2,4,4,6,6,7,0,1,
    2,3,4,5,6,7,6,4,4,2,
    2,3,4,5,6,7,8,1,2,3,
    4,5,6,7,8,6,6,2,2,3,
    4,5,6,7,8,1,2,3,4,4,
    3,3,3,3,3,4,3,3,3,3,
    3,3,4,5,6,7,8,6,6,3,
    2,3,4,5,6,7,8,1,2,3,
    4,5,6,6,6,6,3,4,3,3,
    3,3,1,1,1,0,0,0,0,0,
    0,8,1,8,5,0,0,0,0,0,0};

  const int chargeVal[NELEMMCDL] = {  //0 - dummy
    0,-1,-1,-1,-1,-1,-1, 1, 1, 1,-1, //Ne
    -1,-1,-1,-1, 1, 1, 1,-1,-1,-1, //Ca
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, //Zn
    -1,-1, 1, 1, 1,-1,-1,-1,-1,-1, //Zr
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, //Sn
    1, 1, 1,-1,-1,-1,-1,-1,-1,-1, //Nd
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, //Yb
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, //Hg
    -1,-1, 1, 1, 1,-1,-1,-1,-1,-1, //Th
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, //Fm
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1};


  const string aSymb[NELEMMCDL] = {"0",
                                   "H" ,"He","Li","Be","B" ,"C" ,"N" ,"O" ,"F" ,"Ne",
                                   "Na","Mg","Al","Si","P" ,"S" ,"Cl","Ar","K" ,"Ca",
                                   "Sc","Ti","V" ,"Cr","Mn","Fe","Co","Ni","Cu","Zn",
                                   "Ga","Ge","As","Se","Br","Kr","Rb","Sr","Y" ,"Zr",
                                   "Nb","Mo","Tc","Ru","Rh","Pd","Ag","Cd","In","Sn",
                                   "Sb","Te","I" ,"Xe","Cs","Ba","La","Ce","Pr","Nd",
                                   "Pm","Sm","Eu","Gd","Tb","Dy","Ho","Er","Tm","Yb",
                                   "Lu","Hf","Ta","W" ,"Re","Os","Ir","Pt","Au","Hg",
                                   "Tl","Pb","Bi","Po","At","Rn","Fr","Ra","Ac","Th",
                                   "Pa","U" ,"Np","Pu","Am","Cm","Bk","Cf","Es","Fm",
                                   "Md","No","Lr","D" ,""  ,"G" ,"0" ,"Xx",""  ,""  ,
                                   "M" ,"X" ,"A" ,"Q" ,""  ,""  ,""  ,""  ,""  ,""};


#define NEXACTATOMS 21
  const int exactAtom[NEXACTATOMS]={6,14,5,50,82,8,16,34,52,7,15,33,51,9,17,35,53,32,13,26,80};
#define NALKALYATOMS 5
  const int alkaly[NALKALYATOMS] ={3,11,19,37,55};
#define NALKALYEARTHATOMS 5
  const int alkalyEarth[NALKALYEARTHATOMS] ={4,12,20,38,56};
#define NTRIVALENTATOMS 31
  const int trivalent[NTRIVALENTATOMS] ={21,31,39,49,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,81,89,90,91,92,93,94,95,96,97,98,99};
#define NTITANATOMS 3
  const int titan[NTITANATOMS] ={22,40,72};
#define NVANADIUMATOMS 3
  const int vanadium[NVANADIUMATOMS] ={23,41,73};
#define NCHROMIUMATOMS 3
  const int cromium[NCHROMIUMATOMS] ={24,42,74};
#define NMANGANESEATOMS 3
  const int manganeze[NMANGANESEATOMS] ={25,43,75};
#define NLIKEFEATOMS 2
  const int likeFe[NLIKEFEATOMS] ={27,28};
#define NPLATINUMATOMS 6
  const int platinum[NPLATINUMATOMS] ={44,45,46,76,77,78};
#define NCOPPERATOMS 3
  const int copper[NCOPPERATOMS] ={29,47,79};
#define NZINKATOMS 2
  const int zink[NZINKATOMS] ={30,48};

#define NMETALS 78
#define NHALOGENS 5
#define NHETERO 10
#define NAROMMAX 9
#define NLIGHT_METALS 20
#define NHEAVY_METALS 58

#define DEUTERIUM_ATOM 104
#define METALL_ATOM 111
#define HALOGEN_ATOM 112
#define ANY_ATOM 113
#define HETERO_ATOM 114
#define ANY_BOND 8

  const int possibleAromatic [NAROMMAX] = {7,8,15,16,33,34,51,52,HETERO_ATOM};
  const int metals[NMETALS] = {
    3,4,11,12,13,19,20,21,22,23,24,25,26,27,28,29,
    30,31,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,61,62,63,
    64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,87,88,89,90,91,
    92,93,94,95,96,97,98,99,100,101,102,103};

  //#define A B   ??? -
  const int lightMetals[NLIGHT_METALS] = {
    3,4,11,12,13,19,20,21,22,23,24,25,26,27,28,29,30,31,37,38};
  const int heavyMetals[NHEAVY_METALS] = {
    39,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,61,62,63,
    64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,87,88,89,90,91,
    92,93,94,95,96,97,98,99,100,101,102,103};
  const int halogens[NHALOGENS] = {9,17,35,53,85};
  const int hetero[NHETERO] = {7,8,14,15,16,33,34,51,52,84};

#define RUNDEF -1.2345678E9
#define DEFAULTBONDLENGTH 1.44
#define NDATABASE_MOLECULES 148

  const string strData[NDATABASE_MOLECULES]= {
    "05A53816506A53810000A00008692A99998857A6567442806020101030401050203050504",
    "06A25008659A74998659A99994330A74990000A25000000A00004330100203030405060106060406020305010305020104",
    "06A48805837A48800000A00007834A90467987A59523994A999962970802010103040106040502060503050302",
    "06A33680000A00003697A90943697A90949999A00009999E3368717109020101030203010602050304050606040405",
    "06A00002886A49980000A99992886A71137887A28867887E49985773070102020303060601010503040405",
    "07A00002500A00007499A86397499A86392500A43200000A69404999A4235999909070203070304050402030102050606070105",
    "07A18315489A81685489A18311830A81681830A49990000A00008658A9999865809050403050204010301060602020707010607",
    "07A51830000A99995257A61733821A00008921A86408921A16055257E45686533100604030601070704050702050301020304050602",
    "07A43300000A86602500A00002500A86607499A00007499A43309999A213550000801020301050606040402050301070607",
    "07A69274000A69270000A00000000A00004000A69277999A34649999E3464599909010203040407010707060605050104060203",
    "07A43309999A00007499A86607499A00002499A86602499A43300000E433049990806050406020101030305020406070702",
    "08A99994342A99991475A50354342A74810040A50351475A00004363A24800000A00001455100405050301020402030107080806070506030704",
    "08A14437499A43307499A57735000A43302500A14432500A00005000A57730000A57739999100102020303040405050601060407020808060607",
    "08A55684926A59770000A13416715A91136862A00003196A24094926A99995337E654534311106030806020101030401070408020708060503050207",
    "08A00003799A00009999A21890000A83936200A83930000A61999999E21896200E6199379912070206040206010203010805010806080703030507040405",
    "08A36607320A78867320A99993660A78860000A36600000A15473660A00002113A0000520709010202030304040505060106050701080807",
    "08A00005000A00008332A57705000A28419999A57708332A57701667A29290000A0000166709010202040405050301030306060707080801",
    "08A48819390A53570000A00007833A90467986A59523994A11895837A99996297E48815837100603050602080803040807040502070503010401",
    "08A19105257A80890000A99992628A19100000A00002628A80895257E50001004E500042531101080807070404050105060303020806070204020601",
    "08A50000000A50006666A00002886A16670000A83320000A99992886E66662886E33332886100108080303040401010707060605050106020302",
    "08A25008659A74998659A99994330A74990000A25000000A00004330E30622562E6937256209010202030304040505060106060703080708",
    "09A24994330A74994330A24991444A74991444A49990000A99995773A00005773A85558273A144382731105040305020401030602010607010207090708060908",
    "09A55375090A55370002A12826830A91696964A64713483A18610000A99995492A00003324E2320509012090305090201010304010704050207050908080308060602",
    "09A18510000A00003211A90859999A70960000A00008451A52418451A70965241E52413211E18515241130905050602050102080402080608090101040907070403070603",
    "09A19105257A49994253A49991004A19100000A00002628A80895257A99992628A80890000E386426281101020203030404050105060707080206030805090907",
    "09A49994252A80895257A49991004A80890000A19090000A00002628A19095257A99992628E218626281101020208080404030103030505060607070103090109",
    "09A00003622A10641208A32581208A49670000A32583622A99993247A81610000A68065661E593523311101020203030404050501030909070706060808050407",
    "09A31703170A50000000A00004999A36604999A68293170A63394999A99994999A81698169A18308169100102010303090904040502050106070507080806",
    "09A82718548A41359999A91956942A00008341A44961502A55014870A11246476A55010000E449664761107040607090401090301030609050608050804020102",
    "09A70330000A29660000A00002881A00007010A29669891A70339891A99997010A99992881E63994946100102020303040405050606070708010802090509",
    "09A80419999A43868037A89488452A00009735A15210000A53806452A11118037A53801698E43863169100704060702040102030103060209060805090805",
    "09A10176779A34868279A63437716A99994155A63430500A34860000A10171406A00004155E26634155100102020303090905050606070708010803040504",
    "09A16675773A50005773A83325773A50000000A16670000A00002886A83320000A99992886E66662886100102020909040405050601060407070808030302",
    "09A70296185A40884515A09414515A42940000A00006071A88530000A99994478E46463112E779448571103050803040202050102080409080604070109070706",
    "09A19319009A62699999A97487225A97482775A62690000A19310991A00005000A45715000A23465000100102020303040405050606070107080508020809",
    "10A43309999A86597499A72165000A43305000A28867499A86592500A43300000A28862500A00002500A0000749912020303040405010507080306040810050809091001020607",
    "10A46515888A50291200A06397575A81687425A55524463A17730000A16865888A88076225A00002513A9999993812070305070201010304010502080509070602090610080410",
    "10A48804396A48801478A00006392A90466546A59522553A11914396A99994857A59520000A69959494A2962949412060305060201010304010704070505080208040903101009",
    "10A25474570A16166133A62753127A54374570A54370000A94454931A86996254A38217369A00008932A1791999912010203010504040207040607030506030408020909100810",
    "10A00006995A25904430A25900855A66250000A99991632A46986995A63859327A85547850A85544430E46981632130201030204030410010607060807090802090509040510060510",
    "10A53026409A85668294A00008578A65814346A12696409A99996433A51190000A12692065A65810691E53022065130503040510010103040604091008080508070709091001020206",
    "10A99994745A58033967A85242714A58030000A24865324A65322714A00002818A82426113A18370000E32963967131005061004020205030106040306020808010409090707051007",
    "10A38760000A23092718A00008169A83160000A23097153A99998464A83164436A67457153E67452718E387644361405080205090402090809100101041007070406070806020103100503",
    "10A36631099A20423911A00000000A82571099A20428500A99999856A82575689A66328500E66323911E366356891410050508020509040209080910010104100707040607080603020103",
    "10A73929797A99996506A32668429A26361664A99991664A00009797A63030000A26366506E32663734E68198060130806100802010103030610020804030902050407050709050709",
    "10A00007120A10935313A99996759A14849577A54623723A48450000A82347300A63309577A89634915E4845531312020105020610100107100506090504010708040803070903",
    "10A18301830A50000000A81691830A99995000A00005000A18308169A50009999A81698169E50006340E5000366112010202030310100101050506060909080807070608040403",
    "10A62500000A25002165A76109666A99992165A25006783A40838511A99996491A00009666E74798226E4083374912020110010401070406100502080506080905070903060703",
    "10A73929796A99996506A32668429A26361663A99991663A00009796A63030000A26366506E32663734E6819805912080610080201010303061002080403090205040705070905",
    "11A11600000A46320000A57051522A28912486A00761522A28147513A00008476A10849999A45569999A56288476A284451212002010302070608070910100609080405050104030511041101110211110311060811071111091110",
    "12A86832482A65403688A00002482A21983688A43972482A43970000A21986311A00007446A43977446A65406311A43979999A8683744630030808111112120101060306060504020209090407050510100701021012091107080403010501101202120911101107080908040307030506020604",
    "11A55476610A55471550A30757567A91868524A65015060A24036610A99997020A32150000A24039664A00004877A00001550130506020101030401070405020705080210061110081109060309",
    "11A99994719A35190000A50464719A64810000A90277646A00004838A09727765A41667765A60187646A74542927A25462927131003041002111103040206071106030808070905030910010105",
    "11A54717869A10769779A91039894A00005034A21977869A99998274A65021620A65026365A05821505A19730000E547130661405020805010203010603060801110807110709111007100910040504",
    "11A63167961A37420000A00005471A63165546A43862037A09653395A68423395A00008150A18139999A47959999E342139991406030506021111030411070405020705030808090910100106070401",
    "11A50227868A00000000A06467868A63146852A06463611A63142407A88964074A18652407A30859999E18656852E5022361115011111050503060808100410010411060310090309010607070408020205",
    "11A33586997A99992256A00007945A62567945A51370000A20545575A82195337A20541779A61486761A86960000E33583081130805110501110608030601030906070904010704070205101002",
    "11A46588688A46585901A23299999A23294644A00008688A00005901A85963661A85960000A23290000E41501367E597136611405060406020401020305030107080207040904101011071108110908",
    "11A74236368A00008420A80755210A12646263A46091158A53023684A20804895A53020000A61998579A22849999E46094895130704060711040111030103061105060805080901100902100402",
    "11A31388599A13560000A00009949A58129999A37597499A07368599A63938949A45724300A05043100A17822600E31384849130603050611010103040107040511070510020810110909020508",
    "11A00004220A00001358A24810000A50001358A74818488A24815626A24818488A74815626A99994220A99991358E50004220130201030204031104061101060706081109081009041005080705",
    "11A85916567A35746567A99992562A23462655A00009594A49450000A23469594A12637033A79770000E48375123E758051231402040102031111101004030111010406090609030810070205080705",
    "11A09557693A34559510A65449510A90447693A99994755A90441816A65440000A34550000A09551816A00004755E3675475512010202030304040505060607070808090910011007110311",
    "11A00009999A42230000A00006825A78729999A52073492A10255079A87345449A87348517E10258517E78726930E422350791406030506021111031011071005020705090608090708041001040301",
    "11A13393318A13746318A70459999A49670000A86644773A44732909A00005045A90889045A21849999E78206545E49674999130601110210110506110406040702010708100508090210030903",
    "11A99995000A81698169A81691829A00005000A50009998A50000000A18301829A18308169E50006338E31703169E6830316912070408041004050802050102030106030706110109111009",
    "11A49991430A25005766A99991430A49997229A00001430A25000000A74990000A74995766E74992892E49994337E2500289212050606010701030904080201110510091110100803070402",
    "12A49997216A25008659A49994330A00007216A25002886A00004330A74992886A99994330A74998659A99997216A25000000A749900001405030605040202010103040609011009080707030810051107121211",
    "12A74852867A74850000A44730000A95313961A80111961A56432867A99993093A21052452A00004640A53805093A24853885E5058388515061205060201011204010704050207050809120801101011110903080203",
    "12A00003057A47044586A99994586A47041529A99991529A73520000A47047643A73529172A99997643A17970584A17975530E735261151406050406021203120305020402070708080909030211100101110410",
    "12A40419999A55880712A00007357A17531277A55884325A17535184A90205891A90209166A34830000E81107504E41302134E41306289160603050611121203101207100708030108010507050211040406040909020211",
    "12A83909999A37070000A00005869A00008652A44813000A08764391A75144695A68408652A75147390E08767390E68405999E37074391160603050602121203111207110502070510060910070908110408030401080901",
    "12A67547130A27484678A78944678A27481245A78941245A31286036A53210000A99995885A00006262A08487356E31282716E570157721412021203020406110305040711070507090210061009080301080601",
    "13A00008749A21667501A21669999A46659999A68308749A46657501A21662499A46652499A68301250A46650000A21660000A00001250A3501512124010201030304040505060602021313070708080909101011111212071311131013081309131213011303130413061305",
    "12A98975714A74231429A49490000A24741429A98978571A00005714A00008571A24749999A74239999E49498571E24744285E7423428512120202030304041111060607070808101009090505010112",
    "13A28577422A57147422A71424948A57142474A28572474A14284948A99994948A71420000A99990000A71429897A99999897A00002474A00007422160102020303040405050601060307040808090907021010111107051201131312",
    "13A99994826A91595517A83512806A74203552A54942806A94380000A44703607A85380666A16353603A25602863A13885888A00001596A08320912160507030504070204010201030408030608060907111010051310121309111209",
    "13A39485622A00003358A32469999A69013962A30124453A23988376A61112528A85093962A92982528A68711132A68710000A92980000E84791132160603050602010103040107040502070510130710040808090913101111120912",
    "13A60776420A66072578A90957683A28148103A52614999A83206052A20806788A00005578A07342947A07340000A20809999A52610000E40781315160506020101030401020507050807090813090213091012100512071104110603",
    "13A63116880A88436880A88432580A99994701A50224701A63110000A37776880A12442580A12446880A00004701A37770000A37772580A6311258015030413030501010202040513091007090512120808100507111206131106",
    "13A66660962A66662887A83333849A99992887A99990962A83330000A50000000A33330962A33332887A16660000A00000962A00002887A1666384915010202030304040505060106070808090107101111121213081009130209",
    "13A22073757A07045817A48844666A00000000A07048909A68573757A25832121A52145817A29129999A52148909A22071212E48847575E25834909160806130802010103030613020810031202051009120905091101071304110704",
    "13A18232941A00005293A47863921A77493823A00008725A71412941A22020980A51665293A25839999A51668725A18230000E47867254E22024215161308020101030306130208100312020510091209050911010713110704080604",
    "13A85754958A99992462A99997437A00004924A14072462A85750000A85759898A42717437A42712462A14077437A57289898A57280000E5728495815020103011301060207030813091311081209040510080509120610040711",
    "13A00008994A36698934A00006804A18349999A55028934A36693254A54560000A18345739A73371064A73373195A36691064E55024260E36696804160103080313080213040106110402091007090612121011071205020513100806",
    "13A60780000A67532108A39210000A32242108A10892108A89102108A00003963A99993963A39215201A60785201A79516296A20486296E501033451404031304020101031302050406020705080609101110120907120811",
    "13A60520000A10660521A39180000A20476299A10822113A89172113A00003961A99993961A79526299E60525168E39185168E32162113E675421131412031301010305120613070508061110091004110704080905021302",
    "14A22012921A22010284A00003814A43083895A26732069A05352921A44973124A67292962A64462313A99992313A84583976A71380000A92750000E74831014190603050602010103040107040502070514120814110909120709081113121413101113100408",
    "14A18759999A29620000A01974012A48374140A33072038A08392993A53803184A09386433A20735732A53808661A48875732A00008025E40976433E271529932006030506021414030414070405020705080306091304071108130911120809121011131001121001",
    "14A37508659A62498659A74996495A62494330A37504330A25006495A74992165A62490000A37500000A25002165A00002165A00006495A99996495A999921651701020203030404050506010607080809091004070510120610110313071411121314",
    "14A52504032A47494920A31242823A25623791A06253791A31240000A00004839A25620887A68756129A74375161A93755161A68758952A99994113A743780641705070305040702040102010304080306080611130911101301100209101409121412",
    "14A49995955A36928217A99993692A49992263A00008217A86945955A13032263A00004524A63070000A99990000E86942263E63073692E36924524E130359552314050201050208050708130408130213140707041401010411100904100903100603120103120912110606011104",
    "14A14989134A00007637A67720000A47251181A79534409A99995591A79536772A67722362A55916772A55914409A11815591A35457953A35453228A35455591161314121411141014091405100605070609070810041303040803021101120201",
    "14A00002151A10824678A74260000A21050075A57591849A38601849A29535658A38604678A57594678A64325658A85664678A99992037E29532829E6432282918130414130305050606040314071308060905101411091011121103120208070201020401",
    "14A57093413A57090749A79674204A79030000A00002206A99991915A39023454A39020749A16774204A17100083E30962955E30961415E65801415E658027892002040102031414131304030108100708091111121210090708021312060403060510090511071401",
    "14A00001443A00004330A25005728A60475728A50001443A25000000A75000000A99991443A99994330A85566830E25002887E75005773E60472887E5000433018010202030314140505060106050707080809071301111113141212090910100404030413",
    "14A14499999A00347478A43809999A58294608A58297478A00344608A00002521A58292521A43800000A14490000A28641391E43804999E14494999E286432171713020201050312051213030107130812090810071110091106020405041406141114",
    "14A19889999A45149217A66708216A88286043A70752304A13482174A00004521A12467216A70750000A44130000E29313695E56946043E40096303E4009313018131403130403050414050614070608071308071110110910050912110412021201020801",
    "14A60520641A99990000A38890641A00880000A10822716A88592716A00004565A99114565A20476866A78946866E60525772E38895772E32162716E6695271615130314010103051306140705080612111011091207090810050406020204",
    "15A15004047A35682933A10222610A35680000A59083989A28862199A54313197A00003461A72723050A67272258A90903461A99991848A75220440A93850440E795414082006070402020501020604030603080108050907101109131012111413141207051509151410111315",
    "14A99993463A89991732A89995196A60000000A39990000A60006927A10001732A00003463A10005196A39996927E29995196E29991732E70005196E700017321401020214140404050512120707080809091111101006061313030301",
    "15A14543959A34772874A10002551A34770000A57953929A28402111A53183108A00003402A71132991A65682229A93173842A92260411A99991877A73630411E84542874190607040202050102060403060308010805090710110915101315141014091311121412130705",
    "15A46187999A69287999A80825999A69284000A46184000A34645999A34642000A11552000A00004000A11555999A80822000A69280000A46180000A00007999A3464999918010202030304040505060106070808090910050706101112121313070411150110141415",
    "15A33335773A50006735A33333849A66665773A50002886A66663849A16662886A00003849A16666735A00005773A50000962A66660000A83330962A83334811A9999192418050603050102020404060103091001090307070808100511111212130613061413151514",
    "14A24498659A00004286A50331429A26170000A75508572A99994286A74490000A50337230E75505715E24495715E74492814E26172814E42283637E6140510915081414131303110703070906110608050905030412041202100210010801",
    "16A73181418A16684435A37326615A33468273A10227107A00004783A68276769A83024030A99994030A95756586A76088273A63930000A33840000A24491418A50242305A5024478330030208070908101111070910040305060602040513121413150101121415141613161516121601161608160916101607161116040316160506161602",
    "15A25446903A08194678A53505998A29245772A08191396A75436903A00005998A99992565A32750226A57301396A85660000A75431207A99995508E57304678E53502829191406041401030306040214100315020510091509050907010207130608131208151211081011",
    "16A70462641A70460264A90353433A51463508A66071886A88590264A49702829A29532716A32162075A00002075A13743584A26020000A99991773A06730000E22810906E853726412316030516020101030401070405020705151208151109091207090811131603131412151410111410040806130206",
    "16A38483333A57733333A67351666A57730000A38480000A28861666A28865000A38486666A57736666A28868333A38489999A57739999A67358333A09625000A00006666A09628333190102020303040405050601060708080901071011111212130810091307141415151616100209",
    "16A59953466A69901721A69905199A40043466A99993466A09841721A89921721A89925199A59950000A59956920A29865199A29861721A09845199A40046920A40040000A00003442190201030104010508070208030902100311041204141115121606131106120705150913161014",
    "15A71629322A12851233A50830000A00003000A71620675A50839999A95106091A00006997A95103906A12858764E76162814E34588536E76167185E08895000E3458146215150202040414110505030315130707090911120606010113140808101012",
    "16A40003464A59993464A69991732A59990000A40000000A30001732A30005196A40006928A59996928A69995196A89995196A99993464A89991732A10001732A00003464A1000519618020303040405050601060708080909100107021010111112121303131415151616070614",
    "16A61204512A61201863A99992864A46586454A38260538A15304689A25005747A15301863A99990000A00006454A71320000A89854620E71322864E89851869E25002832E457855732308051505020501020715060810060710160601160407010413011203011211021409021412141311110913030309",
    "16A21912563A23970000A00003476A39953505A26941767A05712563A44522740A81270648A55482740A99992091A63922003A61874654A99993329E89262740E66443329E5091350521060305060201010304010704050207050416070915110911161215120914151313141310141011081008",
    "16A34524404A83733226A38885581A99991895A22621178A42462150A14683840A83734659A68645581A63880000A83730000A00001843A06740461E67061178E38883226E63882407190605140602161615150502140315080209080309101611100402041113051213071201071501",
    "16A21141056A39430000A60560000A78861056A78864045A60565101A00001056A99991056A99994045A00004045A21144045A39435101E39432113E60562113E39432988E6056298818010202030304041414131301010704080809071010111112120606051115151616050509",
    "16A89991732A99993464A69991732A59990000A40000000A30001732A10001732A00003464A10005196A89995196A40006928A59996928E69995196E30005196E59993464E400034641716151503030404050506160606070708080909141411111212131310100202010103",
    "17A57140000A42850825A71430825A42852474A71432474A85720000A28563299A57143299A99992474A99990825A28564949A14282474A57144949A42855774A14285774A00003299A000049492009100503030606100805040202010103070411071308141304081114121616170712151117150509",
    "16A49994173A99990759A00001897A87120000A44480000A15444316A14701043A99993083A84913984A00003510E30513367E69853225E69110901E29411897E72051897E485210911705141305041515161614130407140204070310061003080908020611091211010112",
    "16A00003849A16670962A33330000A16676735A66660000A83320962A33337697A99993849A66667697A83326735E83324810E49996735E83322887E49990962E16674810E16672887161602020303141405050606131308081111101009091212070704041515010116",
    "17A06651153A56331153A00007272A15759999A00009090A56332970A15754545A06652970A47249999A62989090A62987272A47244545A31490000E31493636E47246363E31499090E1575636318041605040317030507171407121512141115100909161011070812060602080113011302",
    "18A69995196A89995196A99993464A89991732A69991732A59993464A59996927A69998659A89998659A99996927A40003464A30005196A40006927A59990000A40000000A30001732A10001732A00003464220102020303040405050601060708080909100107021006111112121307130514141515161116171816171812",
    "18A40005196A59995196A69993464A59991732A40001732A30003464A69996928A89996928A99995196A89993464A10003464A00005196A10006928A30006928A49993464A69990000A49990000A49998609220102020303040405050601060708080909100207031011121213131406110114021504161617171514180718",
    "17A99992891A49990000A99990952A00000952A83330000A16660000A83335782A00002891A66668673A33338673A16665782E33336733E16663843E66666733E66660952E33330952E833338431716021502051506160717140709141012121111131308080404060305010317011009",
    "18A50003750A50001587A99990000A38055337A31250504A12503896A20424760A12501587A87493750A00005337A79570577A61940000A68744833A87491441E62590719E20422378E79572959E374046172308051605020501020716060810060710180601180407010409131713011311171409031411031514021512110212",
    "18A26160872A41280000A58720000A73830872A91270872A99992383A08720872A00002383A08723893A26163893A91273893A41284765A73833893A58724765E58723021E41283021E41281744E587217442001020203030404181817170101070708080909101016161515131314141212101311110606050504",
    "19A57143298A71432474A57144949A42852474A57141649A71430824A99992474A42855773A42850824A28563298A42854124A85720000A57140000A99990824A28564949A14282474A14285773A00003298A00004949220714020606121214010204090913130610041510030108030401150816181819101617151917110405010207",
    "19A29138599A32545200A00009919A53629999A72535319A07138599A60138879A75947359A50524360A46493040A52393200A47120000A33172040A64782279A35650680A61060920E39992279E59512080E3595759924060319060201010304010704190207191009181016141411110918161013111716121315171512150708020909050508",
    "18A83338796A16660979A00003911A33330000A00005865A99995865A66669775A66660000A16668796A83330979A33339775A99993911E50008796E83332932E16666842E50000979E16662932E8333684218081610081410121406121806041602041702031705031505091511091311071301071801",
    "20A93358165A33223593A66773593A33221633A16774532A66771633A83544532A16770694A50000694A00003593A50004532A99993593A00001633A99991633A75940000A90500000A75947145A66775470A93356205E8322069424101305100204040809040609030611020813070312141420200602051103120715061614151618031907171801191701",
    "21A51751924A51750189A66372528A37722565A48541396A62861924A36552075A21641999A23691509A95021396A09942641A19000000A04970000A00001509A70751509A74262150A88882603A84492037A99992037A84493924E169606792906030506020101030401070405020705211208211109091207090811131221131411131404081506161516031910171920181810151817201617",
    "20A83200000A66400000A99990000A33985090A66795090A83205090A17585090A99993327A99991714A50000000A33200000A16400000A00001714A00003427A00005090A00000000A99995090A50005090E50001714E5000332721010302011002051806051706081709080309191011101211161213161415071504071804201813141920",
    "21A99995173A38633013A26931504A22882200A92786421A22880000A04432955A60151579A55582231A55580149A76552418A72793029A00001158A09390000A80304259A84673649A80305700A99993649E94724259E08932200E4223237430200703200604040702042102030621030821100909021209111208101108201313071314140612151116151717161519161818191705050101191801",
    "21A93358655A33224083A66774083A33222123A16785022A66772123A83545022A16781184A49050000A00004083A50005022A99994083A00002123A99992123A75940490A90500490A75947635A66775961A93356696E83221184E500011842610130510020404082104062103061102081307031214142020060205110312071506161415161803190717180119170102092009",
    "22A33333849A33335773A50006735A66665773A66663849A50002886A83336735A99995773A99993849A83332886A16672886A00003849A00005773A16676735A16678659A33339622A50008659A83338659A83330962A66660000A50000962A16670962280102020303040405050601060708080909100407051011121213131401110214151616171703141507181920202121061019112221221718",
    "22A30772664A46152664A53841332A46150000A30770000A23081332A53843997A69223997A76912664A69221332A76915329A92305329A99993997A92302664A46155329A53846661A69226661A23083997A30775329A07691332A00002664A0769399727010202030304040505060106070808090910020703101112121313140811091407151516161711170118181915190620202121221822",
    "22A30008660A10008660A00006928A10005196A00003464A10001732A69998660A89998660A99996928A89995196A99993464A89991732A69991732A60000000A40000000A30001732E40006928E30005196E40003464E60003464E69995196E6000692827222121202019191818172217070808090910220721101011111212132013141515161619131406050504041816060302020101170403",
    "24A16673849A16675773A33336735A50005773A50003849A33332886A66666735A83325773A83323849A66662886A66660962A50000000A33330962A33338659A50009621A66668659A99998659A99996735A00006735A00008659A00000962A00002886A99992886A99990962310102020303040405050601060708080909100407051011121213130610110314141515160716171818080219192021220122232409232113112417161420",
    "24A31693170A31691056A49990000A68301056A68303170A89433170A99995000A89436830A68306830A68308943A49999999A31698943A31696830A10566830A00005000A10563170A86600000A99991340A99998660A86609999A13399999A00008660A00001340A13390000280102020303040405050606070708080909101011111212131314141515161601041706181817081910202019122114222221162302242423",
    "25A68361042A10676736A10673126A32261042A89323158A68368895A31618895A89326811A14140000A99751377A86340000A00001302A50240000A00004938A99754987A49499999A86349925A13409925A00008548A99758598A68366811A32263126A31616736A68363158A494949873224252325222521250124022322030422052406210723082109041005110112031304140315081606170618071902200820171505071601130214120918191110",
    "24A76718683A87797576A96755665A96754023A89382063A77440869A58510000A41080000A59929999A38329999A20659069A06467650A00005731A00003835A08841987A21650706E82286173E63078094E35928094E16716173E16713458E35921537E63071537E8228345824100909181019121111191220141313201421161515211622070808220723050606230524030404240317010202170118",
    "26A99991663A82650000A66210000A99990000A33330000A16890000A99993039A00001605A00003268A00006537A00008200A16899804A33339804A99996422A49770000A66669804A83099804A99998142A99999804A49779804A99994759A00009804A00004931A00000000E49776651E4977321127040102040302150326150515060524060824090823091023111022111222131220132520162017161917181914182114072101072526",
    "28A49997302A49992697A73025000A26975000A20233831A38327976A61687976A31576808A79763831A79766167A68086841A38322023A61682023A68423191A31573191A06743831A00005000A06746167A38320674A49990000A61680674A93253831A99995000A93256167A61689324A49999998A38329324A202361673204050106010706080309031010111107021202131314140912151505051616171718121919202021211309222223232424100725252626272706042828182808",
    "28A26160872A41280000A58720000A73830872A91270872A99995871A08720872A08722616A99994127A91272616A08727383A00005871A00004127A08729127A26169127A91277383A91279127A73839127A58729999A41289999E58728255E41288255E82555871E82554127E17445871E17444127E41281744E587217443201020203030404282827270101070708082626252511111212131308111414151522222121181819192020151817171616232324241010090906061610050504",
    "30A44366431A33185790A22067722A55474499A55475790A44363849A44367722A33184499A22142574A78864569A33331924A67136525A88962558A44440000A33330649A66663849A22143849A78635797A55630649A99991924A00006423A11115774A11114499A88800015A99990649A66660000A77770649A00087746A89043888A2214647033020103070405050130020604070108020917291010181109120513291415151116041723181219142013280321282221232224252520262727240806300316102619",
    "36A42856185A57146185A64284948A57143711A42853711A35714948A64282474A57141237A42851237A35712474A78564948A85713711A78562474A64287422A78567422A85716185A35717422A42858659A57148659A21434948A14296185A21437422A21432474A14293711A35710000A14291237A00003711A00006185A14298659A35719896A64289896A85718659A99996185A99993711A85711237A6428000048010202030304040505060106070808090910040705100311111212130713021414151516111601171718181914190620202121221722102323242024262309252821242730182229321519313412163336081335262536353433323130292827",
    "42A17323500A17326499A08665999A17327499A17322500A08664000A08665000A08662000A00002500A00003500A00006499A00007499A08667999A43302000A34641500A51961500A25982000A43307999A34648499A51968499A25987999A69286499A77935999A69287499A69283500A77934000A69282500A60622000A77935000A60627999A51960500A43300000A34640500A86593500A86592500A77932000A77937999A86597499A86596499A34649499A43309999A5196949948020302040105010603070706050808090910061011121213130403111415141615171705181918201921210422232224252625272728281626292923243030203132323333151631343535363627263424373738383923391940404141422042",
    "60A21159049A17778821A32689182A51019771A54399999A39459638A05577213A35427935A65078888A71849343A47678759A11047581A85878461A82498233A95786811A90306443A08305967A55447753A98515564A63245965A23246328A67698577A37587292A06883953A19256703A01416446A47485643A17834689A00004435A80685310A77586929A31054538A35284033A08213556A02733187A12641538A20943069A51044356A60942706A16031765A33451110A47510228A43082245A91646046A50851240A67475461A75283670A30831422A79273295A87472418A26680656A44130000A63102064A65830816A59060361A90224032A97103553A77360950A92952786A8075117890010201060112020302070304030804050409050605100611071707260818082109140918101310221122112312251226131413151416151915441619163017211724182019572030203821322231232523272435243725282629273327462833283429342935304931443146323732383343344035363640365137483839394539494041414241434252425443534456454845554647475347564851495050575058515252555354546055585659575958605960",
  };

#define NBONDTYPES 11

  const int bondValence[NBONDTYPES] = {1,2,3,1,1,0,0,0,1,1,1};

  const string fsastart="{SA:";
  const string fsbstart="{SB:";


  string intToStr(int k) {
    char temp[16];
    sprintf(temp,"%d",k);
    string line=temp;
    return line;
  };


  //-------------------------------------------------------------------
  class Rect {
  public:
    double left,top,right,bottom;
  };

  class Point {
  public:
    double x,y;
  };

  //-------------------------------------------------------------------
  class  TSingleAtom  {
  public:
    short int na;   /*Atom position in the Periodic Table (nucley charge)*/
    short int nv;   /*Current atom's valence*/
    short int nc;   /*-9..+9 atom's charge*/
    short int iz;   /*Isotope difference between round(AtomMass)*/
    double    rx;   /*Internal X-coordinate representation*/
    double    ry;   /*Internal Y-coordinate representation*/
    short int rl;   /*radical label*/
    short int nb;   /*Number of neightboring atoms*/
    int gtd;        /*Depth of atom in molecule according to GTD*/
    short int currvalence;
    /*Valence, excluding non-defined hydrogen
      atoms. Equal sum of valences for each  bond type.*/
    short int special;
    /*Special=0 - no special definition
      =1 - no other atoms, except explicitly defined, can
      be connected with the atom (query structure)*/
    short int ac[CONNMAX];
    /*atom's numbers in array ATOM, which are
      connected with the atom selected*/
    short int astereo;   /*=0 - no stereo, =1 - R, = 2 -S,  = 3 - unknown*/

    string anum;
    int enumerator;
    int fragIndex;

    TSingleAtom() {
      na=6; nv=hVal[na]; gtd=0;
      nc=0; iz=0; nb=0; rl=0; currvalence=0; special=0; astereo=0; enumerator=0; fragIndex=0;
    };
    TSingleAtom * clone();
    int encoder();
    int chargeConversion();
    int valencyConversion();
    int allAtAtom();
    void atomCopy(TSingleAtom * source);
    static bool atomEquivalent(TSingleAtom * structure, TSingleAtom * query,
                               int nHStr, int nHQuery, bool chargeSensitivity, bool isotopeSensitivity);
    static int chargeDeltaValency(int atomNo);
  };

  class  TSingleBond  {
  public:
    short int tb;
    /*Bond type:
      1 - single
      2 - double
      3 - triple
      4 - aromathic (query)
      5 - single/double (query)
      6 - coordinational
      7 - not used
      8 - any (query)
      9 - up
      10 - down
      11 - either*/
    short int at[2];     /*Bond definition-atoms number in array ATOM*/
    short int db;        /*Ring/Chain conditions*/

    // The original MCDL code used bstereo to store the bond stereo
    short int bstereo;   /* =0 - no, =1 - E , = 2 - Z, =3 E/Z*/
    // The new code uses bstereo_refs, the refs from the OBCisTransStereo object arranged in a U
    //
    //                            1       4
    //                             \     /
    //                              X = Y
    //                             /     \
    //                            2       3
    vector<unsigned long> bstereo_refs;

    short int special;
    int enumerator;
    /*=1 - Chain (query)
      =2 - Ring  (query)
      =3 - CIS/TRANS
      =4 - CIS/TRANS+Chain;
      =5 - CIS/TRANS+Ring;*/
    TSingleBond * clone();
    int bondConversion();
    void bondCopy(TSingleBond * source);
    static bool bondEquivalent(TSingleBond * sBond, TSingleBond * qBond);
    int getValence();
  };
  //-------------------------------------------------------------------
  TSingleAtom * TSingleAtom::clone() {
    TSingleAtom * result;
    result=new TSingleAtom();

    result->astereo=this->astereo;
    for (int i=0; i<CONNMAX; i++) result->ac[i]=this->ac[i];
    result->currvalence=this->currvalence;
    result->iz=this->iz;
    result->na=this->na;
    result->nb=this->nb;
    result->nc=this->nc;
    result->nv=this->nv;
    result->rl=this->rl;
    result->rx=this->rx;
    result->ry=this->ry;
    result->gtd=this->gtd;
    result->special=this->special;
    result->enumerator=this->enumerator;
    result->fragIndex=this->fragIndex;
    result->anum=this->anum;
    return result;
  };


  int TSingleAtom::chargeDeltaValency(int atomNo) {
    int result=-1;
    if (atomNo < NELEMMCDL) result=chargeVal[atomNo];
    return result;
  };

  int TSingleAtom::encoder() {
    // For given atom's number ATN in array ATOM returns a number from 1 to 32.
    //  Atoms with related properties have the same number. It is required to reduce
    //  the possible number of fragments in structure}
    int i;

    for (i=0; i<NEXACTATOMS; i++) if (exactAtom[i] == na) return i;
    for (i=0; i<NALKALYATOMS; i++) if (na == alkaly[i]) return 21;
    for (i=0; i<NALKALYEARTHATOMS; i++) if (na == alkalyEarth[i]) return 22;
    for (i=0; i<NTRIVALENTATOMS; i++) if (na == trivalent[i]) return 23;
    for (i=0; i<NTITANATOMS; i++) if (na == titan[i]) return 24;
    for (i=0; i<NVANADIUMATOMS; i++) if (na == vanadium[i]) return 25;
    for (i=0; i<NCHROMIUMATOMS; i++) if (na == cromium[i]) return 26;
    for (i=0; i<NMANGANESEATOMS; i++) if (na == manganeze[i]) return 27;
    for (i=0; i<NCOPPERATOMS; i++) if (na == copper[i]) return 28;
    for (i=0; i<NLIKEFEATOMS; i++) if (na == likeFe[i]) return 29;
    for (i=0; i<NZINKATOMS; i++) if (na == zink[i]) return 30;
    for (i=0; i<NPLATINUMATOMS; i++) if (na == platinum[i]) return 31;
    return 32;
  };

  int TSingleAtom::chargeConversion() {

    //  3 - if radical label present.
    //  2 - if charge <0
    //  1 - if charge >0
    //  0 - charge=0

    if (nc < 0) return 2;
    if (nc > 0) return 1;
    return 0;
  };

  int TSingleAtom::valencyConversion() {

    //for atom's number ATN in array ATOM returns some connected with valency value:
    // =2-Valence of ATN is less, then usual
    // =1-Valence of ATN is more, then usual
    // =0-usual valency


    int k1,k2;
    int result=0;

    //Default hydrogen
    k1=nv;
    k1=k1-currvalence-abs(nc)-rl;
    if (k1<0) k1=0;
    k2=(na >= 0 && na < NELEMMCDL) ? hVal[na] : 0;
    k2=k2-currvalence-abs(nc)-rl;
    if (k2<0) k2=0;
    if (k1 == k2) result=0; else if (k1 < k2) result=1; else result=2;
    return result;
  };

  int TSingleAtom::allAtAtom() {
    //Define a digital representation of atom, they include:
    //  a) Position of atom in the Periodic System
    //  b) Its charge
    //  c) Its valency}

    int b1,b2,b3,w;

    b1=encoder();
    b2=chargeConversion();
    b3=valencyConversion();
    w=b3;
    w=w << 2;
    w=w+b2;
    w=w << 5;
    w=w+b1;
    if (rl != 0) w= ~w;
    return w;
  };

  void TSingleAtom::atomCopy(TSingleAtom * source) {

    this->astereo=source->astereo;
    for (int i=0; i<CONNMAX; i++) this->ac[i]=source->ac[i];
    this->currvalence=source->currvalence;
    this->iz=source->iz;
    this->na=source->na;
    this->nb=source->nb;
    this->nc=source->nc;
    this->nv=source->nv;
    this->rl=source->rl;
    this->rx=source->rx;
    this->ry=source->ry;
    this->special=source->special;
  };

  bool TSingleAtom::atomEquivalent(TSingleAtom * structure, TSingleAtom * query,
                                   int nHStr, int nHQuery, bool chargeSensitivity, bool isotopeSensitivity) {
    bool result=false;
    int i,j,k;

    if (structure == nullptr || query == nullptr) return result;
    i=nHQuery;
    if (i>0) {   //if explicitly defined H is accociated with query atom
      j=structure->nv;
      k=abs(structure->nc);
      if (k>9) k=k-9;
      j=j-structure->currvalence-k;
      if (j<0) j=0;
      j=j+nHStr;
      if (i>j) return result;
      //on corresponding structure atom must be at least the same number of H}
    }
    if (((structure->nc != query->nc) && chargeSensitivity)
        || ((structure->rl != query->rl) && chargeSensitivity)
        || ((structure->iz != query->iz) && isotopeSensitivity)) return result;
    //non-equivalency of Charge and Isotop is case of exact matching of these attributes
    i=query->special; //'NO OTHER' attribute on query
    if (i == 1)  if ((structure->nb-nHStr) != query->nb) return result;
    //'NO OTHER' means, that number of neighbour in query must be the same as in structure
    //Checking for equivalent position in the Periodic Table
    if (structure->na == query->na) result=true; else {
      if (query->na == METALL_ATOM) { //Metall checking
        for (i=0; i<NMETALS; i++) if (structure->na == metals[i]) {
            result=true;
            break;
          }
      }
      if (query->na == HALOGEN_ATOM) { //Halogen checking
        for (i=0; i<NHALOGENS; i++) if (structure->na == halogens[i]) {
            result=true;
            break;
          }
      }
      if (query->na == HETERO_ATOM) { //Hetero checking
        for (i=0; i<NHETERO; i++) if (structure->na == hetero[i]) {
            result=true;
            break;
          }
      }
      if (query->na == ANY_ATOM) result=true; //Any atom
    }
    return result;
  };

  //----------------  TSingleBond methods ----------------------
  TSingleBond * TSingleBond::clone() {
    TSingleBond * result;
    result=new TSingleBond();

    result->at[0]=this->at[0];
    result->at[1]=this->at[1];
    result->bstereo=this->bstereo;
    result->bstereo_refs=this->bstereo_refs;
    result->db=this->db;
    result->special=this->special;
    result->tb=this->tb;
    result->enumerator=this->enumerator;
    return result;
  };

  int TSingleBond::getValence() {
    int result=0;
    if (this->tb >= 1 && this->tb <= NBONDTYPES) result=bondValence[this->tb-1];
    return result;
  };

  bool TSingleBond::bondEquivalent(TSingleBond * sBond, TSingleBond * qBond){
    //for bond's number BONDNUMBER in structure (BOND) and for query bond's number
    //QBONDNUMBER (QBOND) determines, if they may be accociated one with other.
    //QBC-array, for each query bond contains explicitly defined cyclic conditions:
    // 0-no cyclic condition is implemented
    // 1-query bond and corresponding structure bond must be a Chain
    // 2-query bond and corresponding structure bond must be a Ring
    //Function has 'TRUE' value if bonds can be matched, FALSE otherwise

    bool test1;
    int bT,qBT,bD,qBD;
    bool result=false;

    bT=sBond->tb; qBT=qBond->tb;
    bD=sBond->db; qBD=qBond->db;
    if (sBond->special>=3) sBond->special=sBond->special-3;
    if (qBond->special>=3) qBond->special=qBond->special-3;
    if (((qBond->special==1) && (bD>1)) || ((qBond->special==2) && (bD<2))) return result;
    //Explicitly defined cyclic conditions are violated
    if ((qBD>1) && (bD<2)) return result;
    //Implicitly defined cyclic conditions are violated}
    if (qBT==ANY_BOND) {  //Any bond in query
      result=true;
      return result;
    };
    if ((qBT==4) || (qBD==2) || (qBD==3)) { //Aromatic bond
      result=(bD==2) || (bD==3) || (bT==4);
      return result;
    };
    if ((bD==2) || (bD==3)) {
      //non-Aromatic in query, but Aromatic in structure
      result=false;
      return result;
    };
    test1=false;
    if ((qBT==5) && ((bT==1) || (bT==2) || (bT==5))) test1=true;
    //SINGLE/DOUBLE query bond
    if (bT==qBT) test1=true;
    //Type of bonds in structure and in query are equivalent}
    result=test1;
    return result;
  };


  int TSingleBond::bondConversion() {
    //generate a code for bond's nuber BNB in array BOND. It is took into consi-
    //deration bond type and cycle size
    int b1,b2;

    if (tb > 4) b1=0; else b1=tb;
    b2=7; //for other Switch value
    switch (db) {
    case 0 :
      b2=5;
      break;
    case 1 :
      b2=0;
      break;
    case 2 :
      b1=4;
      b2=1;
      break;
    case 3 :
      b1=4;
      b2=2;
      break;
    case 4 :
      b2=3;
      break;
    case 5 :
      b2=4;
      break;
    case 6 :
      b2=6;
      break;
    };
    b2=b2 << 2;
    b2=b2+b1;
    return b2;
  };

  void TSingleBond::bondCopy(TSingleBond * source) {
    this->at[0]=source->at[0];
    this->at[1]=source->at[1];
    this->bstereo=source->bstereo;
    this->db=source->db;
    this->special=source->special;
    this->tb=source->tb;
  };

  //******************************************************************
  //                      TSimpleMolecule
  //------------------------------------------------------------------
  class TSimpleMolecule {
  protected:
    std::vector<TSingleAtom*> fAtom;
    std::vector<TSingleBond*> fBond;
  public:
    std::ostream * refofs;
    virtual ~TSimpleMolecule() {
      clear();
    };
    TSimpleMolecule() {
      refofs = nullptr;
    };

    int nAtoms();
    int nBonds();
    TSingleAtom * getAtom(int index);
    TSingleBond * getBond(int index);
    void defineAtomConn();
    void defineBondConn(neighbourlist *bondConnection);
    void newB(neighbourlist * bk, int bnum, int anum, int & total, int * e, int * e1);
    void singleVawe(neighbourlist * bk, std::vector<int> & alreadyDefined,
                    std::vector<int> & prevBond, std::vector<int> & prevAtom,
                    int & nPrev, std::vector<int> & curBond, std::vector<int> & curAtom);
    void vaweBond(int bondN, neighbourlist * bk, int & ringSize, std::vector<int> & bondList);
    void allAboutCycles();
    void redraw(const std::vector<int>listAtomClean, const std::vector<int>listBondClean,
                int atomClean, int & bondClean, int spn, int sCHA1, int sCHB1, bool iOPT7);
    void clear();
    void readOBMol(OBMol * pmol);
    void readConnectionMatrix(const std::vector<int>iA1, const std::vector<int>iA2, int nAtoms, int nBonds);
    void readConnectionMatrix(const std::vector<int>iA1, const std::vector<int>iA2, const std::vector<double>rx, const std::vector<double>ry, int nAtoms, int nBonds);
    void redrawMolecule();
    void getMolfile(std::ostream & data);
    bool checkOverlapped();
    double averageBondLength();
    void flipSmall(int cHB);
    int listarSize();
    bool makeFragment(std::vector<int>& list, int aT, int aTEx);
    void moleculeCopy(TSimpleMolecule & source);
    int correctOverlapped();
    void normalizeCoordinates(double aveBL);
    void makeEquivalentList(std::vector<int>& equivalenceList, bool isTopologyOnly);
    void bondEnlarge(int bN);
    void deleteAtom(int index);
    void deleteBond(int index);
    void addAtom(TSingleAtom * sa);
    void addAtom(int na, int charge, double rx, double ry);
    void addBond(TSingleBond * sb);
    void addBond(int tb, int at1, int at2);
    void setCoordinatesString(string value);
    void unitVector(int aN, double& xV, double& yV);
    void bondUnitVector(int bn, double& xv, double& yv);
    double bondLength(int index);
    int singleAtomicDescriptor(int aNumber,int bNumber, bool useEnumerator);
    int hasOverlapped(double delta, bool findFirst);
    int getNH(int atomNo);
    bool correctDblBondStereo();
  private:
    bool aromatic(int cycleSize, const std::vector<int> bondList, std::vector<int>& arom);
    void twoAtomUnitVector(int na1, int na2, double & xv, double & yv, const std::vector<int>atomDefine);
    void defC(int& currNumDef, int baseCycle, int atomClean, std::vector<int>& cycleDefine,
                 std::vector<int>& atomDefine, std::vector<std::vector<int> >& atomCycle, std::vector<int>& dsATN,
                 std::vector<int>& dsTP,
                 std::vector<int>& dsSC, std::vector<int>& dsNA1, std::vector<int>& dsNA2);
    void defA(int& currNumDef, int atomClean, int sPN, int baseCycle, std::vector<int>& atomDefine, const std::vector<int> listAtomClean,
              std::vector<int>& cycleDefine, std::vector<std::vector<int> >& atomCycle,
              std::vector<int>& dsATN, std::vector<int>& dsTP, std::vector<int>& dsNA1, std::vector<int>& dsNA2);
    void canonizeCycle(int ringSize, std::vector<int> & bondList);
    //Chain rotate members
    double atomDistanceMetric(int an);
    bool bondsOverlapped(int bN1, int bN2, double delta);
    int fragmentSecond(int sphere, int att, int secAt, const std::vector<int> a,
                       const std::vector<int> b, const neighbourlist *bk, std::vector<int>& wSphere);
    bool threeBondResolve(int an, int bondExcluded, double& xv, double& yv, neighbourlist* bkExt);
    bool unitVectorCoincident(int aN, double xV, double yV);
    int setupRotorSearch(const vector<int> &rotBondList, vector<int>& inner_bonds, vector<int>& remainder);
  };

  int TSimpleMolecule::getNH(int atomNo) {
    int result=0;
    TSingleAtom * atom;
    int i,n;

    if (atomNo >= nAtoms()) return result;
    atom=getAtom(atomNo);
    result=atom->nv;
    result=result-(atom->currvalence)+(atom->nc*TSingleAtom::chargeDeltaValency(atom->na))-(atom->rl);
    if (result < 0) result=0;
    if (atom->nb > 0) for (i=0; i<atom->nb; i++) {
        n=atom->ac[i];
        if (getAtom(n)->na == 1) result=result+1;
      };
    return result;
  };

  int TSimpleMolecule::singleAtomicDescriptor(int aNumber,int bNumber, bool useEnumerator) {
    //Bond BNumber has to have type=9 or 10
    int result=0;
    int an [4] = {0};
    int j,m,k;
    double x[3];
    double y[3];
    double r,r1,r2;
    bool testBad;
    double tn [2];
    bool rsn;
    bool isInvert;

    if ((getAtom(aNumber)->nb < 3) || (getAtom(aNumber)->nb > 4)) return result;
    for (j=0; j<getAtom(aNumber)->nb; j++) an[j]=getAtom(aNumber)->ac[j];
    if (useEnumerator) {
      //fragIndex as main base
      for (j=0; j<(getAtom(aNumber)->nb-1); j++) for (m=j+1; m<getAtom(aNumber)->nb; m++)
                                                   if (getAtom(an[j])->fragIndex > getAtom(an[m])->fragIndex) {
                                                     k=an[j];
                                                     an[j]=an[m];
                                                     an[m]=k;
                                                   };
    } else {
      for (j=0; j<(getAtom(aNumber)->nb-1); j++) for (m=j+1; m<getAtom(aNumber)->nb; m++)
                                                   if (an[j] > an[m]) {
                                                     k=an[j];
                                                     an[j]=an[m];
                                                     an[m]=k;
                                                   };
    };

    //  return 1;

    for (j=0; j<3; j++) {
      k=an[j];
      x[j]=getAtom(k)->rx-getAtom(aNumber)->rx;
      y[j]=getAtom(k)->ry-getAtom(aNumber)->ry;
    };

    isInvert=true;
    if (getAtom(aNumber)->nb == 4) if (getBond(bNumber)->at[1] != an[3]) {
        isInvert=false;
        for (j=0; j<3; j++) if (an[j] == getBond(bNumber)->at[1]) {
            k=an[3];
            x[j]=getAtom(k)->rx-getAtom(aNumber)->rx;
            y[j]=getAtom(k)->ry-getAtom(aNumber)->ry;
          };
      };
    testBad=false;
    for (j=0; j<3; j++) {
      r=sqrt(x[j]*x[j]+y[j]*y[j]);
      if (r == 0) testBad=true; else {
        x[j]=x[j]/r;
        y[j]=y[j]/r;
      };
    };

    //  return 1;

    if (! testBad) {
      for (j=0; j<2; j++) { //determination of the sign of rotation
        r1=x[0]*y[j+1]-y[0]*x[j+1];     //Sin
        r2=x[0]*x[j+1]+y[0]*y[j+1];     //Cos
        if (r1 < 0) r2=-2-r2;           // 0 degress = +1; Pi/2 degrees = 0; Pi degrees = -1; 3*Pi/2 degrees = -2; 2*Pi degrees = -3
        tn[j]=r2;
      };
      rsn=( tn[0] > tn[1]);
      //return 1;

      //Analizing cases....
      if (getBond(bNumber)->tb == 10) rsn=! rsn;
      if (getAtom(aNumber)->nb == 4) if (isInvert) rsn=! rsn;
      if (tn[0] != tn[1]) {
        if (rsn) result=1; else result=2;
      };
    };
    return result;
  };


  void TSimpleMolecule::bondUnitVector(int bn, double& xv, double& yv) {
    //for bon's number BN in the structure, described by ATOM, BOND, CONN calculates
    //the unit vector (Xv,Yv on output). The vector is best direction to add new fra-
    //gment to current structure. The procedure is used by TEMPLATE and MAKEPOLI}

    double si,r1,r2,r3,s1,s2,s3,s4,x1,y1,y2;
    int na1,na2,i;

    na1=getBond(bn)->at[0];
    na2=getBond(bn)->at[1];
    s1=getAtom(na1)->rx;
    s2=getAtom(na1)->ry;
    s3=getAtom(na2)->rx;
    s4=getAtom(na2)->ry;
    r1=s1-s3;
    r2=s2-s4;
    r3=sqrt(r1*r1+r2*r2);
    r1=r1/r3; //COS
    r2=r2/r3; //SIN
    si=0;
    for (i=0; i<getAtom(na1)->nb; i++) if (getAtom(na1)->ac[i] != na2) {
        x1=getAtom(getAtom(na1)->ac[i])->rx-s1;
        y1=getAtom(getAtom(na1)->ac[i])->ry-s2;
        y2=x1*r2-y1*r1;
        if (y2 != 0) si=si+y2/abs(y2);
      }
    for (i=0; i<getAtom(na2)->nb; i++) if (getAtom(na2)->ac[i] != na1) {
        x1=getAtom(getAtom(na2)->ac[i])->rx-s3;
        y1=getAtom(getAtom(na2)->ac[i])->ry-s4;
        y2=x1*r2-y1*r1;
        if (y2 != 0) si=si+y2/abs(y2);
      }
    if (si != 0) si=si/abs(si); else si=1;
    xv=-r2*si; yv=r1*si;
  }


  bool TSimpleMolecule::threeBondResolve(int an, int bondExcluded, double& xv, double& yv, neighbourlist* bkExt) {
    //Addition from 16 April 2006
    int bondNoList [3];
    bool result=false;
    double centerX[3];
    double centerY[3];
    unsigned int nBondNo;
    neighbourlist* bk;
    std::vector<int>bondList;
    std::vector<int>* blStore = nullptr;
    bool testBad,testOK;
    unsigned int m, j, n1, n2, n, k;
    int rs;
    double dist,x,y,minDist;
    unsigned int i;
    bool test;
    int at;
    double r1,r2,s1,s3;

    if (bkExt != nullptr) {
      bk=bkExt;
    } else {
      bk=(neighbourlist *)calloc(nAtoms(), sizeof(adjustedlist));
      defineBondConn(bk);
    }
    nBondNo=0;
    testBad=false;
    testOK=true;

    for (i=0; i<bk[an].nb; i++) {
      n=bk[an].adjusted[i];
      if (n != bondExcluded) {
        vaweBond(n,bk,rs,bondList);
        if (rs > 0) {
          //I have to analize bondList to determine second cycle to exclude adamanthane
          if (blStore == nullptr) {
            //Save
            blStore= new std::vector<int>(rs);
            for (j=0; j<blStore->size(); j++) (*blStore)[j]=bondList[j];
          } else {
            m=0;
            for (j=0; j<blStore->size(); j++) {
              test=false;
              for (k=0; k<rs; k++) if (bondList[k] == (*blStore)[j]) {
                  test=true;
                  break;
                };
              if (test) m++;
            };
            if ((m > 1) && (m < blStore->size())) {
              testOK=false;
            };
          };
          //center determination
          centerX[nBondNo]=0;
          centerY[nBondNo]=0;
          for (j=0; j<rs; j++) {
            m=bondList[j];
            n1=getBond(m)->at[0];
            n2=getBond(m)->at[1];
            centerX[nBondNo]=centerX[nBondNo]+getAtom(n1)->rx+getAtom(n2)->rx;
            centerY[nBondNo]=centerY[nBondNo]+getAtom(n1)->ry+getAtom(n2)->ry;
          };
          centerX[nBondNo]=centerX[nBondNo]/(2*rs);
          centerY[nBondNo]=centerY[nBondNo]/(2*rs);
          bondNoList[nBondNo]=n;
          nBondNo++;
        };
      };// else testBad:=true;
      if ((nBondNo == 3) || (testBad)) break;
    };
    if (nBondNo < 2) testBad=true;

    if ((! testBad) && testOK) {
      dist=0;
      if (nBondNo == 2) {
        //single bond, attached to ring. Re-definition center....
        x=0; y=0;
        for (i=0; i<nAtoms(); i++) {
          x=x+getAtom(i)->rx;
          y=y+getAtom(i)->ry;
        };
        x=x/nAtoms();
        y=y/nAtoms();
        for (i=0; i<nBondNo; i++) {
          centerX[i]=x;
          centerY[i]=y;
        };
      };
      for (i=0; i<nBondNo; i++) {
        at=getBond(bondNoList[i])->at[0];
        if (at == an) at=getBond(bondNoList[i])->at[1];
        r1=getAtom(at)->rx-getAtom(an)->rx;
        r2=getAtom(at)->ry-getAtom(an)->ry;
        s1=sqrt(r1*r1+r2*r2);
        if (s1 == 0) testBad=true; else {
          r1=r1/s1; r2=r2/s1;
          x=-r1;
          y=-r2;
          minDist=1000000000;
          for (j=0; j<nBondNo; j++) {
            r1=(x*s1+getAtom(an)->rx-centerX[j]);
            r2=(y*s1+getAtom(an)->ry-centerY[j]);
            s3=sqrt(r1*r1+r2*r2);
            if (s3 < minDist) minDist=s3;
          };
          if (minDist > dist) {
            dist=minDist;
            xv=x;
            yv=y;
          };
        };
      };
      if (! testBad) result=true;
    };
    //end addition from 16 April 2006
    if (bkExt == nullptr) free(bk);
    delete blStore;
    return result;
  };

  bool TSimpleMolecule::unitVectorCoincident(int aN, double xV, double yV) {
    bool result=false;
    int i, aT;
    double r1,r2,s1;

    for (i=0; i<getAtom(aN)->nb; i++) {
      aT=getAtom(aN)->ac[i];
      r1=getAtom(aT)->rx-getAtom(aN)->rx;
      r2=getAtom(aT)->ry-getAtom(aN)->ry;
      s1=sqrt(r1*r1+r2*r2);
      if (s1 > 0.00001) {
        r1=r1/s1;
        r2=r2/s1;
        if ((abs(r1-xV) < 0.1) && (abs(r2-yV) < 0.1)) result=true;
      };
      if (result) break;
    };
    return result;
  };

  void TSimpleMolecule::unitVector(int aN, double& xV, double& yV) {
    //For atom's number AN in the array ATOM (the same structure is described with
    //bond's array BOND and bond-connection matrix invariants CONN) unit vector
    //is calculated (XV, YV) on output. Unit vector shows the best direction to
    //make new bond}
    double sc[4] = {0,1/2,1.7320508/2,1};
    double cc[4] = {1,1.7320508/2,1/2,0};
    double sQ3=sqrt(3.0)/2.0;
    double si,r1,r2,r3,r4,s1,s2,s3,s4,fi;
    double xm[3];  //Initial dimensions 1..3
    double ym[3];  //Initial dimensions 1..3
    int i,i1,i2;
    int nB1,aT,aT1;
    bool mK[CONNMAX] = {false};
    bool test;

    nB1=1;
    if (getAtom(aN)->nb == 0) {
      xV=1;
      yV=0;               //if no atoms connected-horizontal unit vector
      return;
    } else if (getAtom(aN)->nb == 1) {  //single atom connected-start calculations}
      aT=getAtom(aN)->ac[0];
      r1=getAtom(aT)->rx-getAtom(aN)->rx;
      r2=getAtom(aT)->ry-getAtom(aN)->ry;
      s1=sqrt(r1*r1+r2*r2);
      if (s1 == 0) {
        xV=0.3826834;
        yV=-0.9238795;
        return;
      }
      r1=r1/s1; r2=r2/s1;
      nB1=getAtom(aT)->nb;
      si=1;
      if (nB1 > 1) {
        aT1=getAtom(aT)->ac[0];
        if (aT1 == aN) aT1=getAtom(aT)->ac[1];
        r3=getAtom(aT1)->rx-getAtom(aN)->rx;
        r4=getAtom(aT1)->ry-getAtom(aN)->ry;
        s2=sqrt(r3*r3+r4*r4);
        if (s2 == 0) s2=1;
        r3=r3/s2; r4=r4/s2;
        si=r2*r3-r4*r1;
        if (si != 0) si=si/abs(si); else si=1;
      }
      s3=sqrt(3.0)/2.0;
      s4=-0.5;
      xV=r1*s4-r2*si*s3;  //single atom connected-unit vector at 2Pi/3 angle
      yV=r2*s4+r1*si*s3;
    } else {            //multiply connection case
      xV=0;
      yV=0;
      for (i=0; i<getAtom(aN)->nb; i++) mK[i]=true;
      if (getAtom(aN)->nb == 3) {
        //three-bond connection-search for projec. of tetrahedron

        if (threeBondResolve(aN,-1,xV,yV,nullptr)) {
          return;
        };

        for (i=0; i<3; i++) {
          aT=getAtom(aN)->ac[i];
          xm[i]=getAtom(aT)->rx-getAtom(aN)->rx;
          ym[i]=getAtom(aT)->ry-getAtom(aN)->ry;
          r1=sqrt(xm[i]*xm[i]+ym[i]*ym[i]);
          xm[i]=xm[i]/r1; ym[i]=ym[i]/r1;
        }
        i=0;
        do {      //Search for bond, which make 30 degree angle with another
          i1=1; i2=2;
          switch (i) {
          case 0: {
            i1=1; i2=2; break;
          }
          case 1: {
            i1=0; i2=2; break;
          }
          case 2: {  //Else value - only three
            i1=0; i2=1; break;
          }
          }
          s1=xm[i1]*xm[i2]+ym[i1]*ym[i2];
          s2=xm[i]*xm[i1]+ym[i]*ym[i1];
          s3=xm[i]*xm[i2]+ym[i]*ym[i2];
          test=false;
          if (abs(s1+0.5) < 0.05) {  //two bonds form 120 degrees angle
            test=(abs(s2-sQ3)<0.05) || (abs(s3-sQ3)<0.05);
            if (! test) test=((abs(s2) < 0.05) && (abs(s3+sQ3)<0.05))
                          || ((abs(s3)<0.05) && (abs(s2+sQ3)<0.05));
          }
          i++;
        } while (! (test || (i == 3)));
        if (test) mK[i-1]=false;  //In the original Java code without -1
      }
      for (i=0; i<getAtom(aN)->nb; i++) if (mK[i]) {
          aT=getAtom(aN)->ac[i];
          r1=getAtom(aT)->rx-getAtom(aN)->rx;
          r2=getAtom(aT)->ry-getAtom(aN)->ry;
          s1=sqrt(r1*r1+r2*r2);
          if (s1 < 0.05) s1=1;
          r1=r1/s1; r2=r2/s1;
          xV=xV-r1;
          yV=yV-r2;
        }
      r1=sqrt(xV*xV+yV*yV);
      if (r1 > 0.05) {
        //unit vector may be calculated from current connection
        xV=xV/r1;
        yV=yV/r1;
      } else {
        //impossible to calculate unit vector-more definitions
        if (getAtom(aN)->nb == 2) {    //linear existing connection-Pi/2 angle
          aT=getAtom(aN)->ac[0];
          r1=getAtom(aT)->rx-getAtom(aN)->rx;
          r2=getAtom(aT)->ry-getAtom(aN)->ry;
          s1=sqrt(r1*r1+r2*r2);
          if (s1 < 0.05) {
            xV=0.3826834;
            yV=-0.9238795;
            return;
          }
          r1=r1/s1; r2=r2/s1;
          xV=-r2; yV=-r1;
        } else if (getAtom(aN)->nb == 3) { //3-bonds connection - projection of tetrahedrone is calculated
          //Which of bonds has the horizontal direction
          r3=100000;
          for (i=0; i<3; i++) {
            aT=getAtom(aN)->ac[i];
            r1=getAtom(aT)->rx-getAtom(aN)->rx;
            r2=getAtom(aT)->ry-getAtom(aN)->ry;
            s1=sqrt(r1*r1+r2*r2);
            if (s1 < 0.05) {
              xV=0.3826834;
              yV=-0.9238795;
              return;
            }
            r1=abs(r1/s1); r2=abs(r2/s1);
            if (r1 < r3) {r3=r1; nB1=i;}
            if (r2 < r3) {r3=r2; nB1=i;}
          }
          aT=getAtom(aN)->ac[nB1];       //Horizontal or vertical bond found}
          r1=getAtom(aT)->rx-getAtom(aN)->rx;
          r2=getAtom(aT)->ry-getAtom(aN)->ry;
          s1=sqrt(r1*r1+r2*r2);
          r1=r1/s1; r2=r2/s1;
          xV= r1*cos(150*PI/180)+r2*sin(150*PI/180);
          yV=-r1*sin(150*PI/180)+r2*cos(150*PI/180);
        } else {
          xV=sqrt(2.0)/2.0; //other case - Pi/4 to horizont angle
          yV=-xV;
        }
      }

      //checking if coincided xV and uV with existing bonds
      if (unitVectorCoincident(aN,xV,yV)) {
        fi=15*PI/180.0;
        r3=cos(fi);
        r4=sin(fi);
        r1= xV*r3+yV*r4;
        r2=-xV*r4+yV*r3;
        if (unitVectorCoincident(aN,r1,r2)) {
          r1=xV*r3-yV*r4;
          r2=xV*r4+yV*r3;
        };
        if (unitVectorCoincident(aN,r1,r2)) {
          fi=7.5*PI/180.0;
          r3=cos(fi);
          r4=sin(fi);
          r1= xV*r3+yV*r4;
          r2=-xV*r4+yV*r3;
          if (unitVectorCoincident(aN,r1,r2)) {
            r1=xV*r3-yV*r4;
            r2=xV*r4+yV*r3;
          };
        };
        xV=r1;
        yV=r2;
      };
    };
    //Correction of angles, closed to 0, 30, 60, 90 degrees to exact values
    if (getAtom(aN)->nb < 6) for (i=0; i<4; i++) if ((abs(abs(xV)-sc[i])<0.04)
                                                     && (abs(abs(yV)-cc[i]) < 0.04)) {
          if (xV < 0) xV=-sc[i]; else xV=sc[i];
          if (yV < 0) yV=-cc[i]; else yV=cc[i];
        }
  }

  void TSimpleMolecule::clear() {
    for (unsigned int i=0; i<fAtom.size(); i++) delete(fAtom.at(i));
    fAtom.clear();
    for (unsigned int i=0; i<fBond.size(); i++) delete(fBond.at(i));
    fBond.clear();
  };

  void TSimpleMolecule::setCoordinatesString(string value){
    //set back above prcedure
    TSingleAtom * sa;
    TSingleBond * sb;
    int i,n,k,kk;
    string s;

    clear();
    n=0;
    s=value.substr(n,2); //2 symbols - number of atoms
    n=n+2;
    kk=strtol(s.c_str(),nullptr,10);
    for (i=0; i<kk; i++) {
      sa=new TSingleAtom();
      s=value.substr(n,1);
      if (s == "1") sa->na=101; else
        if (s == "2") sa->na=102; else
          if (s == "3") sa->na=103; else
            if (s == "A") sa->na=ANY_ATOM; else
              if (s == "E") {
                sa->na=ANY_ATOM;
                sa->special=1;
              } else sa->na=6;//Atom.positionofAtom(s);
      n=n+1;
      s=value.substr(n,4);
      n=n+4;
      k=strtol(s.c_str(),nullptr,10);
      sa->rx=(double)k/10000.0;
      s=value.substr(n,4);
      n=n+4;
      k=strtol(s.c_str(),nullptr,10);
      sa->ry=(double)k/10000.0;
      addAtom(sa);
    };
    s=value.substr(n,2);  //2 symbols - number of bonds
    n=n+2;
    kk=strtol(s.c_str(),nullptr,10);
    for (i=0; i<kk; i++) {
      sb=new TSingleBond();
      sb->tb=ANY_BOND;  //any bond
      s=value.substr(n,2);
      n=n+2;
      k=strtol(s.c_str(),nullptr,10);
      sb->at[0]=k-1;
      s=value.substr(n,2);
      n=n+2;
      k=strtol(s.c_str(),nullptr,10);
      sb->at[1]=k-1;
      addBond(sb);
    };
  };


  void TSimpleMolecule::addAtom(TSingleAtom * sa){
    fAtom.push_back(sa);
  };

  void TSimpleMolecule::addAtom(int na, int charge, double rx, double ry) {
    TSingleAtom * sa;
    sa=new TSingleAtom();
    sa->na=na;
    sa->nc=charge;
    sa->rx=rx;
    sa->ry=ry;
    fAtom.push_back(sa);
  };

  void TSimpleMolecule::addBond(TSingleBond * sb){
    fBond.push_back(sb);
  };

  void TSimpleMolecule::addBond(int tb, int at1, int at2){
    TSingleBond * sb;
    sb=new TSingleBond();
    sb->tb=tb;
    sb->at[0]=at1;
    sb->at[1]=at2;
    fBond.push_back(sb);
  };

  void TSimpleMolecule::moleculeCopy(TSimpleMolecule & source) {
    TSingleAtom * sa;
    TSingleBond * sb;

    clear();
    for (int i=0; i<source.nAtoms(); i++) {
      sa=source.getAtom(i);
      fAtom.push_back(sa->clone());
    };
    for (int i=0; i<source.nBonds(); i++) {
      sb=source.getBond(i);
      fBond.push_back(sb->clone());
    };
    if (refofs == nullptr) refofs=source.refofs;
  };

  void TSimpleMolecule::deleteBond(int index) {
    std::vector<TSingleBond*> tempBond(nBonds());
    int i,n;

    n=0;
    //bond deletion
    for (i=0; i<nBonds(); i++) if (i != index) {
        tempBond[n]=getBond(i);
        n++;
      } else {
        delete(getBond(i));
        fBond[i]=nullptr;
      };
    fBond.resize(n);
    for (i=0; i<n; i++) fBond[i]=tempBond[i];
    tempBond.clear();
  };


  void TSimpleMolecule::deleteAtom(int index) {
    std::vector<TSingleAtom*> tempAtom(nAtoms()-1);
    std::vector<TSingleBond*> tempBond(nBonds());
    unsigned int i, n;

    n=0;
    //atom deletion
    for (i=0; i<nAtoms(); i++) if (i != index) {
        tempAtom[n]=getAtom(i);
        n++;
      } else {
        delete(getAtom(i));
        fAtom[i]=nullptr;
      };
    fAtom.resize(n);
    for (i=0; i<n; i++) fAtom[i]=tempAtom[i];
    tempAtom.clear();
    //connected bonds deletion
    n=0;
    for (i=0; i<tempBond.size(); i++) {
      if ((getBond(i)->at[0] == index) || (getBond(i)->at[1] == index)) {
        delete(getBond(i));
        fBond[i]=nullptr;
      } else {
        if (getBond(i)->at[0] > index) getBond(i)->at[0]=getBond(i)->at[0]-1;
        if (getBond(i)->at[1] > index) getBond(i)->at[1]=getBond(i)->at[1]-1;
        tempBond[n]=getBond(i);
        n++;
      };
    };
    fBond.resize(n);
    for (i=0; i<n; i++) fBond[i]=tempBond[i];
    tempBond.clear();
  };


  double TSimpleMolecule::bondLength(int index) {
    double result=1;
    double x,y;
    int k1,k2;
    k1=getBond(index)->at[0];
    k2=getBond(index)->at[1];
    x=getAtom(k1)->rx-getAtom(k2)->rx;
    y=getAtom(k1)->ry-getAtom(k2)->ry;
    result=sqrt(x*x+y*y);
    return result;
  };

  int TSimpleMolecule::listarSize() { // Probably should be removed and replaced with either nAtoms() or nBonds() as appropriate
    int result=10;  //Minimal vector size 10
    if (nAtoms() > result) result=nAtoms();
    if (nBonds() > result) result=nBonds();
    return result;
  };

  bool TSimpleMolecule::makeFragment(std::vector<int>& list, int aT, int aTEx) {
    //Starting from atom's number AT in bond-connection matrix invariants array CONN
    //the all connected atom's (through one or more bonds) numbers are inserted into
    //the LIST vector. If ATEX non-equal
    //zero, than atom with this number and all other, which is connected through
    //atom ATEX, don't include in LIST array. Boolean variable TEST has TRUE value
    //on output if between AT and ATEX exist cyclic bond, false otherwise}
    int i,j,k,l;
    bool test, test1;
    list.resize(0);

    test=false;
    if ((nAtoms() ==0 ) || (aT < 0) || (aT >= nAtoms())) {
      return test;
    }

    list.push_back(aT);
    for (i=0; i<getAtom(aT)->nb; i++) if (getAtom(aT)->ac[i] != aTEx) {
        list.push_back(getAtom(aT)->ac[i]);
      }
    if (list.size() == 1) return test;                      //exit in AT non-connected atom
    k=0;
    do {                                 //iterational algorithm to define all}
      for (i=0; i<getAtom(list[k])->nb; i++) {
        test1=false;
        l=getAtom(list[k])->ac[i];
        if (l != aTEx) {
          for (j=0; j<list.size(); j++) if (list[j] == l) test1=true;
        } else test=true;
        if ((! test1) && (l != aTEx) && (l >= 0) && (l < nAtoms())) {
          list.push_back(l);
        }
      }
      k=k+1;                             //atoms which are connected with AT}
    } while (k<list.size());
    return test;
  }

  void TSimpleMolecule::readConnectionMatrix(const std::vector<int>iA1, const std::vector<int>iA2, int nAtoms, int nBonds) {
    TSingleAtom * sa;
    TSingleBond * sb;
    int i;

    clear();
    srand(30000);
    for (i=1; i<=nAtoms; i++) {
      sa=new TSingleAtom();
      sa->na=6;
      sa->nv=hVal[sa->na];
      sa->rx=(double)rand()/1000.0;
      sa->ry=(double)rand()/1000.0;
      fAtom.push_back(sa);
    };

    for (i=0; i<nBonds; i++) {
      sb=new TSingleBond();
      sb->at[0]=iA1[i];
      sb->at[1]=iA2[i];
      sb->tb=1;
      fBond.push_back(sb);
    };
    defineAtomConn();
    allAboutCycles();
  };

  void TSimpleMolecule::readConnectionMatrix(const std::vector<int>iA1, const std::vector<int>iA2, const std::vector<double>rx, const std::vector<double>ry, int nAtoms, int nBonds) {
    readConnectionMatrix(iA1,iA2,nAtoms,nBonds);
    for (int i=0; i<nAtoms; i++) {
      getAtom(i)->rx=rx[i];
      getAtom(i)->ry=ry[i];
    };
  };


  void TSimpleMolecule::normalizeCoordinates(double aveBL) {
    int i;
    double d,xMin,yMin;

    if (nAtoms() == 0) return;

    d=averageBondLength();
    if ((d > 0) && (aveBL>0)) for (i=0; i<nAtoms(); i++) {
        getAtom(i)->rx=getAtom(i)->rx*aveBL/d;
        getAtom(i)->ry=getAtom(i)->ry*aveBL/d;
      };
    //Normalizing X and Y coordinates
    xMin=getAtom(0)->rx;
    yMin=getAtom(0)->ry;
    for (i=0; i<nAtoms(); i++) {
      if (getAtom(i)->rx < xMin) xMin=getAtom(i)->rx;
      if (getAtom(i)->ry < yMin) yMin=getAtom(i)->ry;
    };
    for (i=0; i< nAtoms(); i++) {
      getAtom(i)->rx=getAtom(i)->rx-xMin+aveBL;
      getAtom(i)->ry=getAtom(i)->ry-yMin+aveBL;
    };
  };

  void TSimpleMolecule::readOBMol(OBMol * pmol) {
    TSingleAtom * sa;
    TSingleBond * sb;
    OBAtom * atom;
    OBBond * bond;
    int na,nb,i;

    // Stereo perception should not be triggered if this function is called
    // from MDLFormat::ReadMolecule->Alias::Expand->Alias::FromNameLookup->(MCDL)groupRedraw
    // as this triggers a failure in the test suite for InChI conversion
    // (specifically the ferrocene).
    bool perceive_stereo = true;
    if (pmol->GetMod() == 1)
      perceive_stereo = false;
    OBStereoFacade facade(pmol);

    // When laying out, we may need to iterate over the most central bonds
    // first - that's why we remember the GTD: the GTD is the distance from
    // atom i to every other atom j. Atoms on the "inside" of the molecule
    // will have a lower GTD value than atoms on the "outside".
    vector<int> vGTD;
    pmol->GetGTDVector(vGTD);

    clear();

    na=pmol->NumAtoms();
    nb=pmol->NumBonds();

    for (i=1; i<=na; i++) {
      atom=pmol->GetAtom(i);
      sa=new TSingleAtom();
      sa->na=atom->GetAtomicNum();
      sa->nc=atom->GetFormalCharge();
      sa->rl=atom->GetSpinMultiplicity();
      sa->rx=atom->GetX();
      sa->ry=atom->GetY();
      sa->gtd = vGTD.at(i-1);
      fAtom.push_back(sa);
    };
    for (i=0; i<nb; i++) {
      bond=pmol->GetBond(i);
      sb=new TSingleBond();
      sb->at[0]=bond->GetBeginAtomIdx()-1;
      sb->at[1]=bond->GetEndAtomIdx()-1;
      sb->tb=bond->GetBondOrder();
      //	if (bond->IsUp()) sb->tb=9;
      //	if (bond->IsDown()) sb->tb=10;
      if (bond->IsWedge()) sb->tb=9;
      if (bond->IsHash()) sb->tb=10;
      if (perceive_stereo && facade.HasCisTransStereo(bond->GetId())) {
        OBCisTransStereo::Config config = facade.GetCisTransStereo(bond->GetId())->GetConfig(OBStereo::ShapeU);
        if (config.specified)
          sb->bstereo_refs = config.refs;
      }
      fBond.push_back(sb);
    };


    defineAtomConn();
    allAboutCycles();
  };


  int TSimpleMolecule::nAtoms() {
    return fAtom.size();
  };

  int TSimpleMolecule::nBonds() {
    return fBond.size();
  };


  TSingleAtom * TSimpleMolecule::getAtom(int index) {
    return (TSingleAtom *)fAtom.at(index);
  };

  TSingleBond * TSimpleMolecule::getBond(int index) {
    return (TSingleBond *)fBond.at(index);
  };

  void TSimpleMolecule::defineAtomConn() {
    //for each atom returns list of adjusted atoms in atomConnection
    int i,n1, n2;
    TSingleAtom * sa;

    for (i=0; i<nAtoms(); i++) {
      getAtom(i)->nb=0;
      getAtom(i)->currvalence=0;
      for (int j=0; j<CONNMAX; j++) {
        getAtom(i)->ac[j]=0;
      }
    };
    for (i=0; i<nBonds(); i++) {
      n1=getBond(i)->at[0]; n2=getBond(i)->at[1];
      sa=getAtom(n1);
      if (sa->nb < CONNMAX) {
        sa->ac[sa->nb]=n2;
        sa->nb++;
      }
      sa->currvalence=sa->currvalence+getBond(i)->getValence();
      sa=getAtom(n2);
      if (sa->nb < CONNMAX) {
        sa->ac[sa->nb]=n1;
        sa->nb++;
      }
      sa->currvalence=sa->currvalence+getBond(i)->getValence();
    };
  };

  void TSimpleMolecule::defineBondConn(neighbourlist *bondConnection) {
    //for each atom returns list of adjusted bonds in bondConnection
    int i,n1, n2;

    for (i=0; i<nAtoms(); i++) bondConnection[i].nb=0;
    for (i=0; i<nBonds(); i++) {
      n1=getBond(i)->at[0]; n2=getBond(i)->at[1];
      if (bondConnection[n1].nb < CONNMAX) {
        bondConnection[n1].adjusted[bondConnection[n1].nb]=i;
        bondConnection[n1].nb++;
      }
      if (bondConnection[n2].nb < CONNMAX) {
        bondConnection[n2].adjusted[bondConnection[n2].nb]=i;
        bondConnection[n2].nb++;
      }
    };
  };

  void TSimpleMolecule::newB(neighbourlist * bk, int bnum, int anum, int & total, int * e, int * e1) {
    /*for atom's number ANUM calculates the bond's list, which are connected
      with the ANUM, excluding bond BNUM. The bond's list is inserted into array
      L, TOTAL-number of components in the array. Array L1 contains atom's number
      which is connected with atom ANUM through corresponding bond in the array L.*/
    int n,i;

    total=0;
    for (i=0; i<bk[anum].nb; i++) if (bk[anum].adjusted[i] != bnum) {
        n=bk[anum].adjusted[i];  //bond number zero-based
        e[total]=n;
        if (getBond(n)->at[0] == anum) e1[total]=getBond(n)->at[1]; else e1[total]=getBond(n)->at[0];
        total++;
      };
  };

  void TSimpleMolecule::singleVawe(neighbourlist * bk, std::vector<int> & alreadyDefined,
                                   std::vector<int> & prevBond, std::vector<int> & prevAtom,
                                   int & nPrev, std::vector<int> & curBond, std::vector<int> & curAtom) {
    /*
      a vawe algorithm is used to calculate the neighbour sphere. PREVBOND and
      PREVATOM contain on input the bond's and atom's list correspondingly, the
      atom has been took into consideration at previous step. NPREV-number of
      components in PREVBOND and PREVATOM on input.  ALREADYDEFINED is the global
      array for procedure, which calls the SINGLEVAWE. It contains for each bond's
      number either zero, if the bond has not been took into consideration yet or
      bond's number from previous neighbour sphere. The subroutine makes next:
      1) calculates the new neighbour sphere for each bond from PREVBOND.
      2) if some bonds were not defined, they are labelled in ALREADYDEFINED,
      they numbers being stored into PREVBOND and PREVATOM. So, on output
      the arrays contain information for new neighbour sphere.
      3) On output NPrev is changed so new number of component in PREVBOND
      is lighted}
    */
    int e[CONNMAX];
    int e1[CONNMAX];
    int i,j,ncur;
    int n;

    ncur=0;
    n=0;
    for (i=0; i<nPrev; i++) {
      newB(bk,prevBond[i],prevAtom[i],n,e,e1);
      if (n != 0) for (j=0; j<n; j++) if (alreadyDefined[e[j]]<0) {
            curBond[ncur]=e[j];
            curAtom[ncur]=e1[j];
            ncur++;
            alreadyDefined[e[j]]=prevBond[i];
          };
    };
    nPrev=ncur;
    for (i=0; i<ncur; i++) prevBond[i]=curBond[i];
    for (i=0; i<ncur; i++) prevAtom[i]=curAtom[i];
  };

  void TSimpleMolecule::vaweBond(int bondN, neighbourlist *bk,
                                 int & ringSize, std::vector<int> & bondList) {
    /*The procedure for bond's number BONDN determines, whether or not the bond
      belongs to ring (RINGSIZE=0 if not ring bond and RINGSIZE=number of atoms
      in the smallest ring, to which the bond is assigned). If the bond belongs
      to ring, array BONDLIST contains on output the bond's numbers, which are
      also assigned to the same ring */

    int i,j,k,aA,i1,i2;
    std::vector<int>pA(nBonds());
    std::vector<int>pB(nBonds());
    std::vector<int>oD(nBonds());
    std::vector<int>curBond(nBonds());
    std::vector<int>curAtom(nBonds());
    bool test;
    int nP;


    for (j=0; j<nBonds(); j++) oD[j]=-1;
    oD[bondN]=65500;
    ringSize=1;
    nP=1;  //OK for zer-based in C
    pB[0]=bondN; //pB.setValue(1,bondN);
    pA[0]=getBond(bondN)->at[0];//pA.setValue(1,fBond.getAT(bondN,1));
    aA=getBond(bondN)->at[1];//fBond.getAT(bondN,2);

    k=0;
    test=false;
    while (! ((nP==0) || test)) {                        //recursion
      ringSize++;
      singleVawe(bk,oD,pB,pA,nP,curBond,curAtom);      //new neighbour sphere generation}
      test=false;
      if (nP>0) for (j=0; j<nP; j++) if (pA[j] == aA) {
            test=true;
            k=pB[j];
          };
    }; //recursion finishing
    if (test) {                    //bond belongs to ring
      bondList.resize(ringSize);
      bondList[ringSize-1]=bondN;         //bond BONDN must be last in the list
      for (j=1; j<ringSize; j++) {        //BONDLIST formation
        bondList[j-1]=k;
        k=oD[k];
      };
      //Sorting remaining bonds in ascending order - need for cycle comparison
      k=2;                   //all bonds are sorted
      //remains last bond in cycle description=bondN (input parameter)
      for (i=0; i<(ringSize-k); i++) for (j=i+1; j<=(ringSize-k); j++) {
          i1=bondList[i];
          i2=bondList[j];
          if (i1 > i2) {
            bondList[i]=i2;
            bondList[j]=i1;
          };
        };
    } else ringSize=0;
  };


  //This method must be called ONLY from AllAboutCycles
  bool TSimpleMolecule::aromatic(int cycleSize, const std::vector<int> bondList,
                                 std::vector<int>& arom) {

    /*for a cycle with the dimension of CYCLESIZE determines, whether or not the
      cycle is aromatic. BONDLIST contains the bond's numbers, which are belongs
      to the cycle. AROM-global array for the structure under study, for each bond
      in the structure contains label, whether the bond is aromatic or not. On out-
      put function AROMATIC contains TRUE if the ring is aromatic, FALSE otherwise
    */
    bool test;
    int i,j,k,n,n1,m;
    int doubleDetected[11];
    int atomDetected[11];
    bool result=false;

    if ((cycleSize<5) || (cycleSize>6)) return result;
    //procedure define aromatic only for 5 or 6 membered cycles}
    //Simple Test}
    n=0;
    for (i=0; i<cycleSize; i++) {
      k=bondList[i];

      if ((getBond(k)->tb == 1) && (arom[k]==0)) doubleDetected[i]=0; else
        if ((getBond(k)->tb == 2) || (getBond(k)->tb == 4) || (arom[k]>0)) {
          n=n+1;                 //number of double or aromatic bonds calculation}
          doubleDetected[i]=1;
        } else return result;
    };
    if (cycleSize==6) {     //6-membered ring}
      if (n>=3) {
        result=true;
        if (n<=4) for (i=0; i<cycleSize; i++) if (doubleDetected[i]==0) {
              //Checking if not connected
              for (j=0; j<cycleSize; j++) if ((j != i) && (doubleDetected[j]==0)) {
                  test=(getBond(bondList[i])->at[0] == getBond(bondList[j])->at[0]) || (getBond(bondList[i])->at[0] == getBond(bondList[j])->at[1])
                    || (getBond(bondList[i])->at[1] == getBond(bondList[j])->at[0]) || (getBond(bondList[i])->at[1] == getBond(bondList[j])->at[1]);
                  if (test) result=false;
                  if (! result) break;
                };
              if (! result) break;
            };
      };
      return result;
    };

    if (n<2) return result;        //5-membered ring
    m=0;
    for (i=0; i<cycleSize; i++) if (doubleDetected[i]==0) {
        atomDetected[m]=getBond(bondList[i])->at[0];
        m++;
        atomDetected[m]=getBond(bondList[i])->at[1];
        m++;
      };
    n=-1;
    if (m>0) for (i=0; i<(m-1); i++) for (j=i+1; j<m; j++) if (atomDetected[i]==atomDetected[j]) n=i;
    //Addition from January 2001
    if (n>=0) {
      n1=-1;
      for (i=0; i<(m-1); i++) if (i != n) for (j=i+1; j<m; j++) if (atomDetected[i]==atomDetected[j]) n1=i;
      if (n1>=0) return result;
    };
    if (n < 0) {   //No common atoms...
      result=m==4;
      return result;
    };
    test=false;
    i=0;
    j=getAtom(atomDetected[n])->na;
    for (i=0; i<NAROMMAX; i++) if (j == possibleAromatic[i]) {
        test=true;
        break;
      };
    if (! test) test=(j==6) && (getAtom(atomDetected[n])->nc < 0);
    //cyclopentadienyl checking}
    result=test;
    return result;
  };

  void TSimpleMolecule::allAboutCycles() {
    /*
      for each bond in the structure cyclic conditions are calculated and stored
      into the BOND[I].DB variables. Possible values:
      0 - chain;
      1 - chain, appended to cycle;
      2 - aromatic, 5-membered ring;
      3 - aromatic, 6-membered ring;
      4...more = non-aromatic ring size+1}
    */
    std::vector<int>bondTested(nBonds(), 0);
    std::vector<int>bondList;
    std::vector<int>ar(nBonds(), 0);
    std::vector<int>ar1(nBonds());
    std::vector<std::vector<int> > cycleDescription;

    int i,n,j,k;
    int cycleSize;
    neighbourlist *bk;

    if (nBonds() == 0) return;
    bk=(neighbourlist *)calloc(nAtoms(), sizeof(adjustedlist));
    defineBondConn(bk);
    //initial values for MainList-number of bonds, connected to each atom and their numbers in array BOND
    for (i=0; i<nBonds(); i++) {
      getBond(i)->db=0;
    }
    n=0;
    for (i=0; i<nBonds(); i++) if (bondTested[i] == 0) {
        vaweBond(i,bk,cycleSize,bondList); //Is I-th bond cyclic?
        if (cycleSize>0) {       //Yes, cyclic
          canonizeCycle(cycleSize,bondList);
          cycleDescription.push_back(bondList);
          n++;
          ar1[n-1]=0;
          if (aromatic(cycleSize,bondList,ar)) {       //store, if aromatic cycle}
            ar1[n-1]=1;
            for (j=0; j<cycleSize; j++) ar[bondList[j]]=1;
          };
          for (j=0; j<cycleSize; j++) bondTested[bondList[j]]=1;
          //marking all bonds in the cycle}
        };
        bondTested[i]=1;                                //marking I-th bond
      };
    if (n>0) {
      j=1;
      while (j != 0) {
        j=0;
        for (i=0; i<n; i++) if (ar1[i]==0) {   //search for condenced aromatics
            bondList=cycleDescription[i];
            cycleSize=bondList.size();
            if (aromatic(cycleSize,bondList,ar)) {
              j++;
              ar1[i]=1;
              for (k=0; k<cycleSize; k++) ar[bondList[k]]=1;
            };
          };
      }; //until J=0;          {until new aromatics are not detected under iteration}
      for (i=0; i<n; i++) if (ar1[i]==0) {       //Label of non-aromatic cycles in BOND
          bondList=cycleDescription[i];
          cycleSize=bondList.size();
          for (j=0; j<cycleSize; j++) {
            k=cycleSize+1;
            if ((getBond(bondList[j])->db==0) || (k<getBond(bondList[j])->db)) getBond(bondList[j])->db=k;
          };
        };
      for (i=0; i<n; i++) if (ar1[i]==1)  {     //Label of aromatic cycle in BOND
          bondList=cycleDescription[i];
          cycleSize=bondList.size();
          for (j=0; j<cycleSize; j++) {
            if (cycleSize==5) getBond(bondList[j])->db=2;
            if ((cycleSize==6) && (getBond(bondList[j])->db != 2)) getBond(bondList[j])->db=3;
          };
        };
    };
    free(bk);
  };


  void TSimpleMolecule::redrawMolecule() {
    int i;
    int atomClean;
    int bondClean;
    std::vector<int>listAtomClean(nAtoms());
    std::vector<int>listBondClean(nBonds());

    if (nAtoms()==0) return;
    for (i=0; i<nAtoms(); i++) listAtomClean[i]=i;
    for (i=0; i<nBonds(); i++) listBondClean[i]=i;
    atomClean=nAtoms();
    bondClean=nBonds();
    redraw(listAtomClean,listBondClean,atomClean,bondClean,1,1,0,false);
  };


  void TSimpleMolecule::twoAtomUnitVector(int na1, int na2, double & xv, double & yv, const std::vector<int>atomDefine) {
    /*Using atom's numbers NA1 and NA2 in the array ATOMS calculates the direction
      for bond between NA1 and NA2 (XV,YV on output). At this direction new
      substitutor may be added with optimal place.*/
    double si,r1,r2,r3,s1,s2,s3,s4,x1,y1,y2;
    int i,k;

    if ((getAtom(na1)->rx==getAtom(na2)->rx) && (getAtom(na1)->ry==getAtom(na2)->ry)) {
      xv=1;
      yv=1;
      return;
    };
    s1=getAtom(na1)->rx;
    s2=getAtom(na1)->ry;
    s3=getAtom(na2)->rx;
    s4=getAtom(na2)->ry;
    r1=s1-s3;
    r2=s2-s4;
    r3=sqrt(r1*r1+r2*r2);
    r1=r1/r3;  r2=r2/r3;
    si=0;
    for (i=0; i<getAtom(na1)->nb; i++) {
      k=getAtom(na1)->ac[i];
      if (k != na2) if (atomDefine[k] > 0) {
          x1=getAtom(k)->rx-s1;
          y1=getAtom(k)->ry-s2;
          y2=x1*r2-y1*r1;
          if (y2 != 0) si=si+y2/abs(y2);
        };
    };
    for (i=0; i<getAtom(na2)->nb; i++) {
      k=getAtom(na2)->ac[i];
      if (k != na1) if (atomDefine[k] > 0) {
          x1=getAtom(k)->rx-s3;
          y1=getAtom(k)->ry-s4;
          y2=x1*r2-y1*r1;
          if (y2 != 0) si=si+y2/abs(y2);
        };
    };
    if (si != 0) si=si/abs(si); else si=1;
    xv=-r2*si; yv=r1*si;
  };

  void TSimpleMolecule::defC(int& currNumDef, int baseCycle, int atomClean, std::vector<int>& cycleDefine,
    std::vector<int>& atomDefine, std::vector<std::vector<int> >& atomCycle, std::vector<int>& dsATN,
                             std::vector<int>& dsTP,
                             std::vector<int>& dsSC, std::vector<int>& dsNA1, std::vector<int>& dsNA2) {
    //The procedure create priority list formation for cleaning of molecule. Recur-
    // sive calls to the procedure are required together with DefA. After recursion
    // have been finished, the DEFINESEQUENCE array will be created. The procedure
    // analyze cyclic fragments
    int aA,cN,maxAtDef,i,j,atDef;
    bool test;

    test=true;
    while (test) {
      cN=-1;
      if ((baseCycle==0) || (currNumDef==atomClean)) return;
      maxAtDef=0;
      for (i=0; i<baseCycle; i++) if (cycleDefine[i]==0) {
          //        {for all cycles, which were not included into priority list}
          atDef=0;
          //        {search for maximal priority level}
          for (j=0; j<atomCycle[i].size(); j++) if (atomDefine[atomCycle[i][j]]>0) atDef=atDef+1;
          if (atDef > maxAtDef) {
            //          {  search for cycles, for which maximal number of atoms were inserted in the priority list}
            maxAtDef=atDef;
            cN=i;
          } else if ((maxAtDef > 0) && (atDef==maxAtDef)) {
            //         {search for minimal cycle size}
            if (atomCycle[i].size()<atomCycle[cN].size()) cN=i;
          };
        };
      if (cN>=0) if (maxAtDef==atomCycle[cN].size()) {
          cycleDefine[cN]=1;
          cN=-1;
        };

      //          {CN-number of selected cycle with max.number of atoms, already defined, or with minimal size}
      if (cN>=0) {
        cycleDefine[cN]=1;  //{Label, that CN-th cycle is inserted into priority list}

        test=(atomDefine[atomCycle[cN][0]]>0) &&
          (atomDefine[atomCycle[cN][atomCycle[cN].size() - 1]]==0);
        //        {if first atom from cyclic fragment was inserted into list previously and last-no}
        while (! test) {
          //          {enumeration of atom's sequence in cyclic fragment}
          aA=atomCycle[cN][0];
          for (j=1; j<atomCycle[cN].size(); j++) atomCycle[cN][j-1]=atomCycle[cN][j];
          atomCycle[cN][atomCycle[cN].size() - 1]=aA;
          test=(atomDefine[atomCycle[cN][0]]>0) &&
            (atomDefine[atomCycle[cN][atomCycle[cN].size() - 1]]==0);
        };
        //        {now first atom in the cycle definition list must be inserted into the priority list early, and the last atom-no}
        for (j=0;currNumDef < atomClean && j<atomCycle[cN].size()-maxAtDef; j++) {
          //          for each undefined atom from selected cycle}
          //atom is added to priority list}
          dsATN[currNumDef]=atomCycle[cN][maxAtDef+j];

          atomDefine[dsATN[currNumDef]]=1;
          if (maxAtDef<3) dsTP[currNumDef]=maxAtDef+1; else dsTP[currNumDef]=4;
          //type of clean procedure definition}
          dsNA1[currNumDef]=atomCycle[cN][maxAtDef-1];
          dsNA2[currNumDef]=atomCycle[cN][0];
          dsSC[currNumDef]=atomCycle[cN].size()-maxAtDef;
          currNumDef++;

          /*       Initial Java codes
          //atom is added to priority list}
          dsATN.setValue(currNumDef.value,atomCycle.getValue(cycleAddress.getValue(cN)+maxAtDef+j));
          atomDefine.setValue(dsATN.getValue(currNumDef.value),1);
          if (maxAtDef<3) dsTP.setValue(currNumDef.value,maxAtDef+1); else dsTP.setValue(currNumDef.value,4);
          //type of clean procedure definition}
          dsNA1.setValue(currNumDef.value,atomCycle.getValue(cycleAddress.getValue(cN)+maxAtDef));
          dsNA2.setValue(currNumDef.value,atomCycle.getValue(cycleAddress.getValue(cN)+1));
          dsSC.setValue(currNumDef.value,cycleSize.getValue(cN)-maxAtDef);
          currNumDef.value=currNumDef.value+1;
          */
        };
      };
      test=(cN<0) || (currNumDef==atomClean);
      test=! test;
    };
  };

  void TSimpleMolecule::defA(int& currNumDef, int atomClean, int sPN, int baseCycle, std::vector<int>& atomDefine, const std::vector<int> listAtomClean,
                             std::vector<int>& cycleDefine, std::vector<std::vector<int> >& atomCycle,
                             std::vector<int>& dsATN, std::vector<int>& dsTP, std::vector<int>& dsNA1, std::vector<int>& dsNA2) {

    //The procedure create priority list formation for cleaning of molecule. Recur-
    // sive calls to the procedure are required together with DefC. After recursion
    //have been finished, the DEFINESEQUENCE array will be created. The procedure
    //analyze chain fragments
    int i,j,k,rC;



    if (currNumDef==atomClean) return;

    for (i=0; i<atomClean; i++) if (atomDefine[listAtomClean[i]]==0)
                                  if (getAtom(listAtomClean[i])->nb > 0) for (j=0; j<getAtom(listAtomClean[i])->nb; j++) {
                                      k=getAtom(listAtomClean[i])->ac[j];
                                      if (atomDefine[k]>0) {
                                        //if atom has a neighbour, which has already been inserted into priority
                                        // list, then it is inserted into the priority list}
                                        dsATN[currNumDef]=listAtomClean[i];
                                        atomDefine[dsATN[currNumDef]]=1;
                                        dsTP[currNumDef]=1;                  //type of clean}
                                        dsNA1[currNumDef]=k;
                                        dsNA2[currNumDef]=-1;
                                        currNumDef++;
                                        //only one atom is added into priority list, then it is necessary to
                                        // analyze cycles by DEFC procedure!}
                                        return;
                                      };
                                    };
    if ((sPN<3) || (sPN==4)) {   //{next may not be implemented to CleanGroup command}
      //{initializing priority list for clean of a new fragment}
      rC=0;
      j=100000;
      //minimal cycle size searching}
      if (baseCycle>0) for (i=0; i<baseCycle; i++) if (cycleDefine[i]==0) if (atomCycle[i].size()<j) {
              rC=i;
              j=atomCycle[i].size();
            };
      if (rC>0) i=atomCycle[rC][0]; else {
        //        {not found-first undefined atom is selected}
        i=0;
        while (atomDefine[listAtomClean[i]] != 0) i++;
        i=listAtomClean[i];
      };
    } else i=listAtomClean[atomClean-1];
    //for group-first atom, from which group started, is selected}
    dsATN[currNumDef]=i;
    atomDefine[dsATN[currNumDef]]=1;
    dsTP[currNumDef]=0;                  //type of clean}
    dsNA1[currNumDef]=-1;
    dsNA2[currNumDef]=-1;
    currNumDef++; //Addition the atom selected to the list}
  };

  void TSimpleMolecule::canonizeCycle(int ringSize, std::vector<int> & bondList) {
    //Order of nonds in cycle description in so way, that bond with minimal number
    //is the first in this description. Then is coming bond, which is appended to
    //atom with maximal number, then next and so on
    std::vector<int> bondUsed(ringSize);
    std::vector<int> newBondList(ringSize);
    int i,j,n,m,currentAtom;

    n=bondList[0];
    m=0;
    for (i=0; i<ringSize; i++) {
      bondUsed[i]=0;
      if (bondList[i]<n) {  //minimal bond number
        n=bondList[i];
        m=i;
      };
    };
    currentAtom=getBond(n)->at[0];
    if (getBond(n)->at[1] > currentAtom) currentAtom=getBond(n)->at[1];
    newBondList[0]=n;
    bondUsed[m]=1;
    n=1;
    for (i=1; i<ringSize; i++) {  //cycle size-1 because of 1-st bond already selected
      for (j=0; j<ringSize; j++) if (bondUsed[j] == 0) {
          m=bondList[j];
          if ((getBond(m)->at[0] == currentAtom) || (getBond(m)->at[1] == currentAtom)) {
            bondUsed[j]=1;
            newBondList[n]=m;
            n++;
            if (getBond(m)->at[0] == currentAtom) currentAtom=getBond(m)->at[1]; else currentAtom=getBond(m)->at[0];
            break;
          };
        };
    };
    //copy new set
    for (i=0; i<ringSize; i++)bondList[i]=newBondList[i];
  };

  void TSimpleMolecule::redraw(const std::vector<int>listAtomClean, const std::vector<int>listBondClean,
                               int atomClean, int & bondClean, int spn, int sCHA1, int sCHB1, bool /*iOPT7*/) {
    /*
      the arrays are the priority list for clean. Minimal element of record has
      the maximal priority. Each element of record contains:
      ATN-atom's number in the ATOM array, coordinate of which must be calculated
      at current step.
      TP -type of calculation of coordinates for the atom ATN:
      =0 - simple put at any position
      =1 - calculation from coordinates of previously defined atom NA1. NA2
      value hasn't effect in the case.
      =2 - for cyclic fragment, coordinates of all cyclic atoms must be cal-
      culated from the ones for atom NA1-base atom in cycle. This type
      means fragment: chain bond, attached to the cycle. NA2 value hasn't
      effect in the case.
      =3 - for cyclic fragment, coordinates of all cyclic atoms must be cal-
      culated from the ones for pair of atoms NA1 and NA2. The pair is
      connected with bond. This type means fragment in condenced-cyclic
      systems.
      =4 - for cyclic fragment, coordinates of all cyclic atoms must be cal-
      culated from the ones for pair of atoms NA1 and NA2. The pair is
      connected through more, then one bond. This type means fragment
      in polycyclic systems.
      AN1,AN2-auxiliary atom's numbers (see TP description).
      SC-cycle size minus number of already defined atoms. The variable is taken
      into consideration for TP=2-4.
    */
    bool test;
    int cs;
    int add,nb,k,k1,k2,l,i,j,baseCycle,lx,ly;
    int currNumDef;
    int atomSecond;

    double r,cf,fi,ux,uy,ux1,uy1,ux2,uy2,uvX,uvY,c,s;
    double xCenterOld,yCenterOld,xCenterNew,yCenterNew,bondLengthOld,bondLengthNew;
    neighbourlist *bk;
    int n,n1,n2;
    double r1;
    bool isCycle,isChainFour;
    int mm1,mm2,mAny,bnEx;

    //Lx,Ly,Button:integer;

    if ((atomClean<1) || (bondClean==0)) return;

    std::vector<int> dsATN(atomClean);
    std::vector<int> dsTP(atomClean);
    std::vector<int> dsSC(atomClean);
    std::vector<int> dsNA1(atomClean);
    std::vector<int> dsNA2(atomClean);

    defineAtomConn();
    allAboutCycles();

    test=true;
    bk = (neighbourlist *)calloc(nAtoms(), sizeof(adjustedlist));
    defineBondConn(bk);
    //{Start clean for LISTATOMCLEAN and LISTBONDCLEAN atoms and bonds}
    baseCycle=0;
    cs=0;
    ux=0;
    uy=0;
    uvX=0;
    uvY=0;
    atomSecond=0;

    std::vector<int>bondList;
    std::vector<vector<int> > cycleDescription;
    for (i=0; i<bondClean; i++) {
      vaweBond(listBondClean[i],bk,cs,bondList); //If I-th bond belongs to cycle}
      if (cs>0) {
        canonizeCycle(cs,bondList);
        test=false;
        for (j=0; j<baseCycle; j++) if(cycleDescription[j].size() == cs) {
            test=true;
            for (k=0; k<cycleDescription[j].size(); k++) if (bondList[k] != cycleDescription[j][k]) {
                test=false;
                break;
              };
            if (test) break;
          };
        if (! test) {     //{not found-the cycle is added to cycle's list}
          baseCycle++;
          cycleDescription.push_back(bondList);
        };
      };
    };

    std::vector<std::vector<int> > atomCycle(cycleDescription.size());
    std::vector<int> cycleDefine(cycleDescription.size());

    for (i=0; i<baseCycle; i++) { //making atom list in those order, as they will be defined at cycles}
      cycleDefine[i]=0;
      k=cycleDescription[i][0];
      j=cycleDescription[i][1];

      if ((getBond(k)->at[0]==getBond(j)->at[0]) || (getBond(k)->at[0]==getBond(j)->at[1])) atomCycle[i].push_back(getBond(k)->at[0]);
      else atomCycle[i].push_back(getBond(k)->at[1]);
      n=atomCycle[i][0]; //previoulsly putted atom
      for (j=1; j<cycleDescription[i].size(); j++) {
        k=cycleDescription[i][j];
        if (getBond(k)->at[0]==n) atomCycle[i].push_back(getBond(k)->at[1]); else atomCycle[i].push_back(getBond(k)->at[0]);
        n=atomCycle[i][j];
      };
    };

    //calculation of the coordinates of fragment's center and scaling factor}

    if ((spn<3) || (spn==4)) {
      xCenterOld=0;
      yCenterOld=0;
      bondLengthOld=0;
      if (spn == 4) {
        vector<int> tempAtomArray(nAtoms(), 0);
        for (i=0; i<atomClean; i++) {
          k=listAtomClean[i];
          tempAtomArray[k]=1;
        };
        n=0;
        for (i=0; i<nAtoms(); i++) if (tempAtomArray[i]==0) {
            xCenterOld=xCenterOld+getAtom(i)->rx;
            yCenterOld=yCenterOld+getAtom(i)->ry;
            n++;
          };
        xCenterOld=xCenterOld/(double)n; yCenterOld=yCenterOld/(double)n;
        vector<int> tempBondArray(nBonds(), 0);
        for (i=0; i<bondClean; i++) {
          k=listBondClean[i];
          tempBondArray[k]=1;
        };
        n=0;
        bondLengthOld=1E10;
        r1=0;
        for (i=0; i<nBonds(); i++) if (tempBondArray[i] == 0) {
            r=this->bondLength(i);
            if (r < bondLengthOld) bondLengthOld=r;
            r1=r1+r;
            n++;
          };
        r1=r1/n;
        if (5*bondLengthOld < r1) bondLengthOld=r1;
      } else {
        for (i=0; i<atomClean; i++) {
          k=listAtomClean[i];
          xCenterOld=xCenterOld+getAtom(k)->rx;
          yCenterOld=yCenterOld+getAtom(k)->ry;
        };
        xCenterOld=xCenterOld/(double)atomClean; yCenterOld=yCenterOld/(double)atomClean;
        for (i=0; i<bondClean; i++) {
          k=listBondClean[i];
          bondLengthOld=bondLengthOld+this->bondLength(k);
        };
        bondLengthOld=bondLengthOld/(double)bondClean;
      };
      if (bondLengthOld<0.01) bondLengthOld=1;
    } else {

      xCenterOld=getAtom(sCHA1)->rx; //{CHA1 - To atom connected, CHB1-splitting bond}
      yCenterOld=getAtom(sCHA1)->ry;
      lx=getBond(sCHB1)->at[0];
      ly=getBond(sCHB1)->at[1];
      if (ly == sCHA1) {
        lx=getBond(sCHB1)->at[1];
        ly=getBond(sCHB1)->at[0];
      };
      atomSecond=ly;
      //for group it is necessary to calculate unit vector direction
      uvX=getAtom(ly)->rx-getAtom(lx)->rx;
      uvY=getAtom(ly)->ry-getAtom(lx)->ry;
      bondLengthOld=sqrt(uvX*uvX+uvY*uvY);
      if (bondLengthOld<0.01) bondLengthOld=1;
      uvX=uvX/bondLengthOld;
      uvY=uvY/bondLengthOld;

    };

    std::vector<int> atomDefine(nAtoms(), 0); //flags-zero value OK
    if ((spn<3) || (spn==4)) {     //checking already cleaned atoms...
      for (i=0; i<nAtoms(); i++) atomDefine[i]=1;
      for (i=0; i<atomClean; i++) {
        k=listAtomClean[i];
        atomDefine[k]=0;
      };
    };
    currNumDef=0;
    while (currNumDef<atomClean) {
      //start recursion-priority list formation}
      defC(currNumDef,baseCycle,atomClean,cycleDefine,atomDefine,atomCycle,dsATN,dsTP,dsSC,dsNA1,dsNA2);
      defA(currNumDef,atomClean,spn,baseCycle,atomDefine,listAtomClean,cycleDefine,atomCycle,dsATN,dsTP,dsNA1,dsNA2);
    }; //end recursion}

    for (i=0; i<nAtoms(); i++) atomDefine[i]=0;

    if ((spn<3) || (spn==4)) {     //checking already cleaned atoms...
      for (i=0; i<nAtoms(); i++) atomDefine[i]=1;
      for (i=0; i<atomClean; i++) {
        k=listAtomClean[i];
        atomDefine[k]=0;
      };
      for (i=0; i<nAtoms(); i++) if (atomDefine[i]==1) {
          getAtom(i)->rx=(xCenterOld+(getAtom(i)->rx-xCenterOld)/bondLengthOld);
          getAtom(i)->ry=(yCenterOld+(getAtom(i)->ry-yCenterOld)/bondLengthOld);
        };
    };

    i=0;

    if (atomClean>=1) while (i<atomClean) {

        switch (dsTP[i]) {
        case 0:{
          atomDefine[dsATN[i]]=1; //old coordinates of the atom are used}
          getAtom(dsATN[i])->rx=xCenterOld+(getAtom(dsATN[i])->rx-xCenterOld)/bondLengthOld;
          getAtom(dsATN[i])->ry=yCenterOld+(getAtom(dsATN[i])->ry-yCenterOld)/bondLengthOld;
          break;
        }
        case 1:
        case 2: if (atomDefine[dsATN[i]] == 0) {
            k1=dsNA1[i];
            k=getAtom(k1)->nb;
            nb=0;
            ux=0;
            uy=0;
            ux1=0;
            uy1=0;
            //bond direction calculation}
            for (j=0; j<k; j++) if (atomDefine[getAtom(k1)->ac[j]]>0) {
                k2=getAtom(k1)->ac[j];
                nb=nb+1;           //number of already cleaned atoms}
                ux=ux+(getAtom(k1)->rx-getAtom(k2)->rx);
                uy=uy+(getAtom(k1)->ry-getAtom(k2)->ry);
                if (dsTP[i]==1) for (l=0; l<getAtom(k2)->nb; l++) if (atomDefine[getAtom(k2)->ac[l]]>0) {
                      ux1=ux1+(getAtom(k2)->rx-getAtom(getAtom(k2)->ac[l])->rx);
                      uy1=uy1+(getAtom(k2)->ry-getAtom(getAtom(k2)->ac[l])->rx);
                    };
              };
            if (dsTP[i]==1) {     //chain fragment
              if ((abs(ux) <= 0.00001) && (abs(uy) <= 0.00001)) {
                bnEx=-1;
                for (j=0; j<bk[k1].nb; j++) {
                  n=bk[k1].adjusted[j];
                  n1=getBond(n)->at[0];
                  if (n1 == k1) n1=getBond(n)->at[1];
                  if (n1 == dsATN[i]) bnEx=n;
                  if (bnEx >= 0) break;
                };
                test= (bnEx >= 0);
                if (test) test=threeBondResolve(k1,bnEx,ux,uy,bk);
                if (! test) {
                  ux=ux1; uy=uy1;
                };
              };

              if ((ux==0) && (uy==0)) ux=1;
              fi=(k-nb-1)*PI/(double)k;
              //Addition for fluorine chain fragments...
              isChainFour=false;
              n=0; mm1=-1; mm2=-1; mAny=-1;
              if ((k == 4) && (getAtom(k1)->na == 6))  for (j=0; j<getAtom(k1)->nb; j++) {
                  n1=getAtom(k1)->ac[j];
                  if (atomDefine[n1] == 0) {
                    mAny=n1;
                    if (getAtom(n1)->nb == 1) n++; else {
                      if (mm1 == -1) mm1=n1; else mm2=n1;
                    };
                  };
                };
              if ((mm1 == -1) && (n == 3)) {
                mm1=mAny;
                n--;
              };
              isChainFour=(n == 2) && (mm1 >= 0);
              //End addition
              isCycle=false;
              if ((nb == 2) && ((k == 4) || (k == 5))) {
                n=0;
                for (j=0; j<bk[dsNA1[i]].nb; j++) {
                  k2=bk[dsNA1[i]].adjusted[j];
                  if (getBond(k2)->db > 1) {
                    n1=getBond(k2)->at[0];
                    if (n1 == k1) n1=getBond(k2)->at[1];
                    if (atomDefine[n1] != 0) n++;
                  };
                };
                isCycle=(n == 2);
              };
              if (isChainFour) {
                n=0;
                fi=PI/3;
                ux1= ux*cos(fi)+uy*sin(fi);
                uy1=-ux*sin(fi)+uy*cos(fi);
                cf=sqrt(ux1*ux1+uy1*uy1);
                if (cf != 0) {
                  ux1=ux1/cf; uy1=uy1/cf;
                };
                getAtom(mm1)->rx=getAtom(k1)->rx+ux1; //coordinates
                getAtom(mm1)->ry=getAtom(k1)->ry+uy1;
                atomDefine[mm1]=1;
                if (mm2 >= 0) {
                  fi=-PI/3;
                  ux1= ux*cos(fi)+uy*sin(fi);
                  uy1=-ux*sin(fi)+uy*cos(fi);
                  cf=sqrt(ux1*ux1+uy1*uy1);
                  if (cf != 0) {
                    ux1=ux1/cf; uy1=uy1/cf;
                  };
                  getAtom(mm2)->rx=getAtom(k1)->rx+ux1; //coordinates
                  getAtom(mm2)->ry=getAtom(k1)->ry+uy1; //coordinates
                  atomDefine[mm2]=1;
                };
                ux=0; uy=0;  //New cosines....
                for (j=0; j<getAtom(k1)->nb; j++) if (atomDefine[getAtom(k1)->ac[j]] > 0) {
                    k2=getAtom(k1)->ac[j];
                    ux=ux+(getAtom(k1)->rx-getAtom(k2)->rx);
                    uy=uy+(getAtom(k1)->ry-getAtom(k2)->ry);
                  };
                fi=PI/6;
                for (j=0; j<getAtom(k1)->nb; j++) {
                  n1=getAtom(k1)->ac[j];
                  if (atomDefine[n1] == 0) {
                    ux1= ux*cos(fi)+uy*sin(fi);
                    uy1=-ux*sin(fi)+uy*cos(fi);
                    cf=sqrt(ux1*ux1+uy1*uy1);
                    if (cf != 0) {
                      ux1=ux1/cf; uy1=uy1/cf;
                    };
                    getAtom(n1)->rx=getAtom(k1)->rx+ux1; //coordinates}
                    getAtom(n1)->ry=getAtom(k1)->ry+uy1; //coordinates}
                    fi=-fi;
                    atomDefine[n1]=1;
                  };
                };
              } else if (isCycle) {
                if (k == 4) fi=PI/6; else fi=PI/3;
                ux1= ux*cos(fi)+uy*sin(fi);
                uy1=-ux*sin(fi)+uy*cos(fi);
                cf=sqrt(ux1*ux1+uy1*uy1);
                if (cf != 0) {
                  ux1=ux1/cf; uy1=uy1/cf;
                };
                getAtom(dsATN[i])->rx=getAtom(k1)->rx+ux1; //coordinates
                getAtom(dsATN[i])->ry=getAtom(k1)->ry+uy1; //coordinates
                atomDefine[dsATN[i]]=1;
                for (j=0; j<getAtom(dsNA1[i])->nb; j++) {
                  k2=getAtom(dsNA1[i])->ac[j];
                  if (atomDefine[k2] == 0) {
                    ux1=ux*cos(fi)-uy*sin(fi);
                    uy1=ux*sin(fi)+uy*cos(fi);
                    if (cf != 0) {
                      ux1=ux1/cf; uy1=uy1/cf;
                    };
                    getAtom(k2)->rx=getAtom(k1)->rx+ux1;
                    getAtom(k2)->ry=getAtom(k1)->ry+uy1;
                    fi=0;
                    atomDefine[k2]=1;
                  };
                };
              } else {

                if (bk[dsNA1[i]].nb == 2) {  //two-connected fragment
                  //Search for triple bond or for two double-bonds
                  n1=bk[dsNA1[i]].adjusted[0];
                  n2=bk[dsNA1[i]].adjusted[1];
                  if ((getBond(n1)->tb == 3) || (getBond(n2)->tb == 3)) k=3; else
                    if ((getBond(n1)->tb == 2) && (getBond(n2)->tb == 2)) {
                      if (getAtom(dsNA1[i])->na == 6) k=3;
                    };
                };
                //Two-conncted fragment like pyrophosphate
                if ((k== 2) && (getAtom(dsNA1[i])->na != 6)) {
                  n1=getAtom(dsNA1[i])->ac[0];
                  n2=getAtom(dsNA1[i])->ac[1];
                  if ((getAtom(n1)->nb >= 4) && (getAtom(n2)->nb >= 4) && (getAtom(n1)->na != 6) && (getAtom(n2)->na != 6)) k=3;
                };
                //End pyrophosphate
                if (k==2) { //120 degrees fragment}
                  if ((ux1==0) && (uy1==0)) ux1=1;
                  fi=PI/3;
                  cf=uy*ux1-ux*uy1;
                  if (cf != 0) fi=fi*cf/abs(cf);
                };
                ux1=ux*cos(fi)+uy*sin(fi);
                uy1=-ux*sin(fi)+uy*cos(fi);
                cf=sqrt(ux1*ux1+uy1*uy1);
                if (cf != 0) {
                  ux1=ux1/cf; uy1=uy1/cf;
                };
                getAtom(dsATN[i])->rx=getAtom(k1)->rx+ux1; //coordinates
                getAtom(dsATN[i])->ry=getAtom(k1)->ry+uy1; //coordinates
                atomDefine[dsATN[i]]=1;
              };
            } else {                   //cyclic fragment}

              if ((ux==0) && (uy==0)) ux=1;
              fi=(k-nb-2)*PI/(double)k;
              ux1=ux*cos(fi)+uy*sin(fi);
              uy1=-ux*sin(fi)+uy*cos(fi);
              cf=sqrt(ux1*ux1+uy1*uy1);
              if (cf != 0) {
                ux1=ux1/cf; uy1=uy1/cf;
              };
              nb=dsSC[i];
              cs=nb+1;
              cf=1/(2*sin(PI/(double)cs));
              ux=getAtom(dsNA1[i])->rx+cf*ux1;
              uy=getAtom(dsNA1[i])->ry+cf*uy1;
              fi=2*PI/(double)cs;
              ux1=getAtom(dsNA1[i])->rx-ux;
              uy1=getAtom(dsNA1[i])->ry-uy;
              //coordinates of all atoms for the cycle under study are calculated}
              if ((nb + i) > dsATN.size()) nb=dsATN.size()-i; // Check added to avoid segfault below, see issue #1851
              for (j=0; j<nb; j++) {
                getAtom(dsATN[i+j-0])->rx=ux+ux1*cos((j+1)*fi)+uy1*sin((j+1)*fi);
                getAtom(dsATN[i+j-0])->ry=uy-ux1*sin((j+1)*fi)+uy1*cos((j+1)*fi);
                atomDefine[dsATN[i+j-0]]=1;
              };

              i=i+nb-1;
            };
            break;
          } else break;
        case 3:
        case 4: {

          twoAtomUnitVector(dsNA1[i],dsNA2[i],ux,uy,atomDefine);
          //calculation of an optimal side to add new fragment
          ux1=getAtom(dsNA1[i])->rx-getAtom(dsNA2[i])->rx;
          uy1=getAtom(dsNA1[i])->ry-getAtom(dsNA2[i])->ry;
          if (dsTP[i]==3)   {  //angle calc. for condenced cycle}
            nb=dsSC[i];
            cs=nb+2;
            fi=sqrt(ux1*ux1+uy1*uy1);
            cf=fi/(2*sin(PI/(double)cs)/cos(PI/(double)cs));
            add=0;
          } else {     //angle calc. for polycycle
            r=sqrt(ux1*ux1+uy1*uy1);
            add=(int)ceil(r);
            nb=dsSC[i];
            cs=nb+2+add;
            cf=r/(2*sin(PI*(nb+1)/(double)cs));
            r=r/2.0;
            cf=sqrt(cf*cf-r*r);
          };
          ux=(getAtom(dsNA1[i])->rx+getAtom(dsNA2[i])->rx)/2.0+ux*cf;
          uy=(getAtom(dsNA1[i])->ry+getAtom(dsNA2[i])->ry)/2.0+uy*cf;
          ux1=getAtom(dsNA1[i])->rx-ux;
          uy1=getAtom(dsNA1[i])->ry-uy;
          fi=2*PI/(double)cs;
          ux2=ux+ux1*cos((1.0+add)*fi)+uy1*sin((1.0+add)*fi);
          uy2=uy-ux1*sin((1.0+add)*fi)+uy1*cos((1.0+add)*fi);
          if ((abs(getAtom(dsNA2[i])->rx-ux2)<0.01) && (abs(getAtom(dsNA2[i])->ry-uy2)<0.01)) fi=-fi;
          //FAtom's coordinates calculation
          for (j=0; j<nb; j++) {
            getAtom(dsATN[i+j-0])->rx=ux+ux1*cos((j+1)*fi)+uy1*sin((j+1)*fi);
            getAtom(dsATN[i+j-0])->ry=uy-ux1*sin((j+1)*fi)+uy1*cos((j+1)*fi);
            atomDefine[dsATN[i+j-0]]=1;
          }
          i=i+nb-1;
          break;
        }
        }
        i++;
      }
    bondLengthNew=0;

    //Rescaling and shift of structure
    for (i=0; i<bondClean; i++)  bondLengthNew=bondLengthNew+bondLength(listBondClean[i]);
    bondLengthNew=bondLengthNew/(double)bondClean;
    xCenterNew=0; yCenterNew=0;
    for (i=0; i<atomClean; i++) {
      xCenterNew=xCenterNew+getAtom(listAtomClean[i])->rx;
      yCenterNew=yCenterNew+getAtom(listAtomClean[i])->ry;
    };
    xCenterNew=xCenterNew/(double)atomClean; yCenterNew=yCenterNew/(double)atomClean;
    bondLengthNew=0.15*bondLengthOld;
    //IOPT[7]-controlles, whether or not the atom's shifts should be created, if coordinates of pair of atoms are identical
    if (spn==3) {                     //Rescaling and shift coordinates for group (CODE=3)
      xCenterNew=getAtom(sCHA1)->rx;
      yCenterNew=getAtom(sCHA1)->ry;
      ux=getAtom(atomSecond)->rx-getAtom(sCHA1)->rx;
      uy=getAtom(atomSecond)->ry-getAtom(sCHA1)->ry;
      r=sqrt(ux*ux+uy*uy);
      ux=ux/r; uy=uy/r;
      c=ux*uvX+uy*uvY;
      s=ux*uvY-uy*uvX;
      for (i=0; i<atomClean; i++) {
        ux1=getAtom(listAtomClean[i])->rx-xCenterNew;
        uy1=getAtom(listAtomClean[i])->ry-yCenterNew;
        getAtom(listAtomClean[i])->rx=c*ux1-s*uy1;
        getAtom(listAtomClean[i])->ry=s*ux1+c*uy1;
      };
      xCenterNew=0;
      yCenterNew=0;

    };
    if (spn != 4) for (i=0; i<atomClean; i++) {   //New screen coordinates
        getAtom(listAtomClean[i])->rx=getAtom(listAtomClean[i])->rx-xCenterNew+xCenterOld;
        getAtom(listAtomClean[i])->ry=getAtom(listAtomClean[i])->ry-yCenterNew+yCenterOld;
      };
    // Tidy up
    free(bk);
  };


  void TSimpleMolecule::getMolfile(std::ostream & data) {
    char buff[BUFF_SIZE];
    TSingleAtom * sa;
    TSingleBond * sb;
    int charge,bondType,stereoType;

    data<<endl<<endl<<endl;  //three empty lines
    snprintf(buff,BUFF_SIZE,"%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d%3d V2000",nAtoms(),nBonds(),0,0,0,0,0,0,0,0,999);
    data << buff << endl;
    for (int i=0; i<nAtoms(); i++) {
      sa=getAtom(i);
      switch (sa->nc) {
      case 1: charge = 3; break;
      case 2: charge = 2; break;
      case 3: charge = 1; break;
      case -1: charge = 5; break;
      case -2: charge = 6; break;
      case -3: charge = 7; break;
      default: charge=0; break;
      }
      snprintf(buff, BUFF_SIZE, "%10.4f%10.4f%10.4f %-3s%2d%3d%3d%3d%3d",
               sa->rx, sa->ry, 0.0, (aSymb[sa->na]).c_str(), 0,charge,0,0,0);
      data << buff << endl;
    };
    for (int i=0; i<nBonds(); i++) {
      sb=getBond(i);
      bondType=sb->tb;
      stereoType=0;
      if (bondType == 9) {
        bondType=1;
        stereoType=1;
      } else if (bondType == 10) {
        bondType=1;
        stereoType=6;
      } else if (bondType == 11) {
        bondType=1;
        stereoType=4;
      };
      snprintf(buff, BUFF_SIZE, "%3d%3d%3d%3d%3d%3d",(sb->at[0]+1), (sb->at[1]+1), bondType, stereoType, 0, 0);
      data << buff << endl;
    };
  };

  //*******************************************************************************
  //Below routines from ChainRotate-flipping acyclic bonds and enlarging bonds to get fine picture
  //*******************************************************************************

  double TSimpleMolecule::atomDistanceMetric(int an) {
    int i, n;
    double r, rr;
    double x1, y1, x2, y2, d, result;

    if (getAtom(an)->nb == 0) return 0;
    result=0.01;
    n=getAtom(an)->ac[0];
    x1=getAtom(an)->rx-getAtom(n)->rx;
    y1=getAtom(an)->ry-getAtom(n)->ry;
    rr=sqrt(x1*x1+y1*y1);
    for (i=0; i<nAtoms(); i++) if ((i != an) && (i != n)) {
        x2=getAtom(i)->rx-getAtom(n)->rx;
        y2=getAtom(i)->ry-getAtom(n)->ry;
        d=rr*sqrt(x2*x2+y2*y2);
        if (d == 0) r=0; else r=(x1*x2+y1*y2)/d;
        if (r > 0) result=result+r;
      };
    return result;
  };


  double xDistPoint(double x1, double y1, double x2, double y2, double x0, double y0) {
    //The function finds distance between FAtom AN and bond BN (including sign).
    // The bond is treated as segment, not as straight line!}
    double d, r, r1, yMin, yMax, xMin, xMax, xx, yy, result;

    if (y1 < y2) {
      yMin=y1;
      yMax=y2;
    } else {
      yMin=y2;
      yMax=y1;
    };
    xx=x1-x2;
    yy=y1-y2;
    r1=sqrt(xx*xx+yy*yy);
    yMin=yMin-0.1*r1; yMax=yMax+0.1*r1;
    d=y2-y1;
    if (abs(d) < 1E-8) {
      result=1E9;
      return result;
    };
    if ((y0 > yMin) && (y0 < yMax)) {
      r=x1+(y0-y1)*(x2-x1)/d;
      if (x1 > x2) {
        xMin=x2;
        xMax=x1;
      } else {
        xMin=x1;
        xMax=x2;
      };
      xMin=xMin-0.1*r1;
      xMax=xMax+0.1*r1;
      if (r < xMin) r=xMin;
      if (r > xMax) r=xMax;
      result=r-x0;
    } else result=1E9;
    return result;
  };

  bool overlapped(double x1A, double y1A, double x2A, double y2A,
                  double x1B, double y1B, double x2B, double y2B, double delta) {

    double a1, b1, c1, a2, b2, c2, r, cX, cY, x, y, r1, r2;
    double xMin, xMax, yMin, yMax;
    bool result=false;

    r=y2A-y1A;
    if (abs(r) > 1E-9) {
      a1=1/r;
      cY=-y1A/r;
    } else {
      a1=1E9;
      cY=-y1A*1E9;
      if (r < 0) {
        a1=-a1;
        cY=-cY;
      };
    };
    r=x2A-x1A;
    if (abs(r) > 1E-9) {
      b1=1/r;
      cX=x1A/r;
    } else {
      b1=1E9;
      cX=x1A*1E9;
      if (r < 0) {
        b1=-b1;
        cX=-cX;
      };
    };
    b1=-b1;
    c1=cX+cY;
    r=y2B-y1B;
    if (abs(r) > 1E-9) {
      a2=1/r;
      cY=-y1B/r;
    } else {
      a2=1E9;
      cY=-y1B*1E9;
      if (r < 0) {
        a2=-a2;
        cY=-cY;
      };
    };
    r=x2B-x1B;
    if (abs(r) > 1E-9) {
      b2=1/r;
      cX=x1B/r;
    } else {
      b2=1E9;
      cX=x1B*1E9;
      if (r < 0) {
        b2=-b2;
        cX=-cX;
      };
    };
    b2=-b2;
    c2=cX+cY;
    r1=b1*c2-b2*c1;
    r2=a1*b2-a2*b1;
    if (abs(r2) > 1E-9) y=r1/r2; else {
      y=1E9;
      if (r1 < 0) y=-y;
    };
    r1=c1*a2-c2*a1;
    r2=a1*b2-a2*b1;
    if (abs(r2) > 1E-9) x=r1/r2; else {
      x=1E9;
      if (r1 < 0) x=-x;
    };
    if (x1A < x2A) {
      xMin=x1A;
      xMax=x2A;
    } else {
      xMin=x2A;
      xMax=x1A;
    };
    if (y1A < y2A) {
      yMin=y1A;
      yMax=y2A;
    } else {
      yMin=y2A;
      yMax=y1A;
    };
    xMin=xMin-delta;
    xMax=xMax+delta;
    yMin=yMin-delta;
    yMax=yMax+delta;
    result=((x >= xMin) && (x <= xMax) && (y >= yMin) && (y <= yMax));
    if (result) {
      if (x1B < x2B) {
        xMin=x1B;
        xMax=x2B;
      } else {
        xMin=x2B;
        xMax=x1B;
      };
      if (y1B < y2B) {
        yMin=y1B;
        yMax=y2B;
      } else {
        yMin=y2B;
        yMax=y1B;
      };
      xMin=xMin-delta;
      xMax=xMax+delta;
      yMin=yMin-delta;
      yMax=yMax+delta;
      result=((x >= xMin) && (x <= xMax) && (y >= yMin) && (y <= yMax));
    };
    if (! result) result=(abs(xDistPoint(x1A,y1A,x2A,y2A,x1B,y1B)) < delta);
    if (! result) result=(abs(xDistPoint(x1A,y1A,x2A,y2A,x2B,y2B)) < delta);
    if (! result) result=(abs(xDistPoint(x1B,y1B,x2B,y2B,x1A,y1A)) < delta);
    if (! result) result=(abs(xDistPoint(x1B,y1B,x2B,y2B,x2A,y2A)) < delta);
    return result;
  };


  bool TSimpleMolecule::bondsOverlapped(int bN1, int bN2, double delta) {
    double x1A,y1A,x2A,y2A,x1B,y1B,x2B,y2B;
    bool result;

    x1A=getAtom(getBond(bN1)->at[0])->rx;
    y1A=getAtom(getBond(bN1)->at[0])->ry;
    x2A=getAtom(getBond(bN1)->at[1])->rx;
    y2A=getAtom(getBond(bN1)->at[1])->ry;

    x1B=getAtom(getBond(bN2)->at[0])->rx;
    y1B=getAtom(getBond(bN2)->at[0])->ry;
    x2B=getAtom(getBond(bN2)->at[1])->rx;
    y2B=getAtom(getBond(bN2)->at[1])->ry;

    result=false;
    if (((x1A>(x1B+delta)) && (x2A>(x1B+delta)) && (x1A>(x2B+delta)) && (x2A>(x2B+delta))) ||
        ((x1A<(x1B-delta)) && (x2A<(x1B-delta)) && (x1A<(x2B-delta)) && (x2A<(x2B-delta))) ||
        ((y1A>(y1B+delta)) && (y2A>(y1B+delta)) && (y1A>(y2B+delta)) && (y2A>(y2B+delta))) ||
        ((y1A<(y1B-delta)) && (y2A<(y1B-delta)) && (y1A<(y2B-delta)) && (y2A<(y2B-delta)))) return result;
    result=overlapped(x1A,y1A,x2A,y2A,x1B,y1B,x2B,y2B,delta);
    return result;
  };


  int TSimpleMolecule::hasOverlapped(double delta, bool findFirst) {
    int i, j;
    bool test;
    double r,xx,yy;
    int result=0;

    for (i=1; i<(nBonds()-1); i++) for (j=i+1; j<nBonds(); j++) {
        test=(getBond(i)->at[0] == getBond(j)->at[0]) || (getBond(i)->at[0] == getBond(j)->at[1]) ||
          (getBond(i)->at[1] == getBond(j)->at[0]) || (getBond(i)->at[1] == getBond(j)->at[1]);
        if (! test) if (bondsOverlapped(i,j,delta)) {
            result++;
            if (findFirst) return result;
          };
      };
    for (i=0; i<(nAtoms()-1); i++) for (j=i+1; j<nAtoms(); j++) {
        xx=getAtom(i)->rx-getAtom(j)->rx;
        yy=getAtom(i)->ry-getAtom(j)->ry;
        r=sqrt(xx*xx+yy*yy);
        if (r < (2*delta)) {
          result++;
          if (findFirst) return result;
        };
      };
    return result;
  };

  bool TSimpleMolecule::checkOverlapped() {
    bool result;
    result=hasOverlapped(averageBondLength()/32,true)>0;
    return result;
  };

  double TSimpleMolecule::averageBondLength() {
    double result=0;
    if (nBonds() == 0) return result;
    for (int i=0; i<nBonds(); i++) result=result+bondLength(i);
    result=result/(double)nBonds();
    return result;
  };

  void TSimpleMolecule::flipSmall(int cHB) {
    //the bond number CHB is used to divide the fragment into two parts. For lower
    //part flip is executed. Case CHB-ring bond-no effects}

    int cHA1, cHA2, n;
    bool test;
    std::vector<int>list1(listarSize());
    double r, xc, yc, xo, yo, xn, yn;
    int i;

    if (cHB < 0) return;

    test=makeFragment(list1,getBond(cHB)->at[1],getBond(cHB)->at[0]);
    if (list1.size() > 1) {
      //One of the atoms haven't neighbours-flip unavalable
      cHA1=getBond(cHB)->at[0];
      cHA2=getBond(cHB)->at[1];
      xc=getAtom(cHA2)->rx-getAtom(cHA1)->rx; //Axes direction calculation
      yc=getAtom(cHA2)->ry-getAtom(cHA1)->ry;
      r=sqrt(xc*xc+yc*yc);
      xc=xc/r;
      yc=yc/r;
      xo=xc*xc-yc*yc;
      yo=2*xc*yc;

      for (i=0; i<list1.size(); i++) {
        //rotation at angle Pi around axes for all atoms in the LIST fragment
        n=list1[i];
        xc=getAtom(n)->rx-getAtom(cHA1)->rx;
        yc=getAtom(n)->ry-getAtom(cHA1)->ry;
        xn=xc*xo+yc*yo;
        yn=xc*yo-yc*xo;
        getAtom(n)->rx=getAtom(cHA1)->rx+xn;
        getAtom(n)->ry=getAtom(cHA1)->ry+yn;
      };
    };
  };

  void TSimpleMolecule::bondEnlarge(int bN) {
    double r;
    std::vector<int> list(listarSize());
    int cHA1, cH1, cH2, n;
    bool test;
    double xc, yc, xc1, yc1;
    int i;

    for (i=0; i<nAtoms(); i++) list[i]=i;
    cHA1=getBond(bN)->at[0];
    test=makeFragment(list,cHA1,getBond(bN)->at[1]);
    if (list[0] == getBond(bN)->at[0]) { //center definition
      cH1=getBond(bN)->at[0];
      cH2=getBond(bN)->at[1];
    } else {
      cH1=getBond(bN)->at[1];
      cH2=getBond(bN)->at[0];
    };
    xc=getAtom(cH1)->rx-getAtom(cH2)->rx;
    yc=getAtom(cH1)->ry-getAtom(cH2)->ry;
    r=sqrt(xc*xc+yc*yc);
    xc=xc/r;
    yc=yc/r;
    xc1=getAtom(cH2)->rx-getAtom(cH1)->rx;
    yc1=getAtom(cH2)->ry-getAtom(cH1)->ry;
    r=r*2;
    for (i=0; i<list.size(); i++) { //coordinates change
      n=list[i];
      getAtom(n)->rx=getAtom(n)->rx+xc1+r*xc;
      getAtom(n)->ry=getAtom(n)->ry+yc1+r*yc;
    };
  };

  int sproduct(TSimpleMolecule & sm, int br, int i1, int i2) {
    /*
      BR-central bond's number in array BOND, I1, I2-bond's numbers, which are
      connected to different atoms of BR. The BR bond is treated by the subroutine
      as a strait line. On return SPRODUCT has value 1 if both I1 and I2 lies at
      one side of strait line (Z), 2-if at different side (E) and 0 if I1 or I2
      is collinear with BR */

    int crAN[4];  //0-th element will not be used-translation from Delphi
    double crRx[4];
    double crRy[4];
    int i;
    double l1,l2;
    int result=0;

    crAN[0]=sm.getBond(br)->at[0];
    crAN[1]=sm.getBond(br)->at[1];
    if ((sm.getBond(i1)->at[0] != crAN[0]) && (sm.getBond(i1)->at[0] != crAN[1])) {
      crAN[2]=sm.getBond(i1)->at[0];
    } else {
      crAN[2]=sm.getBond(i1)->at[1];
    };
    if ((sm.getBond(i2)->at[0] != crAN[0]) && (sm.getBond(i2)->at[0] != crAN[1])) {
      crAN[3]=sm.getBond(i2)->at[0];
    } else {
      crAN[3]=sm.getBond(i2)->at[1];
    };
    for (i=0; i<4; i++) {
      crRx[i]=sm.getAtom(crAN[i])->rx;
      crRy[i]=sm.getAtom(crAN[i])->ry;
    };
    for (i=1; i<4; i++) {
      crRx[i]=crRx[i]-crRx[0];
      crRy[i]=crRy[i]-crRy[0];
    };
    l1=crRx[1]*crRy[2]-crRy[1]*crRx[2];
    l2=crRx[1]*crRy[3]-crRy[1]*crRx[3];
    if ((l1 == 0) || (l2 == 0)) return result;
    if (((l1 > 0) && (l2 > 0)) || ((l1 < 0) && (l2 < 0))) result=1; else result=2;
    return result;
  };

  bool TSimpleMolecule::correctDblBondStereo() {
    TSimpleMolecule &sm = *this;
    int i,j,an1,an2,bn1,bn2,n;
    bool result = false;

    //Flip bonds to show Z/E orientation
    for (i=0; i<sm.nBonds(); i++) {
      TSingleBond* dblbond = sm.getBond(i);
      if (dblbond->bstereo_refs.empty())
        continue;

      an1 = dblbond->at[0];
      an2 = dblbond->at[1];

      int ref_atom1 = 0;
      if (dblbond->bstereo_refs[ref_atom1]==OBStereo::ImplicitRef)
        ref_atom1 = 1;
      int ref_atom2 = 2;
      if (dblbond->bstereo_refs[ref_atom2]==OBStereo::ImplicitRef)
        ref_atom2 = 3;
      short int cistrans=1; // cistrans of 1 => cis, 2 => trans
      if ((ref_atom2 - ref_atom1) == 2)
        cistrans=2;

      bn1=-1; bn2=-1;
      for (j=0; j<sm.nBonds(); ++j) {
        TSingleBond* bond = sm.getBond(j);
        if ((bond->at[0]==an1 && bond->at[1]!=an2) || (bond->at[0]==an2 && bond->at[1]!=an1) ||
            (bond->at[1]==an1 && bond->at[0]!=an2) || (bond->at[1]==an2 && bond->at[0]!=an1)) {
          // This is one of the single bonds around the dbl bond
          if (bond->at[0]==dblbond->bstereo_refs[ref_atom1] || bond->at[1]==dblbond->bstereo_refs[ref_atom1])
            bn1=j;
          if (bond->at[0]==dblbond->bstereo_refs[ref_atom2] || bond->at[1]==dblbond->bstereo_refs[ref_atom2])
            bn2=j;
        }
      }

      if ((bn1 >= 0) && (bn2 >= 0)) {
        n = sproduct(sm,i,bn1,bn2); // 1 for cis, 2 for trans
        if (n != cistrans) {
          sm.flipSmall(i);
          result = true;
        }
      }
    }
    return result;
  }

  bool compareAtoms(int a1, int a2, const std::vector<std::vector<int> *> aeqList) {
    std::vector<int> * l1;
    std::vector<int> * l2;
    unsigned int i;
    bool result=false;

    if ((a1 < 0) || (a2 < 0) || (a1 >= aeqList.size()) || (a2 >= aeqList.size())) return result;
    l1 = (std::vector<int> *)(aeqList.at(a1));
    l2 = (std::vector<int> *)(aeqList.at(a2));
    if (l1 == nullptr || l2 == nullptr) return result;
    if (l1->size() != l2->size()) return result;
    result=true;
    for (i=0; i<l1->size(); i++) if ((*l1)[i] != (*l2)[i]) {
        result=false;
        break;
      };
    return result;
  };

  int TSimpleMolecule::fragmentSecond(int sphere, int att, int secAt, const std::vector<int> a,
                                      const std::vector<int> b, const neighbourlist *bk, std::vector<int>& wSphere) {

    /*Generate a longinteger number, which is characterize fragment with atom
      CHA in center. Up to second neigbour's sphere are took into account. Array
      A contains the atom's codes, generated by ALLATATOM, array B-bond's codes,
      generated by BONDCONVERSION*/

    int i,j,k,n,i1,i2,i3,jj;
    std::vector<int> aDist(listarSize());
    std::vector<int> aList(listarSize());
    std::vector<int> atomoBond(listarSize());
    std::vector<int> * aPrev [3];
    bool test,testOK;
    int w2;
    int l2,l3,tl1,tl2;
    std::vector<int> ab(listarSize());
    int result=0;
    //    String s;

    if (nAtoms()==0) return result;


    for (j=0; j<3; j++) aPrev[j]=new std::vector<int>(listarSize());
    for (i=0; i<nAtoms(); i++) {
      aDist[i]=65700;
      atomoBond[i]=0;
      for (j=0; j<3; j++) (*aPrev[j])[i]=-1;
    };
    for (i=0; i<sphere; i++) wSphere[i]=0;
    aDist[att]=0;
    k=0;
    atomoBond[att]=a[att];
    testOK=false;
    test=true;

    while (test) {
      test=false;
      k++;
      for (i1=0; i1<nAtoms(); i1++) if (aDist[i1]==(k-1)) { //K-sphere number, K-1-previous sphere
          if (bk[i1].nb > 0) for (j=0; j<bk[i1].nb; j++) {
              //for each neighbour
              i3=bk[i1].adjusted[j];//[I1].BN[J];
              i2=getBond(i3)->at[0];
              if (i2 == i1) i2=getBond(i3)->at[1];

              if ((aDist[i2] >= k) && (aDist[i2] <= 65700)) {
                //if the neighbour has not been added yet to list}
                aDist[i2]=k;          //Mark neighbour's sphere number
                jj=0;
                test=true;
                for (jj=1; jj<=3; jj++) {
                  if (((*aPrev[jj-1])[i2] == -1) || (jj == 3)) {
                    (*aPrev[jj-1])[i2]=i1;
                    break;
                  };
                };
                w2=a[i2];
                w2=w2 << 6;
                w2=w2+b[i3];
                w2=w2 ^ atomoBond[i2];  //atomoBond[I2]:=AtomoBond[I2] xor W2; !!!!!!!
                atomoBond[i2]=w2;
              };
            };
        };
      if (secAt < 0) testOK=(k==sphere); else testOK=((k>=sphere) && (aDist[secAt] < 65700));
      if (testOK) test=false;
    }; //end WHILE
    // At this point I have sphere numbers in Adist, corresponding AtomoBond word, number of atom(s), from
    //which the desirable atom were generated

    for (i=0; i<nAtoms(); i++) ab[i]=atomoBond[i];
    for (i1=k; i1>=1; i1--) {
      n=0;
      for (i=0; i<nAtoms(); i++) if (aDist[i] == i1) {
          aList[n]=i;
          n++;
        };
      if (n > 0) {
        i2=0;
        for (i=0; i<n; i++) {
          for (j=1; j<=3; j++) if ((*aPrev[j-1])[aList[i]] >= 0) {
              tl1=ab[aList[i]];
              tl2=atomoBond[(*aPrev[j-1])[aList[i]]]; // [Aprev[J][AList[I]]];
              tl2=tl2 << 9;
              tl1=tl1 ^ tl2;
              ab[aList[i]]=tl1;
            };
        };
        //Sorting
        if (n > 1) for (i=0; i<(n-1); i++) for (j=i+1; j<n; j++) if (ab[aList[i]] < ab[aList[j]]) {
                i2=aList[i]; aList[i]=aList[j]; aList[j]=i2;
              };
        if (n > 1) i2=15/(n-1);
        l2=ab[aList[0]];
        if (n > 1) for (i=1; i<n; i++) {
            l3=ab[aList[i]];
            // Shift in unsigned to avoid signed overflow UB — this is a
            // fingerprint hash, so wraparound is the desired behavior.
            l3=static_cast<int>(static_cast<unsigned int>(l3) << (i*i2));
            l2=l2 ^ l3;
          };
        l3=0;
        for (i=0; i<n; i++) l3=l3+getAtom(aList[i])->nc;
        if (l3 != 0) l2=-l2;
        for (i=0; i<n; i++) l2=l2 + a[aList[i]];  //Addition from 04.04.94}
        wSphere[i1-1]=l2;
      } else wSphere[i1-1]=0;
    };
    if ((secAt == -1) || (secAt == 65700)) result=0; else result=a[secAt];
    //freeing resources
    for (j=0; j<3; j++) delete(aPrev[j]);


    return result;
  };


  void TSimpleMolecule::makeEquivalentList(std::vector<int>& equivalenceList, bool isTopologyOnly) {
    //AllAboutCycles must be called early

    std::vector<int> a(listarSize());
    std::vector<int> b(listarSize());
    TSimpleMolecule * em;
    int i,j,n;
    neighbourlist *bk;
    std::vector<std::vector<int> *> aeqList(0);
    std::vector<int> * lL;


    em= new TSimpleMolecule();
    em->moleculeCopy(*this);

    //Only topology-nothing more!!!!
    if (isTopologyOnly) {
      for (i=0; i<em->nAtoms(); i++) {
        em->getAtom(i)->na=6;
        em->getAtom(i)->nv=4;
        em->getAtom(i)->rl=6;
        em->getAtom(i)->nc=0;
      };
      for (i=0; i<em->nBonds(); i++) em->getBond(i)->tb=1;
      em->defineAtomConn();
    } else {
      for (i=0; i<em->nBonds(); i++) if ((em->getBond(i)->tb >= 9) && (em->getBond(i)->tb <= 11)) em->getBond(i)->tb=1;
    };
    bk=(neighbourlist *)calloc(nAtoms(), sizeof(adjustedlist));
    em->defineBondConn(bk);
    //
    for (i=0; i<em->nAtoms(); i++) a[i]=em->getAtom(i)->allAtAtom();
    for (i=0; i<em->nBonds(); i++) b[i]=em->getBond(i)->bondConversion();
    for (i=0; i<em->nAtoms(); i++) {
      lL=new vector<int>(em->listarSize());
      for (j=0; j<lL->size(); j++) (*lL)[i]=0;
      em->fragmentSecond(em->nAtoms(),i,-1,a,b,bk,*lL);
      aeqList.push_back(lL);
    };
    equivalenceList.resize(em->nAtoms());


    n=0;
    for (i=0; i<equivalenceList.size(); i++) equivalenceList[i]=0;
    for (i=0; i<em->nAtoms(); i++) if (equivalenceList[i] == 0) {
        n++;
        equivalenceList[i]=n;
        if (i < (em->nAtoms()-1)) for (j=i+1; j<em->nAtoms(); j++) if (equivalenceList[j] == 0) {
              if (compareAtoms(j,i,aeqList)) equivalenceList[j]=n;
            }
      };

    //freeing resorces
    for (int i=0; i<aeqList.size(); i++) delete(aeqList.at(i));
    aeqList.clear();
    free(bk);
    delete(em);
  };

  // Iterates through all of the possibilities 1000..., 0100..., 1100..., 0010...
  // (in the case where maxValues is [1111...]). Returns false when all possibilities
  // have been generated (true otherwise).
  bool incrementValues(std::vector<int>& currentValues, const std::vector<int> maxValues) {
    unsigned int i, l;
    bool result=false;

    for (i=0; i<currentValues.size(); i++) {
      l=currentValues[i];
      l++;
      if (l <= maxValues[i]) {
        currentValues[i]=l;
        result=true;
        break;
      }
      else
        currentValues[i]=0;
    }
    return result;
  }



  int TSimpleMolecule::correctOverlapped() {
    double r;
    TSimpleMolecule * smCopy=new TSimpleMolecule();
    TSimpleMolecule * bestStore=nullptr;
    TSimpleMolecule * tmpStore = new TSimpleMolecule();
    int i, j, n, k, kk;
    bool test;
    int result;
    std::vector<int> currentValues(nBonds());
    std::vector<int> maxValues(nBonds());
    std::vector<int> rotBondList(nBonds());
    int at1,at2;


    r=averageBondLength()/blDenominator;
    k=hasOverlapped(r,false);
    result=k;
    smCopy->moleculeCopy(*this);
    test=true;
    while (test) {
      test=false;
      for (i=0; i<nBonds(); i++) if (getBond(i)->db == 0) {
          flipSmall(i);
          kk=hasOverlapped(r,false);
          if (kk<k) {
            test=true;
            k=kk;
            smCopy->moleculeCopy(*this);
          } else moleculeCopy(*smCopy);
        }
      if (k == 0) test=false;
    }
    result=k;
    if (result > 0)  {  //multiple bonds rotation...
      smCopy->moleculeCopy(*this);

      for (i=0; i<rotBondList.size(); i++)
        rotBondList[i]=0;
      for (i=0; i<nBonds(); i++) {
        TSingleBond* bond = getBond(i);
        if (bond->db != 0)
          continue;
        // Skip if it's a dbl bond with defined CT stereo as this will already have been set
        if (bond->tb == 2 && !bond->bstereo_refs.empty())
          continue;

        at1 = bond->at[0];
        at2 = bond->at[1];
        if ((getAtom(at1)->nb >= 2) && (getAtom(at2)->nb >=2)) {
          //checking if greter 1
          test=false;
          if (getAtom(at1)->nb == 3) {
            test=true;
            for (j=0; j<getAtom(at1)->nb; j++) {
              k=getAtom(at1)->ac[j];
              if ((k != at2) && (getAtom(k)->nb > 1)) test=false;
            }
          }
          if ((! test) && (getAtom(at2)->nb == 3)) {
            test=true;
            for (j=0; j<getAtom(at2)->nb; j++) {
              k=getAtom(at2)->ac[j];
              if ((k != at1) && (getAtom(k)->nb > 1)) test=false;
            }
          }
          if (! test) rotBondList[i]=1;
        }
      }

      vector<int> inner_bonds;
      vector<int> remainder;
      int n_rotors = setupRotorSearch(rotBondList, inner_bonds, remainder);
      int kk_flip;

      if (n_rotors > 0) {  // All possible combinations of rotations for the inner_bonds...
        int m_rotors = n_rotors <= nRotBondsMax ? n_rotors : nRotBondsMax;
        currentValues.resize(m_rotors);
        maxValues.resize(m_rotors);
        for (i=0; i<m_rotors; i++) {
          currentValues[i]=0;
          maxValues[i]=1;
        }
        bestStore= new TSimpleMolecule();
        bestStore->moleculeCopy(*smCopy);
        test=true;
        k = result;
        while (test && (k>0)) {
          moleculeCopy(*smCopy);
          n=0;
          for (i=0; i<inner_bonds.size(); i++) if (inner_bonds[i] != 0) {
              n++;
              if (currentValues[n-1] == 1) flipSmall(i);
            }
          kk = hasOverlapped(r, false);
          if (kk < k) {
            k = kk;
            bestStore->moleculeCopy(*this);
          }
          // Now greedily try the remainder of the bonds
          for (i=0; i<remainder.size(); i++) {
            tmpStore->moleculeCopy(*this);
            flipSmall(remainder[i]);
            kk_flip = hasOverlapped(r, false);
            if (kk < kk_flip) // Revert to unflipped
              moleculeCopy(*tmpStore);
            else
              kk = kk_flip;
            if (kk < k) {
              k = kk;
              bestStore->moleculeCopy(*this);
            }
          }
          test=incrementValues(currentValues,maxValues);
        };// (k=0) or (not test);
        moleculeCopy(*bestStore);
        result=k;
      };
    };
    if (result>0) { //Bond enlarge....]
      k=hasOverlapped(r,false);
      n=1;
      while (n != 0) {
        n=0;
        for (i=0; i<nBonds(); i++) if (getBond(i)->db == 0) {
            smCopy->moleculeCopy(*this);
            smCopy->bondEnlarge(i);
            kk=smCopy->hasOverlapped(r,false);
            if (kk < k) {
              k=kk;
              n=i;
            };
            smCopy->flipSmall(i);
            kk=smCopy->hasOverlapped(r,false);
            if (kk < k) {
              k=kk;
              n=-i;
            };
          };
        if (abs(n) != 0) {
          bondEnlarge(abs(n));
          if (n < 0) flipSmall(abs(n));
        };
      };
      result=k;
    };
    //freeing resources
    delete smCopy;
    delete bestStore;
    delete tmpStore;

    return result;
  };

  // Comparison function for sort in setupRotorSearch
  bool CompareRotor(const pair<int, int> &a, const pair<int, int> &b)
  {
    return(a.second < b.second);   //inside->out
  }

  int TSimpleMolecule::setupRotorSearch(const vector<int> &rotBondList, vector<int>& inner_bonds, vector<int>& remainder)
  {
    vector<pair<int,int> > vtmp; // pair of (bond_id, gtd_score)
    int at1, at2;
    int n_rotors = 0;

    for (unsigned int i=0; i<rotBondList.size(); i++)
      if (rotBondList[i] != 0) {
        n_rotors++;
        at1 = getBond(i)->at[0];
        at2 = getBond(i)->at[1];
        int score = getAtom(at1)->gtd + getAtom(at2)->gtd;
        vtmp.push_back(pair<int,int> (i, score));
      }
    // sort the rotatable bonds by GTD score
    sort(vtmp.begin(), vtmp.end(), CompareRotor);

    // inner_bonds will be identical to rotBondList except that
    // only the inner ten rotatable bonds will have values of 1
    inner_bonds.resize(rotBondList.size(), 0);
    for (unsigned int j=0; j<nRotBondsMax && j<vtmp.size(); ++j) {
      inner_bonds[vtmp[j].first] = 1;
    }

    // remainder will store all of the other rotatable bonds
    if (vtmp.size() > nRotBondsMax) {
      for (unsigned int j=nRotBondsMax; j<vtmp.size(); ++j) {
        remainder.push_back(vtmp[j].first);
      }
    }

    return n_rotors;
  }

  //********************************************************************************
  //                 Determine Bond orders from attached hydrogens
  //*******************************************************************************

  void deleteIntElement(std::vector<int> * source, int index) {
    unsigned int i, n;
    std::vector<int> temp(source->size()-1);

    n=0;
    for (i=0; i<source->size(); i++) if (i != index) {
        temp[n]=(*source)[i];
        n++;
      };
    source->resize(source->size()-1);
    for (i=0; i<source->size(); i++) (*source)[i]=temp[i];
  };

  int hydrogenValency(int na) {   //Hydrogen valency
    int result=0;
    if (na < NELEMMCDL) result=hVal[na];
    return result;
  };

  int maxValency(int na) {        //Maximal valency of a specified element
    int result=8;
    if (na < NELEMMCDL) result=maxVal[na];
    return result;
  };

  static int findAlternateSinglets(const std::vector<int>iA1, const std::vector<int>iA2, const std::vector<int> nH,
                                   const std::vector<int> hydrogenValency, std::vector<int>& bondOrder, int nAtoms, int nBonds) {
    //return values: 0 - no singlet found, 1 - found and assigned singlet, 2 - assigned singlet only with special

    std::vector<int>nUnassigned(nAtoms);
    std::vector<int>nAssigned(nAtoms);
    std::vector<int>bNumber(nAtoms);


    int i,n,k;
    int result;

    result=0;
    for (i=0; i<nAtoms; i++) {
      nUnassigned[i]=0;
      nAssigned[i]=0;
    };
    for (i=0; i<nBonds; i++) {
      n=bondOrder[i];
      if (n == 0) {
        nUnassigned[iA1[i]]=nUnassigned[iA1[i]]+1;
        nUnassigned[iA2[i]]=nUnassigned[iA2[i]]+1;
        bNumber[iA1[i]]=i;
        bNumber[iA2[i]]=i;
      } else {
        nAssigned[iA1[i]]=nAssigned[iA1[i]]+n;
        nAssigned[iA2[i]]=nAssigned[iA2[i]]+n;
      };
    };

    for (i=0; i<nAtoms; i++) if ((hydrogenValency[i] > 0) && (nUnassigned[i] == 1)) {
        n=bNumber[i];
        k=hydrogenValency[i]-(nH[i]+nAssigned[i]);
        if (k < 1) {
          if (k == 0) {  //increment H valence by 2
            k=2;
          } else {
            k=1;
          };
          result=2;
        };
        if (k > 3) {
          k=3;
          result=3;
        };
        bondOrder[n]=k;
        if (result == 0) {
          result=1;
        };
      };
    return result;
  };

  static void makeAssignment(const std::vector<int> iA1, const std::vector<int> iA2, const std::vector<int> nH,
                             const std::vector<int> hydrogenValency,	const std::vector<int> bondAssignment, const std::vector<int> specialFlag,
                             std::vector<int>& bondOrder, int nAtoms, int nBonds, int & nAss) {

    int i,k;

    nAss=0;
    for (i=0; i<nBonds; i++) if (bondOrder[i] == 0) {
        bondOrder[i]=bondAssignment[nAss]+specialFlag[i];
        nAss++;
        k=1;
        while (k != 0) {
          k=findAlternateSinglets(iA1,iA2,nH,hydrogenValency,bondOrder,nAtoms,nBonds);
        };
      };
  };

  static bool analyzeOK(const std::vector<int> iA1,const std::vector<int> iA2, const std::vector<int> nH,
                        const std::vector<int> hydrogenValency,	const std::vector<int> maxValency, const std::vector<int> bondOrder,
                        const std::vector<int> atomCheckFlag, int nAtoms, int nBonds, int & nGtMax, int & nNEH, int & nOddEven,
                        bool testExceedHydrogen, bool oddEvenCheck) {

    std::vector<int>nBondsValency(nAtoms);  //dynamically allocation
    int i,k;
    bool result;

    nGtMax=0;
    nNEH=0;
    nOddEven=0;
    for (i=0; i<nAtoms; i++) nBondsValency[i]=0;
    for (i=0; i<nBonds; i++) {
      nBondsValency[iA1[i]]=nBondsValency[iA1[i]]+bondOrder[i];
      nBondsValency[iA2[i]]=nBondsValency[iA2[i]]+bondOrder[i];
    };
    for (i=0; i<nAtoms; i++) if (atomCheckFlag[i] == 1) {
        if (nBondsValency[i] > maxValency[i]) nGtMax++;
        if (testExceedHydrogen) {
          if ((nH[i]+nBondsValency[i]) != hydrogenValency[i]) nNEH++;
        } else {
          if ((hydrogenValency[i] > 0) && (nH[i] > 0)) if ((nH[i]+nBondsValency[i]) != hydrogenValency[i]) nNEH++;
          if ((hydrogenValency[i] > 0) && (nH[i] ==0)) if (nBondsValency[i] < hydrogenValency[i]) nNEH++;
          if (oddEvenCheck) {
            k=nH[i]+nBondsValency[i];
            if ((k % 2) != (maxValency[i] % 2)) nOddEven++;
          };
        };
      };
    result=((nGtMax == 0) && (nNEH == 0) && (nOddEven == 0));
    return result;
  };

  static bool incrementAssignment(std::vector<int>& bondAssignment, int nAss) {
    int i,j;
    bool result;

    result=false;
    for (i=nAss-1; i>=0; i--) if (bondAssignment[i] == 1) {
        bondAssignment[i]++;
        if (i < (nAss-1)) for (j=i+1; j<nAss; j++) bondAssignment[j]=1;
        result=true;
        return result;
      };
    return result;
  };

  static int determineBondsOrder(const std::vector<int> iA1, const std::vector<int> iA2,
                                 const std::vector<int> nH, const std::vector<int> maxValency,std::vector<int>& bondOrder,
                                 std::vector<int>& hydrogenValency, int nAtoms, int nBonds, bool /*oddEvenViolate*/) {
    //On input BortOrder has to be initialized. Real bond orders have to be putted. 0 means this order should be determined
    //MaxValency and HydrogenValency and NH are required only for those atoms, which are included in BondOrder=0

    std::vector<int>nNeighbour(nAtoms);
    std::vector<int>bondAssignment(nBonds);  //Should be Max(Atoms, Bonds);
    std::vector<int>bondOrderStore(nBonds);
    std::vector<int>specialFlag(nBonds);

    int i,j,k,n,nAss;
    bool  test;
    int nGtMax;  //number of atoms, for which maximal valency is exausted
    int nNEH;    //bumber of atoms, for which number of calc and desirable hydrogens are disagree
    int nOddEven;//Parity violation - atom with odd maximal valency has even valency and back
    int result;

    k=nAtoms;
    if (nBonds > k) k=nBonds;
    k++;

    result=0;
    for (i=0; i<nAtoms; i++) nNeighbour[i]=0;
    for (i=0; i<nBonds; i++) {
      nNeighbour[iA1[i]]=nNeighbour[iA1[i]]+1;
      nNeighbour[iA2[i]]=nNeighbour[iA2[i]]+1;
      specialFlag[i]=0;
    };
    //Special flag-find allene and cumulene
    for (i=0; i<nBonds; i++) {
      if ((nNeighbour[iA1[i]] == 2) && (nNeighbour[iA2[i]] == 2) && (hydrogenValency[iA1[i]] == 4)
          && (hydrogenValency[iA2[i]] == 4) && (nH[iA1[i]] == 0) && (nH[iA2[i]] == 0)) specialFlag[i]=1;
    };

    //correct hydrogen valency by 2 if required....
    for (i=0; i<nAtoms; i++) if (hydrogenValency[i] > 0) {
        n=nH[i]+nNeighbour[i];
        if (n > hydrogenValency[i]) hydrogenValency[i]=hydrogenValency[i]+2;
        if (n > hydrogenValency[i]) hydrogenValency[i]=hydrogenValency[i]+2;
      };
    //Label all bonds which have order 1 exactly
    for (i=0; i<nAtoms; i++) if ((hydrogenValency[i] > 0) && (nH[i] > 0)) {
        n=nH[i]+nNeighbour[i];
        if (n == hydrogenValency[i]) for (j=0; j<nBonds; j++) if (((iA1[j] == i) || (iA2[j] == i)) && (bondOrder[j] == 0)) {
              bondOrder[j]=1;
            };
      };

    k=1;
    while (k != 0) {
      k=findAlternateSinglets(iA1,iA2,nH,hydrogenValency,bondOrder,nAtoms,nBonds);
    };
    //repeat default no. hydrogens correction
    for (i=0; i<nAtoms; i++) nNeighbour[i]=0;
    for (i=0; i<nBonds; i++) {
      k=bondOrder[i];
      if (k == 0) k=1;
      nNeighbour[iA1[i]]=nNeighbour[iA1[i]]+k;
      nNeighbour[iA2[i]]=nNeighbour[iA2[i]]+k;
    };
    //correct hydrogen valency by 2 if required....


    for (i=0; i<nAtoms; i++) if (hydrogenValency[i] > 0) {
        n=nH[i]+nNeighbour[i];
        if (n > hydrogenValency[i]) hydrogenValency[i]=hydrogenValency[i]+2;
        if (n > hydrogenValency[i]) hydrogenValency[i]=hydrogenValency[i]+2;
      };

    //below array NNeighbour is used for picking atoms, for which valency have to be checked..
    for (i=0; i<nAtoms; i++) nNeighbour[i]=0;
    for (i=0; i<nBonds; i++) if (bondOrder[i] == 0) {
        nNeighbour[iA1[i]]=1;
        nNeighbour[iA2[i]]=1;
      };
    test=false;
    for (i=0; i<nBonds; i++) {
      bondAssignment[i]=1;
      bondOrderStore[i]=bondOrder[i];
      if (bondOrder[i] == 0) test=true;   //bad bonds exists-must to assign...
    };
    if (! test) return result;    //All fine-not necessary especially alternate
    test=false;
    while (! test) {              //Try to assign with fina valencies
      for (i=0; i<nBonds; i++) bondOrder[i]=bondOrderStore[i];
      makeAssignment(iA1,iA2,nH,hydrogenValency,bondAssignment,specialFlag,bondOrder,nAtoms,nBonds,nAss);
      test=analyzeOK(iA1,iA2,nH,hydrogenValency,maxValency,bondOrder,nNeighbour,nAtoms,nBonds,nGtMax,nNEH,nOddEven,true,true);
      if (! test) {
        test=! incrementAssignment(bondAssignment,nAss);
        if (test) result=1;
      };
    };
    if (result == 1) {        //try to assign with hydrogen valency exceeded
      result=0;
      for (i=0; i<nBonds; i++) bondAssignment[i]=1;
      test=false;
      while (! test) {
        for (i=0; i<nBonds; i++) bondOrder[i]=bondOrderStore[i];
        makeAssignment(iA1,iA2,nH,hydrogenValency,bondAssignment,specialFlag,bondOrder,nAtoms,nBonds,nAss);
        test=analyzeOK(iA1,iA2,nH,hydrogenValency,maxValency,bondOrder,nNeighbour,nAtoms,nBonds,nGtMax,nNEH,nOddEven,false,true);
        if (! test) {
          test=! incrementAssignment(bondAssignment,nAss);
          if (test) result=1;
        };
      };
    };
    if (result == 1) {        //hydrogen valency is still bad. Try to analyze withoud Odd/Even checking (metals, etc).
      result=0;
      for (i=0; i<nBonds; i++) bondAssignment[i]=1;
      test=false;
      while (! test) {
        for (i=0; i<nBonds; i++) bondOrder[i]=bondOrderStore[i];
        makeAssignment(iA1,iA2,nH,hydrogenValency,bondAssignment,specialFlag,bondOrder,nAtoms,nBonds,nAss);
        test=analyzeOK(iA1,iA2,nH,hydrogenValency,maxValency,bondOrder,nNeighbour,nAtoms,nBonds,nGtMax,nNEH,nOddEven,false,false);
        if (! test) {
          test=! incrementAssignment(bondAssignment,nAss);
          if (test) result=1;
        };
      };
    };
    return result;
  };

  int alternate(const std::vector<int> aPosition,const std::vector<int> aCharge,
                const std::vector<int> aRad,const std::vector<int> nHydr, const std::vector<int> iA1,
                const std::vector<int> iA2, std::vector<int> & bondOrders, int nAtoms, int nBonds) {

    std::vector<int> hVal(nAtoms);
    std::vector<int> maxVal(nAtoms);
    int i,result;

    for (i=0; i<nAtoms; i++) {
      hVal[i]=hydrogenValency(aPosition[i]);
      if (hVal[i] > 0) {
        if (aRad[i] != 0) hVal[i]=hVal[i]-1;  //returns 0 for non-radical and 2 for radical
        if (aPosition[i] == 5) hVal[i]=hVal[i]-aCharge[i];           //B
        else if (aPosition[i] == 6) hVal[i]=hVal[i]-abs(aCharge[i]); //C
        else hVal[i]=hVal[i]+aCharge[i];  //Heteroatoms
        if (hVal[i] < 0) hVal[i]=0;
      };
      maxVal[i]=maxValency(aPosition[i]);
      if (aCharge[i] != 0) maxVal[i]=maxVal[i]+1;
    };
    result=determineBondsOrder(iA1,iA2,nHydr,maxVal,bondOrders,hVal,nAtoms,nBonds,true);
    return result;
  };

  int alternate(OBMol * pmol, const std::vector<int> nH, std::vector<int>& bondOrders) {
    //This overloaded method does not work. By unknown reason I cannot extract
    //connection matrix from pmol

    //number of hydogens must be filled on input.
    std::vector<int> hVal(pmol->NumAtoms());
    std::vector<int> maxVal(pmol->NumAtoms());
    std::vector<int>iA1(pmol->NumBonds());
    std::vector<int>iA2(pmol->NumBonds());
    int nAtoms,nBonds;
    int i,k,na;
    OBAtom * sa;
    OBBond * sb;
    int result=0;

    pmol->AssignSpinMultiplicity();

    nAtoms=pmol->NumAtoms();
    nBonds=pmol->NumBonds();

    for (i=0; i<nBonds; i++) {
      sb=pmol->GetBond(i);
      iA1[i]=sb->GetBeginAtomIdx()-1;
      iA2[i]=sb->GetEndAtomIdx()-1;
    };


    for (i=1; i<=nAtoms; i++) {
      sa=pmol->GetAtom(i);
      na=sa->GetAtomicNum();
      hVal[i-1]=hydrogenValency(na);
      if (hVal[i-1] > 0) {
        if (sa->GetSpinMultiplicity() != 0) hVal[i-1]=hVal[i-1]-1;  //returns 0 for non-radical and 2 for radical
        k=sa->GetFormalCharge();
        if (sa->IsHeteroatom()) hVal[i-1]=hVal[i-1]+k;
        else if (na == 6) hVal[i-1]=hVal[i-1]-abs(k);
        else hVal[i-1]=hVal[i-1]-k;
        if (hVal[i-1] < 0) hVal[i-1]=0;
      };
      maxVal[i-1]=maxValency(na);
      if (sa->GetFormalCharge() != 0) maxVal[i-1]=maxVal[i-1]+1;
    };

    result=determineBondsOrder(iA1,iA2,nH,maxVal,bondOrders,hVal,nAtoms,nBonds,true);
    for (i=0; i<nBonds; i++) {
      sb=pmol->GetBond(i);
      sb->SetBondOrder(bondOrders[i]);
    };
    return result;
  };
  //*****************************************************************************
  //*******************  EditedMolecule class ***********************************
  //*****************************************************************************


  class TEditedMolecule: public TSimpleMolecule {
  protected:
    std::vector<int> queryQHydr;
    std::vector<int> queryAGer;
    std::vector<int> queryBQCounter;
    std::vector<int> queryCurrentAssignment;
    std::vector<int> queryEnum;
    std::vector<int> queryInverse;

    bool queryStereoQ,fIsQueryPrepare;

    std::vector<int> aSTested;
    std::vector<int> bSTested;
    std::vector<int> bSTestedStore;

    void removeHydrogen(std::vector<int> * qHydr, std::vector<int> * qEnumerator);
    void atomBondChange();
    bool stereoBondChange();
    void directBondAss(int& bnq, bool& test, bool& test1, bool const* const* beq,
                       bool const* const* aeq, std::vector<int>& bqcounter, std::vector<int>& aqtested,
                       std::vector<int>& bstested, std::vector<int>& bqtested, std::vector<int>& astested,
                       const std::vector<int> ager, const neighbourlist *bsconn, TSimpleMolecule * smol);
    bool allQueryPresent(const std::vector<int> qA, const std::vector<int> qB,
                         int nA, int nB);
  public:
    static int const NOOTHER_MASK=1;
    static int const AROMATIC_MASK=NOOTHER_MASK << 1;
    static int const EXACTNUMBER_MASK=AROMATIC_MASK << 1;
    bool fIOPT10;   //charge sensitivite
    bool fIOPT11;   //isotopes difference
    int  fIOPT12;   //stereo bond change
    bool fIOPT13;   //semipolar bond as double
    std::vector<int> queryAQTested;
    std::vector<int> queryBQTested;
    std::vector<int>* fIncludedList;
    TEditedMolecule() : TSimpleMolecule() {
      fIncludedList=nullptr;
	  fIOPT10=false;
	  fIOPT11=false;
	  fIOPT13=true;
	  fIOPT12=1;
    };

    int prepareQuery(TSimpleMolecule & sMol);
    bool fragmentSearch(TEditedMolecule * molecule1, std::vector<int>* bondLabel);
    TEditedMolecule * extractFragment(int atomN, std::vector<int> * enumerator);
    void addAsTemplate(TEditedMolecule& fragmentMol, int thisAN, int smAN, int thisBN, int smBN, bool isAddition);
    int addFragment(TEditedMolecule & eMolecule, int naDEF, int cha, int chb,
                    int chb1, std::vector<int>& list, double xOldCenter, double yOldCenter, double xNewCenter,
                    double yNewCenter, double scale, double cFi, double sFi, int buttonStatus, bool clearEnumerator);
  };

  int TEditedMolecule::addFragment(TEditedMolecule & eMolecule, int naDEF, int cha, int chb,
                                   int chb1, std::vector<int>& list, double xOldCenter, double yOldCenter, double xNewCenter,
                                   double yNewCenter, double scale, double cFi, double sFi, int buttonStatus, bool clearEnumerator) {

    //    The procedure is used by TEMPLATE and MAKEPOLI procedure to add large frag-
    //     ments to structure. The connection between structure and fragment may be
    //     achived both through atoms (CHA>0) and through bonds (CHB>0).
    //                              Variables description:
    //     NAtoms-number of atoms in structure
    //     NBonds-number of bonds in structure
    //     ATOM-atom's attributes in structure
    //     BOND-bond's attributes in structure
    //     CONN-some invariants of bond-connection matrix
    //     NAtoms1, NBonds1, ATOM1, BOND1, CONN1-the same for fragments (these varia-
    //       bles can contain data for more, than one fragments)
    //     LIST-atom's number in arrays ATOM1,CONN1, which should be added to structure
    //     NaDef-number of principal components in LIST array
    //     CHA-atom's number in array ATOM (structure), which was selected for addition
    //     CHB-bond's number in array BOND (structure), which was selected for addition
    //     CHB1-bond's number in array BOND1 (fragment), which was selected for addition
    //     XOldCenter,YOldCenter-old coordinates of the fragment on screen (center rotation)
    //     XNewCenter,YNewCenter-new coordinates of the fragment on screen
    //     Scale-scale variables to resize fragment
    //     CFi,SFi-cosine and sine of the angle of rotation of the fragment relative
    //      old coordinate of ths type of a fragment addition (active only for addition
    //       through atoms). If e fragment on screen
    //     ButtonStatus-regulateButtonStatus=1 then fragment will be added to structure
    //       (new bond arise). If ButtonStatus=2 then fragment will be freezed in
    //       structure (selected new atom for structure will be deleted, no new bond
    //       will be arised)}

    //    Returns 0 if addition is OK,  otherwise:
    //    =1 - Maxima number of atoms is reached
    //    =2 - Maximal number of bonds is reached

    int i,j1,j2,na,k1,k2,j,nb,n1,n2;
    int l1=0;
    int l2=0;
    bool test;
    double r1,r2,r3,r4,emBLength;
    TSingleAtom * sa=nullptr;
    TSingleBond * sb=nullptr;
    int result=0;



    //return result;
    //Analizing on boundaries}
    k2=1; k1=1;

    //Analizing of bond's
    nb=0;
    emBLength=0;
    std::vector<int> bList(eMolecule.nAtoms(), 0);
    for (i=0; i<naDEF; i++) bList[list[i]]=1;
    for (i=0; i<eMolecule.nBonds(); i++) {
      n1=eMolecule.getBond(i)->at[0];
      n2=eMolecule.getBond(i)->at[1];
      if ((bList[n1] != 0) || (bList[n2] != 0)) {
        nb++;
        emBLength=emBLength+eMolecule.bondLength(i);
      }
    }
    if (nb > 0) emBLength=emBLength/nb;

    na=nAtoms();
    nb=nBonds();


    if (chb >= 0) {   //Bond was selected for addition

      l1=getBond(chb)->at[0];     //L1,L2,K1,K2-atoms numbers for corresponding bonds
      l2=getBond(chb)->at[1];     //in structure and in fragment
      k1=eMolecule.getBond(chb1)->at[0];
      k2=eMolecule.getBond(chb1)->at[1];
      j=0;
      for (i=0; i<naDEF; i++) {
        test=(list[i] == k1) || (list[i] == k2);
        if (! test) {
          list[j]=list[i];
          j++;
        };
      };
      list[naDEF-2]=k1;
      list[naDEF-1]=k2;
      //It is necessary to make the pair of atoms last in array so they may be
      // deleted easy from final structure
    }
    //Addition from 13 May 2000
    if (((cha < 0) || (nBonds() == 0)) && (emBLength > 0)) {
      if (nBonds() == 0) r1=DEFAULTBONDLENGTH; else r1=averageBondLength();
      scale=r1/emBLength;
    }
    //End addition

    for (i=0; i<naDEF; i++) {
      //recalculation of atom's coordinates in fragment to new ones, compartible
      //with the structure coordinates. Some rescaling and rotation take place
      r1=eMolecule.getAtom(list[i])->rx-xOldCenter;
      r2=eMolecule.getAtom(list[i])->ry-yOldCenter;
      r3=scale*(r1*cFi-r2*sFi);
      r4=scale*(r1*sFi+r2*cFi);
      sa=eMolecule.getAtom(list[i])->clone();
      sa->rx=xNewCenter+r3;
      sa->ry=yNewCenter+r4;
      if (clearEnumerator) sa->enumerator=0;
      sa->fragIndex=0;
      addAtom(sa);
    }
    if (chb >= 0) {
      //specific for bond-to-bond addition block-determination of correspondence
      //of pair of atoms, which make bond, in fragment to the same pair of atoms in
      //structure. Determination is perfomed through internuclear distances}
      r1=getAtom(l2)->rx-getAtom(nAtoms()-1)->rx;
      r2=getAtom(l2)->ry-getAtom(nAtoms()-1)->ry;
      r3=r1*r1+r2*r2;
      r1=getAtom(l1)->rx-getAtom(nAtoms()-1)->rx;
      r2=getAtom(l1)->ry-getAtom(nAtoms()-1)->ry;
      r4=r1*r1+r2*r2;
      if (r3 < r4) {k2=nAtoms()-1; k1=nAtoms()-2;
      } else {k2=nAtoms()-2; k1=nAtoms()-1;}
    }

    for (i=0; i<eMolecule.nBonds(); i++) if ((chb < 0) || ((chb1 >= 0) && (i != chb1))) {
        //addition of bonds from fragment to structure
        test=false;
        j1=-1;
        do { //Search, if bond I from BOND1 is presented in the fragment
          j1++;
          if (eMolecule.getBond(i)->at[0] == list[j1]) test=true;
        }  while (! (test || (j1 == (naDEF-1))));
        if (test) {  //Bond is presented-addition
          j2=-1;
          do     //Search for second atom, which makes I-th bond in fragment
            j2++;
          while (eMolecule.getBond(i)->at[1] != list[j2]);
          sb=new TSingleBond();
          j1=na+j1;            //atoms, which make the bond, renumeration
          j2=na+j2;
          sb->tb=eMolecule.getBond(i)->tb;  //attributes copy
          sb->at[0]=j1;
          sb->at[1]=j2;
          if (clearEnumerator) sb->enumerator=0;
          addBond(sb);
        }
      }


    if (chb >= 0) { //bond-to-bond addition
      for (i=0; i<nBonds(); i++) { //atom renumeration
        if (getBond(i)->at[0] == k1) getBond(i)->at[0]=l1;
        if (getBond(i)->at[0] == k2) getBond(i)->at[0]=l2;
        if (getBond(i)->at[1] == k1) getBond(i)->at[1]=l1;
        if (getBond(i)->at[1] == k2) getBond(i)->at[1]=l2;
      }
      //Two atoms deleted...
      delete(fAtom[nAtoms()-1]);
      delete(fAtom[nAtoms()-2]);
      fAtom.resize(nAtoms()-2);


      //two atoms, which make the bond to be added in fragment,
      //are deleted. They occupy last positions in arrays ATOM and CONN due to
      //initial sorting
      /* Contains mistake-commented to the better time
         i=0;
         do {                 //Two or three bond connection is calculated
         j=na;
         if (j < nAtoms()) do {               //Search for concided atoms
         rr1=getAtom(i)->rx-getAtom(j)->rx;
         rr2=getAtom(i)->ry-getAtom(j)->ry;
         lR=sqrt(rr1*rr1+rr2*rr2);
         test=((i != j) & ((lR) <= 3));
         if (test) { //Concided pair of atoms found
         for (k=0; k<nBonds(); k++) {
         //Re-assignment of bonds
         if (getBond(k)->at[0] == j) getBond(k)->at[0]=i;
         if (getBond(k)->at[1] == j) getBond(k)->at[1]=i;
         }
         deleteAtom(j);                          //Deletion of atom
         k=0;
         do {      //Search for bonds, which have identical pair of atom or which
         l=k;
         do {
         test=(getBond(k)->at[0] == getBond(l)->at[0])
         && (getBond(k)->at[1] == getBond(l)->at[1]);
         test=test || (getBond(k)->at[0] == getBond(l)->at[1])
         && (getBond(k)->at[1] == getBond(l)->at[0]);
         test=test || (getBond(l)->at[0] == getBond(l)->at[1]);
         if (test) {         //Bad bonds was found-deletion
         deleteBond(l);
         l--;
         }
         l++;
         } while (l < nBonds());
         k++;
         } while (k < (nBonds()-1));
         j--;
         }
         j++;
         } while (j < nAtoms());
         i++;
         } while (i < na);
      */
    }


    if ((buttonStatus>1) && (chb < 0)) {
      //if fragment 'is freezed' through atom, the atom needs to be deleted
      for (i=0; i<nBonds(); i++) {
        if (getBond(i)->at[0] == cha) getBond(i)->at[0]=na;
        if (getBond(i)->at[1] == cha) getBond(i)->at[1]=na;
      }
      defineAtomConn();
      deleteAtom(cha);                      //atom deleting
    }; //new values for attribute array

    defineAtomConn();
    //Search for badly-connected aromatic bonds
    /* commented to better time. Use alternation bond instead
       if (chb>=0) {
       for (i=0; i<nBonds(); i++) bTested[i]=0;
       do {
       i=0;
       do {                               //Search for badly connected atom
       test=(getAtom(i)->currvalence > maxVal[getAtom(i)->na]);
       i++;
       } while (! (test || (i == nAtoms())));
       if (test) {                   //Creation aromtic bond list
       n=0;
       aList[0]=i-1;
       doubleSearch=true;
       do {
       j=nb;
       test=false;
       if (j < nBonds()) do {
       test=((getBond(j)->at[0] == aList[n]) || (getBond(j)->at[1] == aList[n]));
       if (doubleSearch) test=(test && (getBond(j)->tb == 2)); else test=(test && (getBond(j)->tb == 1));
       test=(test && (bTested[j] == 0));
       j++;
       } while (! (test || (j == nBonds())));
       if (test) {              //Addition to the aromatic list
       bList[n]=j-1;
       bTested[j]=1;
       l=getBond(j-1)->at[0];
       if (l == aList[n]) l=getBond(j-1)->at[1];
       n++;
       aList[n]=l;
       doubleSearch= ! doubleSearch;
       }
       } while (test);
       if (n > 1) {                 //Alternation of aromatic chain
       for (j=1; j<n; j++) {
       if ((int)Math.IEEEremainder(J,2) == 1) fBond.setTB(BList.getValue(J),(byte)1); else fBond.setTB(BList.getValue(J),(byte)2);
       }
       fAtom.setCurrValence(AList.getValue(1),(byte)(fAtom.getCurrValence(AList.getValue(1))-1));
       fAtom.setCurrValence(AList.getValue(N),(byte)(fAtom.getCurrValence(AList.getValue(N))+1));
       Test=true;
       } else {                     //Unable to alternate
       J=Nb;
       Test=false;
       if (J < fBond.maxIndex()) do {                          //Search for double bond
       J=J+1;
       Test=((fBond.getAT(J,1) == AList.getValue(N)) || (fBond.getAT(J,2) == AList.getValue(N)));
       Test=(Test & (fBond.getTB(J) == 2));
       } while (! (Test || (J == fBond.maxIndex())));
       if (Test) {        //Conversion of found double to single bond
       fBond.setTB(J,(byte)1);
       fAtom.setCurrValence(fBond.getAT(J,1),(byte)(fAtom.getCurrValence(fBond.getAT(J,1))-1));
       fAtom.setCurrValence(fBond.getAT(J,2),(byte)(fAtom.getCurrValence(fBond.getAT(J,2))-1));
       Test=true;
       }
       }
       }
       } while (test);
       }
    */
    return result;
  }



  void TEditedMolecule::addAsTemplate(TEditedMolecule& fragmentMol, int thisAN, int smAN, int thisBN, int smBN, bool isAddition) {
    int nAtomsOld,nBondsOld,naDef1,naDef,i;
    bool test,test1,test2;
    std::vector<int> list;
    double r,scale,xOld,yOld,xNew,yNew,xCenter,yCenter;
    double r1;
    double r2;
    double xu1;
    double yu1;
    double xu2;
    double yu2;
    double cAngle;
    double rxTemp1,ryTemp1;
    int mouseButton=0;
    int n;
    double amin;



    if (fragmentMol.nAtoms() == 0) return;
    if ((thisAN<0) && (thisBN<0)) {
      this->moleculeCopy(fragmentMol);
      return;
    }

    naDef1=smAN;
    test1=true;
    test2=false;
    xCenter=0;
    yCenter=0;
    if (thisBN >= 0) {
      naDef1=fragmentMol.getBond(smBN)->at[0];
      test1=false; test2=true;
    }

    scale=1;
    xOld=0;
    yOld=0;
    test=fragmentMol.makeFragment(list,naDef1,-1); //creation of template's fragment
    //Scale definitions

    if (thisAN >= 0) { //connection through atoms
      xCenter=this->getAtom(thisAN)->rx;
      yCenter=this->getAtom(thisAN)->ry;
      naDef=thisAN;
      scale=1;
      r1=0;
      r2=0;
      if (fragmentMol.getAtom(naDef1)->nb > 0) {
        amin=100000000; n=1;
        for (i=0; i<fragmentMol.getAtom(naDef1)->nb; i++) {
          rxTemp1=fragmentMol.getAtom(naDef1)->rx-fragmentMol.getAtom(fragmentMol.getAtom(naDef1)->ac[i])->rx;
          ryTemp1=fragmentMol.getAtom(naDef1)->ry-fragmentMol.getAtom(fragmentMol.getAtom(naDef1)->ac[i])->ry;
          r1=sqrt(rxTemp1*rxTemp1+ryTemp1*ryTemp1);
          if(r1 < amin) {
            amin=r1;
            n=i;
          };
        };
        rxTemp1=fragmentMol.getAtom(naDef1)->rx-fragmentMol.getAtom(fragmentMol.getAtom(naDef1)->ac[n])->rx;
        ryTemp1=fragmentMol.getAtom(naDef1)->ry-fragmentMol.getAtom(fragmentMol.getAtom(naDef1)->ac[n])->ry;
        r1=sqrt(rxTemp1*rxTemp1+ryTemp1*ryTemp1);
      } else r1=DEFAULTBONDLENGTH;

      if (this->getAtom(naDef)->nb > 0) {
        amin=100000000; n=1;
        for (i=0; i<this->getAtom(naDef)->nb; i++) {
          rxTemp1=this->getAtom(naDef)->rx-this->getAtom(this->getAtom(naDef)->ac[i])->rx;
          ryTemp1=this->getAtom(naDef)->ry-this->getAtom(this->getAtom(naDef)->ac[i])->ry;
          r2=sqrt(rxTemp1*rxTemp1+ryTemp1*ryTemp1);
          if(r2 < amin) {
            amin=r2;
            n=i;
          };
        };
        rxTemp1=this->getAtom(naDef)->rx-this->getAtom(this->getAtom(naDef)->ac[n])->rx;
        ryTemp1=this->getAtom(naDef)->ry-this->getAtom(this->getAtom(naDef)->ac[n])->ry;
        r2=sqrt(rxTemp1*rxTemp1+ryTemp1*ryTemp1);
      } else {
        if (this->nBonds() > 0) r2=this->averageBondLength(); else r2=DEFAULTBONDLENGTH;
      }
      if (r1 > 0) scale=r2/r1; else scale=1;
    } else if (thisBN >= 0) {      //connection through bonds
      rxTemp1=fragmentMol.getAtom(fragmentMol.getBond(smBN)->at[0])->rx-fragmentMol.getAtom(fragmentMol.getBond(smBN)->at[1])->rx;
      ryTemp1=fragmentMol.getAtom(fragmentMol.getBond(smBN)->at[0])->ry-fragmentMol.getAtom(fragmentMol.getBond(smBN)->at[1])->ry;
      r1=sqrt(rxTemp1*rxTemp1+ryTemp1*ryTemp1);
      rxTemp1=this->getAtom(this->getBond(thisBN)->at[0])->rx-this->getAtom(this->getBond(thisBN)->at[1])->rx;
      ryTemp1=this->getAtom(this->getBond(thisBN)->at[0])->ry-this->getAtom(this->getBond(thisBN)->at[1])->ry;
      r2=sqrt(rxTemp1*rxTemp1+ryTemp1*ryTemp1);
      if (r1 > 0) scale=r2/r1; else scale=1;
    }
    //Old coordinates definition
    if (smAN >= 0) {
      xOld=fragmentMol.getAtom(smAN)->rx;
      yOld=fragmentMol.getAtom(smAN)->ry;
    }
    if (thisBN >= 0) {
      xOld=(fragmentMol.getAtom(fragmentMol.getBond(smBN)->at[0])->rx+fragmentMol.getAtom(fragmentMol.getBond(smBN)->at[1])->rx)/2;
      yOld=(fragmentMol.getAtom(fragmentMol.getBond(smBN)->at[0])->ry+fragmentMol.getAtom(fragmentMol.getBond(smBN)->at[1])->ry)/2;
    }


    //New coordinate definition
    if (thisBN >= 0) {  //connection through bonds
      xNew=(this->getAtom(this->getBond(thisBN)->at[0])->rx+this->getAtom(this->getBond(thisBN)->at[1])->rx)/2;
      yNew=(this->getAtom(this->getBond(thisBN)->at[0])->ry+this->getAtom(this->getBond(thisBN)->at[1])->ry)/2;
    } else {        //connection through atoms}
      if (isAddition) { //addition of fragment
        this->unitVector(thisAN,xu1,yu1);
        if (xu1 > -0.999) r=yu1/(1+xu1); else if (yu1 > 0) r=1E9; else r=-1E9;
        cAngle=2*180*atan(r)/PI;
        if (true) {
          cAngle=(int)(cAngle/30);
          cAngle=30*cAngle;
          r=cAngle*PI/180;
          xu1=cos(r);
          yu1=sin(r);
        }
        xNew=r1*scale*xu1+this->getAtom(thisAN)->rx;
        yNew=r1*scale*yu1+this->getAtom(thisAN)->ry;
      } else {                     //freezing of fragment
        if (this->getAtom(thisAN)->nb == 0) {
          xu1=1; yu1=0;
        } else if (this->getAtom(thisAN)->nb == 1) {
          xu1=this->getAtom(thisAN)->rx-this->getAtom(this->getAtom(thisAN)->ac[0])->rx;
          yu1=this->getAtom(thisAN)->ry-this->getAtom(this->getAtom(thisAN)->ac[0])->ry;
          //yu1=this.fAtom.getRY(thisAN)-this.fAtom.getRY(this.fAtom.getAC(thisAN,1));
          r2=sqrt(xu1*xu1+yu1*yu1);
          if (r2 > 1.0E-4) {
            xu1=xu1/r2;
            yu1=yu1/r2;
          } else {xu1=1; yu1=0;}
        } else this->unitVector(thisAN,xu1,yu1);
        if (xu1 > -0.999) r=yu1/(1+xu1); else if (yu1 > 0) r=1E9; else r=-1E9;
        cAngle=2*180*atan(r)/PI;
        if (true) {
          cAngle=(int)(cAngle/30);
          cAngle=30*cAngle;
          r=cAngle*PI/180;
          xu1=cos(r);
          yu1=sin(r);
        }
        xNew=this->getAtom(thisAN)->rx;
        yNew=this->getAtom(thisAN)->ry;
      }
    }


    //Angle definition
    if (thisAN >= 0) {                             //connection through atoms
      fragmentMol.unitVector(smAN,xu2,yu2);
      xu2=-xu2; yu2=-yu2;
      r1=xu1*xu2+yu1*yu2;
      r2=yu1*xu2-xu1*yu2;
      nBondsOld=this->nBonds();
      nAtomsOld=this->nAtoms();
      if (isAddition) mouseButton=1; else mouseButton=2;

      this->addFragment(fragmentMol,list.size(),thisAN,thisBN,smBN,list,
                        xOld,yOld,xNew,yNew,scale,r1,r2,mouseButton,false);


      if (isAddition) {
        this->addBond(1,nAtomsOld,thisAN);
      } else nAtomsOld=nAtomsOld-1;
    } else if ((smBN >= 0) && (thisBN >= 0)) {       //connection through bonds
      this->bondUnitVector(thisBN,xu1,yu1);
      fragmentMol.bondUnitVector(smBN,xu2,yu2);
      xu2=-xu2; yu2=-yu2;
      r1=xu1*xu2+yu1*yu2;
      r2=yu1*xu2-xu1*yu2;
      nBondsOld=this->nBonds();
      nAtomsOld=this->nAtoms();
      addFragment(fragmentMol,list.size(),thisAN,thisBN,smBN,list,
                  xOld,yOld,xNew,yNew,scale,r1,r2,1,false);
    }
  }


  TEditedMolecule * TEditedMolecule::extractFragment(int atomN, std::vector<int> * enumerator) {

    std::vector<int> list(listarSize());
    std::vector<int>  inverseList(listarSize());
    int i,j,k;
    bool test;
    TSingleAtom * sa;
    TSingleBond * sb;
    TEditedMolecule * result=nullptr;

    if ((atomN < 0) || (atomN >= nAtoms())) return result;
    if (enumerator != nullptr) for (i=0; i<nAtoms(); i++) (*enumerator)[i]=-1;
    for (i=0; i<nAtoms(); i++) inverseList[i]=-1;
    test=makeFragment(list,atomN,-1);


    if (list.size()>1) for (i=0; i<(list.size()-1); i++) for (j=i+1; j<list.size(); j++) if (list[i]>list[j]) {
            k=list[i];
            list[i]=list[j];
            list[j]=k;
          };
    for (i=0; i<list.size(); i++) inverseList[list[i]]=i;

    result= new TEditedMolecule();
    for (i=0; i<list.size(); i++) {
        sa=this->getAtom(list[i])->clone();
        result->addAtom(sa);
        if (enumerator != nullptr) (*enumerator)[list[i]]=i;
      }
    if (nBonds() > 0) for (i=0; i<nBonds(); i++)
                        if (inverseList[getBond(i)->at[0]] >= 0) {
                          sb=getBond(i)->clone();
                          sb->at[0]=inverseList[getBond(i)->at[0]];
                          sb->at[1]=inverseList[getBond(i)->at[1]];
                          result->addBond(sb);
                        }
    return result;
  }



  int TEditedMolecule::prepareQuery(TSimpleMolecule & sMol) {
    /*Returns error code:
      0  - no error
      -1 - input molecule is not assigned or number of atoms equal zero
      -2 - unconnected fragments were detected
      -3 - an exception take place*/

    TEditedMolecule * molecule1;
    int i,j,k,l;
    bool test,test1,test2,test3;
    int aQ1,aQ2,bNQ;
    int result;
    bool whileCondition,whileCondition1;

    result=-1;
    if (sMol.nAtoms()==0) return result;
    sMol.defineAtomConn();
    sMol.allAboutCycles();
    //Three above line instead of this line: CalculateAllIndeces(SMOl);
    moleculeCopy(sMol);

    result=0;


    fIsQueryPrepare=true;
    for (i=0; i<nAtoms(); i++) { //isotops change
      if ((getAtom(i)->na==104) && (! fIOPT11)) getAtom(i)->na=1;
      if (! fIOPT11) getAtom(i)->iz=0;
    };

    //Initializinf arrays
    neighbourlist *queryBK=(neighbourlist *)calloc(listarSize(),sizeof(adjustedlist));
    queryQHydr.resize(listarSize());
    queryAGer.resize(listarSize());
    queryAQTested.resize(listarSize());
    queryBQTested.resize(listarSize());
    queryBQCounter.resize(listarSize());
    queryCurrentAssignment.resize(listarSize());
    aSTested.resize(listarSize());
    bSTested.resize(listarSize());
    bSTestedStore.resize(listarSize());
    //initializing
    for (i=0; i<listarSize(); i++) {
      queryBK[i].nb=0;
      queryQHydr[i]=0;
      queryAGer[i]=-1;
      queryAQTested[i]=-1;
      queryBQTested[i]=-1;
      queryBQCounter[i]=-1;
      queryCurrentAssignment[i]=-1;
      aSTested[i]=-1;
      bSTested[i]=-1;
      bSTestedStore[i]=-1;
    };
    queryEnum.resize(sMol.nAtoms());
    queryInverse.resize(sMol.nAtoms());
    for (i=0; i<sMol.nAtoms(); i++) {
      queryEnum[i]=-1;
      queryInverse[i]=-1;
    };
    molecule1=new TEditedMolecule();

    //At this step memory was not allocated to: BK1,BEQ,AEQ. Realloction will be
    //required for three above temporary allocated arrays}
    removeHydrogen(&queryQHydr,nullptr);  //Connection is calculated inside RemoveHydr}
    if (fIOPT13) atomBondChange();  //semipolar bond conversion
    defineBondConn(queryBK);
    //initial values
    for (i=0; i<nAtoms(); i++) aSTested[i]=getAtom(i)->special;
    l=1;
    if (nAtoms()>2) {
      j=queryBK[0].nb;
      for (i=1; i<nAtoms(); i++) {
        //search for maximally coordinated non-carbon
        k=queryBK[i].nb;
        test1=k>j;
        test2=(getAtom(l)->na<104) && (getAtom(l)->na!=6);
        test3=(getAtom(i)->na<104) && (getAtom(i)->na!=6);
        if ((test1 && (! test2)) || (test3 && (! test2))
            || (test1 && test2 && test3)) {
          j=k; l=i;
        };
      };
    };

    queryAQTested[0]=0; //Sequence for query assignment begin from the atom
    aQ1=0; bNQ=-1; test=true;
    if (nBonds()>0) while (test) {  //Define sequence to match query and structure
        i=0;
        whileCondition=true;
        while (whileCondition) {
          test=(queryAQTested[i] != -1);
          if (test) {
            j=0;
            whileCondition1=true;
            if (queryBK[i].nb>0) while (whileCondition1) {
                k=queryBK[i].adjusted[j];
                j++;
                test=(bSTested[k]==-1);
                whileCondition1=test || (j>=queryBK[i].nb);
                whileCondition1=! whileCondition1;
              };
            if (queryBK[i].nb==0) test=false;
          };
          i++;
          whileCondition=test || (i==nAtoms());
          whileCondition=! whileCondition;
        };
        if (test) { //connected atom found
          i--;  //zero-index
          aQ2=i;
          whileCondition=true;
          while (whileCondition) {
            j=0;
            //search for query bond appended to AQ2, which has not been assigned yet
            whileCondition1=true;
            k=0;
            test1=true;
            if (queryBK[aQ2].nb>0) while (whileCondition1) {
                k=queryBK[aQ2].adjusted[j];
                test1=(bSTested[k]==-1);
                j++;
                whileCondition1=test1 || (j>=queryBK[aQ2].nb);
                whileCondition1=! whileCondition1;
              } else {
              k=0;
              test1=false;
            };
            if (test1)  {  //found
              bNQ++; bSTested[k]=bNQ; //store, that BNQ has been assigned
              l=getBond(k)->at[1];
              //atoms enumeration
              if (l==aQ2) {
                l=getBond(k)->at[0];
                getBond(k)->at[1]=l;
                getBond(k)->at[0]=aQ2;
              };
              test1=(queryAQTested[l]==-1);
              //Make AGER array for end-of cycle BNQ bond}
              if (test1) {
                queryAGer[bNQ]=l;
                aQ1=aQ1+1;
                queryAQTested[l]=aQ1;
                aQ2=l;
              } else aQ2=-1;
            };
            whileCondition=(! test1) || (aQ2==-1);
            whileCondition=! whileCondition;
          };
        };
      };
    //Detection of unconnected fragment}
    for (i=0; i<nAtoms(); i++) if (queryAQTested[i]==-1) result=-2;
    if (result>=0) {
      //Creation of inverse enumeration
      queryInverse.resize(queryAQTested.size());
      for (j=0; j<queryInverse.size(); j++) queryInverse[j]=queryAQTested[j];
      //Enumeration of atoms and bonds in query in order of assignment}
      molecule1->moleculeCopy(*this);
      for (i=0; i<nAtoms(); i++) molecule1->getAtom(queryAQTested[i])->atomCopy(this->getAtom(i));
      for (i=0; i<nAtoms(); i++) queryBQTested[queryAQTested[i]]=queryQHydr[i];
      for (i=0; i<queryQHydr.size(); i++) queryQHydr[i]=queryBQTested[i];
      //Do NOT enumeate QueryEnum - it will be done later throgh QueryInverse!!!}
      if (nBonds()>0) for (i=0; i<nBonds(); i++) if (queryAGer[i] != -1) queryAGer[i]=queryAQTested[queryAGer[i]];
      if (nBonds()>0) for (i=0; i<nBonds(); i++) molecule1->getBond(bSTested[i])->bondCopy(this->getBond(i));
      bSTestedStore.resize(bSTested.size());
      for (i=0; i<bSTestedStore.size(); i++) bSTestedStore[i]=bSTested[i];
      if (nBonds()>0) for (i=0; i<nBonds(); i++) {
          molecule1->getBond(i)->at[0]=queryAQTested[molecule1->getBond(i)->at[0]];
          molecule1->getBond(i)->at[1]=queryAQTested[molecule1->getBond(i)->at[1]];
        };
      //Enumeration of
      this->moleculeCopy(*molecule1);
      defineAtomConn();
      //Store NO OTHER atom attribute
      for (i=0; i<nAtoms(); i++) getAtom(queryAQTested[i])->special=aSTested[i];
      defineBondConn(queryBK);
      j=0;
      //Search for last non-special atom in query}
      queryStereoQ=stereoBondChange(); //Stereo bond conversion
    };
    delete(molecule1);
    free(queryBK);
    return result;
  };


  void TEditedMolecule::removeHydrogen(std::vector<int> * qHydr, std::vector<int> * qEnumerator) {

    //Explicitly-defined hydrogens are removed from the structure, which is characte-
    //rized of total number of atoms NA, total number of bonds NB, atom's attribute
    //array ATOM, bond's attribute array BOND, bond-connection matrix invariants
    //ONN. Number of explicitly-defined hydrogens for each atom are stored in
    //QHYDR. If QUERYLABEL points on some atom, the value is recalculated so that
    //the same atom is pointed after hydrogens have been removed from the structure

    //NB! QueryLabel should be array!}
    int i,j,i1;
    bool test,test1,test2;

    if (qEnumerator != nullptr) {
      if (qEnumerator->size() != nAtoms()) qEnumerator->resize(nAtoms());
      for (i=0; i<qEnumerator->size(); i++) (*qEnumerator)[i]=i;
    };
    for (i=0; i<nAtoms(); i++) {
      if (qHydr != nullptr) (*qHydr)[i]=0;
      if ((! fIOPT11) && (getAtom(i)->na==104)) getAtom(i)->na=1;
      //D->H if no isotop sensitivity}
    };
    i=0;
    test1=false;
    if (nAtoms()>0) while (i<nAtoms()) {
        if (getAtom(i)->na==1) { //hydrogen found
          test1=true; j=0; i1=0; test2=true;
          if (nBonds()>0) while (test2) { //search for corresponding bond and hydrogen's neighbour detection
              test=(getBond(j)->at[0]==i) || (getBond(j)->at[1]==i);
              if (test) {
                i1=getBond(j)->at[0];
                if (i1==i) i1=getBond(j)->at[1];
              };
              test2=test || (j==nBonds());
              test2=! test1;
              j++;
            };

          deleteAtom(i);
          if (qHydr != nullptr && i < nAtoms() - 1) deleteIntElement(qHydr,i);

          if (i1>i)  i1=i1-1;
          //shift of attribute's arrays
          if (qEnumerator != nullptr) {
            for (j=0; j<qEnumerator->size(); j++) {
              if ((*qEnumerator)[j] == i) (*qEnumerator)[j]=-i1; else
                if ((*qEnumerator)[j] > i)  (*qEnumerator)[j]=(*qEnumerator)[j]-1; else
                  if (((*qEnumerator)[j] < 0) && (abs((*qEnumerator)[j]) > i)) (*qEnumerator)[j]=(*qEnumerator)[j]+1;
            };
          };
          if (i1 > 0 && qHydr != nullptr) (*qHydr)[i1]=(*qHydr)[i1]+1;
          //counter of explicitly defined hydrogens
          i--;
        };
        i++;
      };
    if (test1) {
      defineAtomConn();
      //Inverse enumerator creation... New QA->OldQA array}
      if (qEnumerator != nullptr) {
        //??? Is it required ?}
      };
    };
  };

  void TEditedMolecule::atomBondChange() {
    //substitutes the semipolar bond with double. NBONDS-total number of bonds,
    //BOND-bond's attributes, ATOM-atom's attributes}
    int i;
    int ca,cb;

    if (nBonds()==0) return;
    for (i=0; i<nBonds(); i++) {
      ca=getAtom(getBond(i)->at[0])->nc;
      cb=getAtom(getBond(i)->at[1])->nc;
      if ((((ca<0) && (cb>0)) || ((ca>0) && (cb<0))) && ((getBond(i)->tb<3) || (getBond(i)->tb>8))) {
        if (ca<0) {
          getAtom(getBond(i)->at[0])->nc=ca+1;
          getAtom(getBond(i)->at[1])->nc=cb-1;
        };
        if (ca>0) {
          getAtom(getBond(i)->at[0])->nc=ca-1;
          getAtom(getBond(i)->at[1])->nc=cb+1;
        };
        if (getBond(i)->tb<3) getBond(i)->tb=getBond(i)->tb+1; else getBond(i)->tb=2;
      };
    };
  };

  bool TEditedMolecule::stereoBondChange() {
    //Subtitute stereo bonds with single. On output TEST has TRUE value, if at
    //least one stereo bond was detected in structure with bond attributes BOND
    //nd total number of bonds NBONDS
    int i;
    bool result;

    result=false;
    if ((nBonds()==0) || (fIOPT12==2)) return result;
    //If Exact Stereo Search-no substitution
    for (i=0; i<nBonds(); i++)  {
      if (fIOPT12==3) {
        //If Replace Stereo Search-only EITHER bond substitution}
        if (getBond(i)->tb==11) getBond(i)->tb=1;
        if (getBond(i)->tb>=9) result=true;
      };
      if (fIOPT12==1) if (getBond(i)->tb>=9) getBond(i)->tb=1;
      //If No Stereo search-all bonds substitution
    };
    return result;
  };

  void TEditedMolecule::directBondAss(int& bnq, bool& test, bool& test1, bool const* const* beq,
                                      bool const* const* aeq, std::vector<int>& bqcounter, std::vector<int>& aqtested,
                                      std::vector<int>& bstested, std::vector<int>& bqtested, std::vector<int>& astested,
                                      const std::vector<int> ager, const neighbourlist *bsconn, TSimpleMolecule * smol) {
    //Assign a structure atom to query atom. Variables:
    //BNQ-query bond's number, which needs to be assigned
    //BEQ,AEQ-boolean matrix, contains list of equivalent bonds
    //BSCONN-for each atom containes list of connected bonds in structure
    //QBOND,SBOND-bond's attributes for query and structure respectively
    //ASTESTED- I-th element of the array contains the query atom's number, which
    //          has been assigned to I-th atom of structure (=0-no assignment)
    //AQTESTED- I-th element of the array contains the structure atom's number,
    //          which has been assigned to I-th atom of query (=0-no assignment)
    //BSTESTED- I-th element of the array contains the query bond's number, which
    //          has been assigned to I-th bond of structure (=0-no assignment)
    //BQTESTED- I-th element of the array contains the structure bond's number,
    //          which has been assigned to I-th bond of query (=0-no assignment)
    //BQCOUNTER-for each query bond contains bond's number in array BSCONN(!)-con-
    //          nected to corresponding structure atom bonds. The structure bonds
    //          in array BSCONN with less than or equal number have been tested on
    //          assignment, with above number-no.
    //AGER-for each query bond contains query atom's number, which must be generated
    //     at assignment of this bond to structure or zero, if no atom may be gene-
    //     rated. This array is used for cyclic conditions definition (last bond in
    //     the cycle must be created between already-defined query atoms-no genera-
    //     tion).
    //TEST-on output contains TRUE, if assignment was successful, FALSE otherwise
    //TEST1-on output contains TRUE if all bonds, connected to last assigned atom
    //      in structure will be tested, FALSE otherwise. If TEST1=TRUE and TEST=
    //      FALSE it means, that last atom in structure had been unproperly assigned
    //      -backstep is required to reassign the atom.*/
    int bns,bs,as1,as2,aq2,aq1;
    bool whiletest;

    test=false;
    aq1=getBond(bnq)->at[0];      //first query atom, already assigned
    as1=aqtested[aq1];  //corresponding first structure atom
    if (as1<0) return;
    aq2=getBond(bnq)->at[1];      //second query atom}
    bs=bqcounter[bnq];
    bns=0; as2=0;
    whiletest=true;
    if (bs<bsconn[as1].nb) while (whiletest) {
        bns=bsconn[as1].adjusted[bs];  //structure bond, assigned to query BNQ}
        //if structure bond hasn't already been assigned, and query and structure
        //bonds are equivalent, then...
        if (bstested[bns]<0) if (beq[bns][bnq]) {
            as2=smol->getBond(bns)->at[0];                  //second structure atom}
            if (as2==as1) as2=smol->getBond(bns)->at[1];
            test=false;
            //if no new structure atom assignment must be generated-checking, if AS2
            // equal already defined atom for query atom AQ2}
            if ((ager[bnq]<0) && (astested[as2]>=0)) test=(aqtested[aq2]==as2);
            //if new atom in structure must be assigned-testing equivalence with
            //corresponding query
            if ((ager[bnq]>=0) && (astested[as2]<0)) test=aeq[as2][aq2];
          };
        bs=bs+1;
        whiletest=(bs==bsconn[as1].nb) || test;
        whiletest=! whiletest;
      }; //until(BS=BSCONN[AS1].NB) or TEST;
    //until all list of structure bonds will be exausted or success in assignment
    if (test) { //Success
      if (ager[bnq]>=0) {    //if new atom has been assigned-store assignment}
        aqtested[aq2]=as2; astested[as2]=aq2;
      };
      bstested[bns]=bnq; //store assignment of bonds}
      bqtested[bnq]=bns;
    };
    bqcounter[bnq]=bs;    //last used structure bond's number in SCONN array}
    test1=(bs==bsconn[as1].nb); //test, if SCONN for atom given is exausted}
  };

  bool TEditedMolecule::allQueryPresent(const std::vector<int> qA, const std::vector<int> qB,
                                        int nA, int nB) {
    //the function returns TRUE if for all query atoms and bonds the equivalent
    //structure atom (bond) can be found, FALSE otherwise. QA-for each query atom
    //contains '1' if a structure atom may be associated with the query, '0' other-
    //wise. The same is true for bond's list QB. NA-total number of query atoms,
    //NB-total number of query bonds
    int i;
    bool test,whiletest;

    i=0;
    if (nA<0) return false;
    whiletest=true;
    test=false;
    while (whiletest) {
      test=qA[i]==1;
      i++;
      whiletest=(! test) || (i==nA);
      whiletest=! whiletest;
    };
    if (test && (nB>=0)) {
      i=0;
      whiletest=false;
      while (whiletest) {
        test=qB[i]==1;
        i++;
        whiletest=(! test) || (i==nB);
        whiletest=! whiletest;
      };
    };
    return test;
  };

  bool TEditedMolecule::fragmentSearch(TEditedMolecule * molecule1, std::vector<int>* bondLabel) {
    int cycleNumber;
    int j,k,l,m,mm;
    bool test;
    bool test1;
    bool test2,test3;
    int aq1,aq2,as1,as2,j1,i1;
    int ii;
    bool result=false;
    bool whiletest1,whiletest2;

    if (molecule1 == nullptr || !fIsQueryPrepare) return result;
    if (molecule1->nAtoms()==0) return result;

    if (molecule1->listarSize()>aSTested.size()) aSTested.resize(molecule1->listarSize());
    if (molecule1->listarSize()>bSTested.size()) bSTested.resize(molecule1->listarSize());
    if (molecule1->listarSize()>queryQHydr.size()) queryQHydr.resize(molecule1->listarSize());
    if (molecule1->listarSize()>queryAQTested.size()) queryAQTested.resize(molecule1->listarSize());
    if (molecule1->listarSize()>queryBQTested.size()) queryBQTested.resize(molecule1->listarSize());
    if (molecule1->listarSize()>queryCurrentAssignment.size()) queryCurrentAssignment.resize(molecule1->listarSize());
    if (this->listarSize()>queryAQTested.size()) queryAQTested.resize(this->listarSize());

    // Initialise aEQ, a 2D bool matrix of size [molecule1->nAtoms()][nAtoms()] and set all to false
    bool **aEQ = (bool **)calloc(molecule1->nAtoms(),sizeof(bool *));
    for (int i=0; i<molecule1->nAtoms(); ++i) {
      aEQ[i] = (bool *)calloc(nAtoms(),sizeof(bool ));
    }
    // Initialise bEQ, a 2D bool matrix of size [molecule1->nBonds()][nBonds()] and set all to false
    bool **bEQ = (bool **)calloc(molecule1->nBonds(),sizeof(bool *));
    for (int i=0; i<molecule1->nBonds(); ++i) {
      bEQ[i] = (bool *)calloc(nBonds(),sizeof(bool ));
    }

    cycleNumber=0;

    molecule1->fIOPT11=fIOPT11;
    molecule1->fIOPT12=fIOPT13;
    molecule1->fIOPT13=fIOPT13;
    test2 = true;

    //{R/S/Z/E description are removed: they are not used in substructure search}
    if (fIOPT13) molecule1->atomBondChange(); //Semipolar bond conversion
    molecule1->defineAtomConn();
    neighbourlist *structureBK = (neighbourlist *)calloc(molecule1->nAtoms(), sizeof(adjustedlist));
    molecule1->defineBondConn(structureBK);
    // GRH: 2011-10-15 unused via clang static analyzer
    // stereoS=molecule1->stereoBondChange(); //Stereo bond conversion}
    for (j=0; j<molecule1->nAtoms(); j++) {
      //Isotops conversion}
      if ((molecule1->getAtom(j)->na==104) && (! fIOPT11)) molecule1->getAtom(j)->na=1;
      if (! fIOPT11) molecule1->getAtom(j)->iz=0;
      bSTested[j]=0;  //bsTested contains nu. explicit hydrogens - so 0 is fine!
    };
    for (j=0; j<molecule1->nAtoms(); j++) if (molecule1->getAtom(j)->na==1)
                                            if (molecule1->getAtom(j)->nb>0) for (k=0; k<molecule1->getAtom(j)->nb; k++) {
                                                //Formation of list explicitly-defined hydrogens}
                                                l=molecule1->getAtom(j)->ac[k];
                                                bSTested[l]=bSTested[l]+1;
                                              };
    for (k=0; k<nAtoms(); k++) aSTested[k]=-1;
    if (nAtoms()==1) {
      //Partial case - if single atom was defined}
      test2=false;
      j=0;
      whiletest1=true;
      if (molecule1->nAtoms()>0) while (whiletest1) {
          test2=TSingleAtom::atomEquivalent(molecule1->getAtom(j),getAtom(0),bSTested[j],queryQHydr[0],fIOPT10,fIOPT11);
          //Addition for aromatic search}
          if (test2 && ((getAtom(0)->special & AROMATIC_MASK)!=0) ){
            test2=false;
            for (m=0; m<=structureBK[j].nb; m++) {
              mm=structureBK[j].adjusted[m];
              if ((molecule1->getBond(mm)->db==2) || (molecule1->getBond(mm)->db==3)) {
                test2=true;
                break;
              };
            };
          };
          //End addition}
          if (test2) {
            if (queryEnum.size()<1) queryEnum.resize(1);
            queryEnum[0]=0;
            if (queryAQTested.size()<1) queryAQTested.resize(1);
            queryAQTested[0]=j;
          };
          j++;
          whiletest1=test2 || (j==molecule1->nAtoms());
          whiletest1=! whiletest1;
        };
    } else if (nBonds()==0) test2=false; else {
      //General case - substructure search
      if (fIncludedList != nullptr) {
        for (j=0; j<molecule1->nAtoms(); j++) for (k=0; k<nAtoms(); k++) aEQ[j][k]=false;
        for (k=0; k<nAtoms(); k++) {
          j=(*fIncludedList)[k];
          aEQ[j][k]=true;
          aSTested[k]=1;
        };
      } else {
        for (j=0; j<molecule1->nAtoms(); j++) for (k=0; k<nAtoms(); k++) {
            //Creation of atom-equivalent matrix}

            test3=(TSingleAtom::atomEquivalent(molecule1->getAtom(j),getAtom(k),bSTested[j],
                                               queryQHydr[k],fIOPT10,fIOPT11) && (getAtom(k)->nb<=molecule1->getAtom(j)->nb));

            //Addition for aromatic search
            if (test3 && ((getAtom(k)->special & AROMATIC_MASK) !=0)) {
              test3=false;
              for (m=0; m<structureBK[j].nb; m++) {
                mm=structureBK[j].adjusted[m];
                if ((molecule1->getBond(mm)->db==2) || (molecule1->getBond(mm)->db==3)) {
                  test3=true;
                  break;
                };
              };
            };
            aEQ[j][k]=test3;
            if (test3) aSTested[k]=1;
          };
      };

      for (j=0; j<nBonds(); j++) queryAQTested[j]=0;
      for (j=0; j<molecule1->nBonds(); j++) for (k=0; k<nBonds(); k++) {
          //Creation of bond-equivalent matrix
          aq1=getBond(k)->at[0];   aq2=getBond(k)->at[1];
          as1=molecule1->getBond(j)->at[0]; as2=molecule1->getBond(j)->at[1];
          test2=(aEQ[as1][aq1] && aEQ[as2][aq2]) || (aEQ[as1][aq2] && aEQ[as2][aq1]);
          if (test2) {
            test3=TSingleBond::bondEquivalent(molecule1->getBond(j),getBond(k));
            bEQ[j][k]=test3;
            if (test3) queryAQTested[k]=1;
          } else bEQ[j][k]=false;
        };
      //Check, if all query atoms has a partner in structure
      test2=allQueryPresent(aSTested,queryAQTested,nAtoms(),nBonds());
      if (test2) {
        j1=0;
        for (k=1; k<molecule1->nAtoms(); k++) if (aEQ[k][0]) {
            //Collection of structure atoms, which may be associated with first query atom
            j=0;
            whiletest1=true;
            while (whiletest1) {
              test=bEQ[structureBK[k].adjusted[j]][0];
              if (test) {
                queryCurrentAssignment[j1]=k;
                j1++;
              };
              j++;
              whiletest1=test || (j==structureBK[k].nb);
              whiletest1=! whiletest1;
            };
          };
        i1=0;
        whiletest1=true;
        if (j1>0) while (whiletest1) { //for each structure, which may be assigned to 1-st query
            for (j=0; j<nAtoms(); j++) queryAQTested[j]=-1; //array initializing
            for (j=0; j<nBonds(); j++) queryBQCounter[j]=0;
            for (j=0; j<nBonds(); j++) queryBQTested[j]=-1;
            for (j=0; j<molecule1->nBonds(); j++) bSTested[j]=-1;
            for (j=0; j<molecule1->nAtoms(); j++) aSTested[j]=-1;
            queryAQTested[0]=queryCurrentAssignment[i1];
            aSTested[queryCurrentAssignment[i1]]=0;
            ii=0;
            whiletest2=true;
            while (whiletest2) { //start recursion
              directBondAss(ii,test,test1,bEQ,aEQ,queryBQCounter,queryAQTested,bSTested,
                            queryBQTested,aSTested,queryAGer,structureBK,molecule1);
              if ((! test) && (ii>=1)) {
                //previous atom were badly assigned-backstep
                queryBQCounter[ii]=0;
                k=queryAGer[ii-1];
                if (k>=0) {
                  l=queryAQTested[k]; queryAQTested[k]=-1; aSTested[l]=-1;
                };
                bSTested[queryBQTested[ii-1]]=-1;
                queryBQTested[ii-1]=-1;
                ii=ii-2;
                test=true;
              };
              ii=ii+1; //query bond counter
              whiletest2=(ii==nBonds()) || ((! test) && (ii==1));
              whiletest2=! whiletest2;
            };
            i1++;
            test2=(ii==nBonds()); //Checking, if success has been reached
            whiletest1=((j1==i1) || test2);
            whiletest1=! whiletest1;
          } else test2=false;
      };
    };

    if (bondLabel != nullptr && nBonds() > 0) {
      bondLabel->resize(molecule1->nBonds());
      if (test2) for (j=0; j<molecule1->nBonds(); j++) if (bSTested[j]>=0) (*bondLabel)[j]=1; else (*bondLabel)[j]=0;
    };
    result=test2;

    // Tidy up
    free(structureBK);
    for (int i=0; i<molecule1->nAtoms(); ++i)
      free(aEQ[i]);
    free(aEQ);
    for (int i=0; i<molecule1->nBonds(); ++i)
      free(bEQ[i]);
    free(bEQ);


    return result;
  };
  //***************************************************************************
  //                   Diagram generation routines
  //***************************************************************************
  class PartFragmentDefinition {
  public:
    int fragID1,fragID2,fragID3,fragFirstAtomNo;
    int fragmentCount;
    double fragWidth,fragHeight,fragTop,fragLeft;

    PartFragmentDefinition(){
    };
    void assign(const PartFragmentDefinition source) {
      fragID1=source.fragID1;
      fragID2=source.fragID2;
      fragID3=source.fragID3;
      fragFirstAtomNo=source.fragFirstAtomNo;
      fragmentCount=source.fragmentCount;
      fragWidth=source.fragWidth;
      fragHeight=source.fragHeight;
      fragTop=source.fragTop;
      fragLeft=source.fragLeft;
    };
  };



  class  TemplateRedraw  {
  public:
    TemplateRedraw();
    bool isOverlapped(const std::vector<PartFragmentDefinition *> list, int fragNo, double xSuggested, double ySuggested);
    void arrangeFragments(std::vector<PartFragmentDefinition *>& list, int fragNo, double aspOptimal);
    void redrawFine(TSimpleMolecule& smIn);
    int  coordinatesPrepare(TEditedMolecule& sm, int kk, int anTemplateNo);
  private:
    // Cache of query templates, loaded once on first construction and
    // shared across all instances. Owned via unique_ptr so static
    // destruction at program exit frees them (the previous raw-pointer
    // vector leaked the entries — destructor was disabled because every
    // stack-allocated TemplateRedraw would otherwise wipe the cache).
    static std::vector<std::unique_ptr<TEditedMolecule>> queryData;
    bool internalBondsPresent(TEditedMolecule * mQuery, TSimpleMolecule * mStructure);
    void rotateBondVertically(TSimpleMolecule * sm, const std::vector<int>bondList, int bondNo,
                              double xuValue, double yuValue, double& c1, double& s1, double& xSize, double& ySize,
                              double& xCenter, double& yCenter, int& nVert);
    void selectFragmentConfiguration(TSimpleMolecule * sm, std::vector<int>* atomList);
    void rescaleSingleFragment(TSimpleMolecule * sm, std::vector<int>* atomList, PartFragmentDefinition& pf, double offset);
    void arrangeMolecules(std::vector<PartFragmentDefinition *>& extendedList, double aspOptimal);
    bool loadTemplates();
  };

  //Initialization of static member variable
  std::vector<std::unique_ptr<TEditedMolecule>> TemplateRedraw::queryData;

  bool TemplateRedraw::loadTemplates() {
    std::ifstream ifs;
    string filename("templates.sdf");//("e:\\templates.sdf");
    TEditedMolecule sm;
    TEditedMolecule * em;
    int i,na1,na2;
    bool test;
    bool result=false;

    try {
      OpenDatafile(ifs, filename);
    } catch (exception &ex) {
      return result;
    };

    //Read into a vector of OBMol
    if (ifs) {
      OBConversion conv(&ifs);
      conv.SetInFormat("sdf");

      OBMol mol;
      mol.SetIsPatternStructure();
      while (conv.Read(&mol)) {
        sm.readOBMol(&mol);
        mol.Clear();
        for (i=0; i<sm.nAtoms(); i++) {
          if (sm.getAtom(i)->na != 1) sm.getAtom(i)->na=ANY_ATOM;
          sm.getAtom(i)->nc=0;
        }
        for (i=0; i<sm.nBonds(); i++) {
          na1=sm.getBond(i)->at[0];
          na2=sm.getBond(i)->at[1];
          test=((sm.getAtom(na1)->na != 1) && (sm.getAtom(na2)->na != 1));
          if (test) sm.getBond(i)->tb=ANY_BOND;  //ANY bons
        }
        sm.defineAtomConn();
        sm.allAboutCycles();
        em=new TEditedMolecule();
        em->prepareQuery(sm);
        queryData.emplace_back(em);
      }
      result=true;
      obErrorLog.ThrowError(__FUNCTION__, "Read OK " + filename, obInfo);
    }
    // else {obErrorLog.ThrowError(__FUNCTION__, "Cannot find " + filename, obWarning);}
    return result;
  };


  TemplateRedraw::TemplateRedraw(){
    if(queryData.empty()) //Load internal and external templates only once
      {
        unsigned int i, j;
        TEditedMolecule * em;
        TEditedMolecule * em1;
        TEditedMolecule * em2;
        TEditedMolecule sm;
        bool test;

        //Load external..
        loadTemplates();
        //...and internal templates
        for (i=0; i<NDATABASE_MOLECULES; i++) {
          sm.setCoordinatesString(strData[i]);
          sm.defineAtomConn();
          sm.allAboutCycles();
          em=new TEditedMolecule();
          em->prepareQuery(sm);
          queryData.emplace_back(em);
        }
        if (queryData.size()>1) for (i=0; i<(queryData.size()-1); i++) for (j=i+1; j<queryData.size(); j++) {
              test=false;
              em1=queryData[i].get();
              em2=queryData[j].get();
              if (em1->nAtoms() < em2->nAtoms()) test=true; else
                if (em1->nAtoms() > em2->nAtoms()) test=false; else
                  if (em1->nBonds() < em2->nBonds()) test=true;

              if (test) {
                std::swap(queryData[i], queryData[j]);
              }
            }
      }
  }


  bool TemplateRedraw::internalBondsPresent(TEditedMolecule * mQuery, TSimpleMolecule * mStructure) {
    std::vector<int> aList(mStructure->nAtoms());
    std::vector<int> bList(mStructure->nBonds());
    unsigned int i, n1, n2;
    bool result=false;

    for (i=0; i<aList.size(); i++) aList[i]=0;
    for (i=0; i<bList.size(); i++) bList[i]=0;
    for (i=0; i<mQuery->nAtoms(); i++) aList[mQuery->queryAQTested[i]]=1;
    for (i=0; i<mQuery->nBonds(); i++) bList[mQuery->queryBQTested[i]]=1;
    for (i=0; i<bList.size(); i++) if (bList[i] == 0) {
        n1=mStructure->getBond(i)->at[0];
        n2=mStructure->getBond(i)->at[1];
        if ((aList[n1] == 1) && (aList[n2] == 1)) result=true;
        if (result) break;
      };
    //seek for 3-attached atom
    return result;
  };

  void TemplateRedraw::rotateBondVertically(TSimpleMolecule * sm, const std::vector<int>bondList, int bondNo, double xuValue, double yuValue, double& c1, double& s1, double& xSize, double& ySize, double& xCenter, double& yCenter, int& nVert) {
    //Dummy rotation of molecule
    //Two solution - when c2,s2 are used - are determined for cases of rotaition when Up and Down are counterchnged. Single solution would be enough
    std::vector<bool> atomList(sm->nAtoms(), false);
    int i,n,n1,n2;
    bool test;
    double rX,rY,r;
    std::vector<double> coorX(sm->nAtoms());
    std::vector<double> coorY(sm->nAtoms());
    double xMin,xMax,yMin,yMax;



    xSize=0;
    ySize=0;
    c1=1; s1=0;
    xCenter=0; yCenter=0;
    nVert=0;
    test=false;
    for (i=0; i<bondList.size(); i++) {
      n=bondList[i];
      if (n==bondNo) test=true;
      n1=sm->getBond(n)->at[0];
      n2=sm->getBond(n)->at[1];
      atomList[n1]=true;
      atomList[n2]=true;
    };
    if (! test) return;  //bond is absent in the list....
    n1=sm->getBond(bondNo)->at[0];
    n2=sm->getBond(bondNo)->at[1];
    xCenter=sm->getAtom(n2)->rx;
    yCenter=sm->getAtom(n2)->ry;
    rX=sm->getAtom(n1)->rx-xCenter;
    rY=sm->getAtom(n1)->ry-yCenter;
    r=sqrt(rX*rX+rY*rY);
    if (r != 0) {
      rX=rX/r; rY=rY/r;
      if (abs(rX) < 0.00001) {
        s1=xuValue/rY;
        c1=-yuValue/rY;
      } else if (abs(rY) < 0.00001) {
        s1=yuValue/rX;
        c1=xuValue/rX;
      } else {
        s1=(xuValue/rX+yuValue/rY)/(rY/rX+rX/rY);
        c1=(xuValue/rY-yuValue/rX)/(rY/rX+rX/rY);
      };
    };
    //c1, s1 analizing
    for (i=0; i<sm->nAtoms(); i++) {
      coorX[i]=c1*(sm->getAtom(i)->rx-xCenter)+s1*(sm->getAtom(i)->ry-yCenter);
      coorY[i]=s1*(sm->getAtom(i)->rx-xCenter)-c1*(sm->getAtom(i)->ry-yCenter);
    };
    xMin=RUNDEF; xMax=RUNDEF;
    yMin=RUNDEF; yMax=RUNDEF;
    for (i=0; i<sm->nAtoms(); i++) if (atomList[i]) {
        if ((coorX[i] < xMin) || (xMin == RUNDEF)) xMin=coorX[i];
        if ((coorX[i] > xMax) || (xMax == RUNDEF)) xMax=coorX[i];
        if ((coorY[i] < yMin) || (yMin == RUNDEF)) yMin=coorY[i];
        if ((coorY[i] > yMax) || (yMax == RUNDEF)) yMax=coorY[i];
      };
    xSize=xMax-xMin;
    ySize=yMax-yMin;
    //calculation no. vertical bonds...
    for (i=0; i<bondList.size(); i++) {
      n=bondList[i];
      n1=sm->getBond(n)->at[0];
      n2=sm->getBond(n)->at[1];
      //no. vert. bonds
      r=coorY[n1]-coorY[n2];
      if (abs(r) > 0) {
        r=abs((coorX[n1]-coorX[n2])/r);
        if (r < 0.02) nVert++;
      };
    };
  };

  void TemplateRedraw::selectFragmentConfiguration(TSimpleMolecule * sm, std::vector<int>* atomList) {
    //for each fragment in AtomList select optimal angle of rotation
    double xMax;
    double xSize;
    double ySize;
    double xCenter;
    double yCenter;
    double c;
    double s;
    int nVert;
    double cMax,sMax,x,y;
    std::vector<int> bondList(0);
    std::vector<int> bondListAll(0);
    std::vector<bool> atomCleaned(sm->nAtoms());
    int i,j,n,n1,n2,w;
    bool test;

    if (atomList == nullptr) {
      for (i=0; i<sm->nAtoms(); i++) atomCleaned[i]=true;
    } else {
      for (i=0; i<sm->nAtoms(); i++) atomCleaned[i]=false;
      for (i=0; i<atomList->size(); i++) {
        n=(*atomList)[i];
        atomCleaned[n]=true;
      };
    };
    //bondList generation...
    for (i=0; i<sm->nBonds(); i++) {
      n1=sm->getBond(i)->at[0];
      n2=sm->getBond(i)->at[1];
      if (atomCleaned[n1] && atomCleaned[n2]) {
        w=i;
        bondListAll.push_back(w);
        if (sm->getBond(i)->db > 1) bondList.push_back(w); //only ring bonds...
      };
    };
    if (bondList.size() == 0) {
      bondList.resize(bondListAll.size());
      for (i=0; i<bondListAll.size(); i++) bondList[i]=bondListAll[i];
    };
    if (bondList.size() > 0) {
      //search for 4-coordinater non-carbon
      test=false;
      n=-1;
      for (i=0; i<sm->nAtoms(); i++) if (atomCleaned[i] && (sm->getAtom(i)->na != 6) && (sm->getAtom(i)->nb == 4)) {
          test=true;
          for (j=0; j<sm->nBonds(); j++) if ((sm->getBond(j)->at[0] == i) || (sm->getBond(j)->at[1] == i)) {
              n=j;
              if (sm->getBond(j)->db > 1) {
                n=-1;
                test=false;
                break;
              };
            };
          if (test) break;
        };
      if (! test) for (i=0; i<sm->nBonds(); i++) if (atomCleaned[sm->getBond(i)->at[0]] && (sm->getBond(i)->db == 5)) {
            n=i;
            test=true;
            break;
          };
      if (test) {
        rotateBondVertically(sm,bondListAll,n,1.0,0.0,c,s,xSize,ySize,xCenter,yCenter,nVert);
        if (ySize > xSize) rotateBondVertically(sm,bondListAll,n,0.0,1.0,c,s,xSize,ySize,xCenter,yCenter,nVert);
        cMax=c;
        sMax=s;
      } else {
        xMax=0; cMax=1; sMax=0;
        for (i=0; i<bondList.size(); i++) {
          n=bondList[i];
          rotateBondVertically(sm,bondList,n,sqrt(3.0)/2.0,0.5,c,s,xSize,ySize,xCenter,yCenter,nVert);
          xSize=xSize+nVert*xSize/10.0;  //5 vertical bonds=1 xSize
          if (xSize > xMax) {
            xMax=xSize;
            cMax=c;
            sMax=s;
          };
        };
        for (i=0; i<bondList.size(); i++) {
          n=bondList[i];
          rotateBondVertically(sm,bondList,n,1.0,0.0,c,s,xSize,ySize,xCenter,yCenter,nVert);
          xSize=xSize+nVert*xSize/10.0;  //5 vertical bonds=1 xSize
          if (xSize > xMax) {
            xMax=xSize;
            cMax=c;
            sMax=s;
          };
        };
      };
      //Rotation
      for (i=0; i<sm->nAtoms(); i++) if (atomCleaned[i]) {
          x=cMax*(sm->getAtom(i)->rx-xCenter)+sMax*(sm->getAtom(i)->ry-yCenter);
          y=sMax*(sm->getAtom(i)->rx-xCenter)-cMax*(sm->getAtom(i)->ry-yCenter);
          sm->getAtom(i)->rx=x;
          sm->getAtom(i)->ry=y;
        };
    };
  };

  void TemplateRedraw::rescaleSingleFragment(TSimpleMolecule * sm, std::vector<int>* atomList, PartFragmentDefinition& pf, double offset) {
    int i,n;
    double xMin,xMax,yMin,yMax;
    double scale,r1,r2;
    double x,y;

    xMin=RUNDEF;
    xMax=RUNDEF;
    yMin=RUNDEF;
    yMax=RUNDEF;
    for (i=0; i<atomList->size(); i++) {
      n=(*atomList)[i];
      if ((sm->getAtom(n)->rx < xMin) || (xMin == RUNDEF)) xMin=sm->getAtom(n)->rx;
      if ((sm->getAtom(n)->rx > xMax) || (xMax == RUNDEF)) xMax=sm->getAtom(n)->rx;
      if ((sm->getAtom(n)->ry < yMin) || (yMin == RUNDEF)) yMin=sm->getAtom(n)->ry;
      if ((sm->getAtom(n)->ry > yMax) || (yMax == RUNDEF)) yMax=sm->getAtom(n)->ry;
    };
    // LPW: Nearly horizontal molecules were being scaled which resulted in
    // some nonsensical structures.  This code ensures that coordinates with
    // "almost" horizontal or vertical geometries don't get scaled.
    bool Xeq = (fabs(xMax - xMin) < 0.01);
    bool Yeq = (fabs(yMax - yMin) < 0.01);
    if ((Xeq) && (Yeq)) {
      for (i=0; i<atomList->size(); i++) {
        n=(*atomList)[i];
        sm->getAtom(n)->rx=(pf.fragLeft+pf.fragWidth/2);
        sm->getAtom(n)->ry=(pf.fragTop+pf.fragHeight/2);
      };
      return;
    };
    if (Xeq) {         //y should be scaled
      scale=(pf.fragHeight-2*offset)/(yMax-yMin);
    } else if (Yeq) { //x should be scaled
      scale=(pf.fragWidth-2*offset)/(xMax-xMin);
    } else {
      r1=(pf.fragHeight-2*offset)/(yMax-yMin);
      r2=(pf.fragWidth-2*offset)/(xMax-xMin);
      if (r1 > r2) scale=r2; else scale=r1;
    };
    for (i=0; i<atomList->size(); i++) {
      n=(*atomList)[i];
      x=pf.fragLeft+offset+(sm->getAtom(n)->rx-xMin)*scale;
      y=pf.fragTop+offset+(sm->getAtom(n)->ry-yMin)*scale;
      sm->getAtom(n)->rx=x;
      sm->getAtom(n)->ry=y;
    };
  };


  bool ptInRect(const Rect r, const Point p) {
    bool result=((p.x >= r.left) & (p.x <= r.right) & (p.y >= r.top) & (p.y <= r.bottom));
    return result;
  }


  bool TemplateRedraw::isOverlapped(const std::vector<PartFragmentDefinition *> list, int fragNo, double xSuggested, double ySuggested) {
    //  !!! Zero-based fragno !!!
    //checking if recteangles are overlapped from different fagments.
    Rect rect;
    Point p;
    int i,j,n1,n2;
    PartFragmentDefinition * ef;
    PartFragmentDefinition * efTemp;
    bool test, result;

    result=false;
    ef=(PartFragmentDefinition *)list[fragNo];
    rect.left=xSuggested;
    rect.top=ySuggested;
    rect.right=rect.left+ef->fragWidth;
    rect.bottom=rect.top+ef->fragHeight;
    for (i=0; i<fragNo; i++) {
      efTemp=(PartFragmentDefinition *)list[i];
      test=((efTemp->fragLeft+efTemp->fragWidth) < rect.left);
      if (! test) test=((efTemp->fragTop+efTemp->fragHeight) < rect.top);
      if (! test) test=(efTemp->fragLeft > rect.right);
      if (! test) test=(efTemp->fragTop > rect.bottom);
      if (! test) {
        n1=(int)(efTemp->fragLeft);
        n2=(int)(efTemp->fragLeft+efTemp->fragWidth);
        for (j=n1; j<=n2; j++) {
          p.x=j;
          p.y=efTemp->fragTop;
          if (ptInRect(rect,p)) {
            result=true;
            return result;
          };
          p.x=j;
          p.y=efTemp->fragTop+efTemp->fragHeight;
          if (ptInRect(rect,p)) {
            result=true;
            return result;
          };
        };
        n1=(int)(efTemp->fragTop);
        n2=(int)(efTemp->fragTop+efTemp->fragHeight);
        for (j=n1; j<=n2; j++) {
          p.y=j;
          p.x=efTemp->fragLeft;
          if (ptInRect(rect,p)) {
            result=true;
            return result;
          };
          p.y=j;
          p.x=efTemp->fragLeft+efTemp->fragWidth;
          if (ptInRect(rect,p)) {
            result=true;
            return result;
          };
        };
      };
    };
    return result;
  };

  void TemplateRedraw::arrangeFragments(std::vector<PartFragmentDefinition *>& list, int fragNo, double aspOptimal) {
    //!! Frag no zero-based!
    double aspDelta,xNice,yNice,xMax,yMax,xMin,yMin,r,x,y,xNew,yNew;
    PartFragmentDefinition * ef;
    PartFragmentDefinition * efInterest;
    int i;

    ef=(PartFragmentDefinition *)list[0];
    xMax=ef->fragLeft+ef->fragWidth; yMax=ef->fragTop+ef->fragHeight;
    xMin=ef->fragLeft; yMin=ef->fragTop;
    //Calculate sizes....
    for (i=1; i<fragNo; i++) {
      ef=(PartFragmentDefinition*)list[i];
      r=ef->fragLeft+ef->fragWidth;
      if (r > xMax) xMax=r;
      r=ef->fragTop+ef->fragHeight;
      if (r > yMax) yMax=r;
      if (ef->fragTop < yMin) yMin=ef->fragTop;
      if (ef->fragLeft < xMin) xMin=ef->fragLeft;
    };
    aspDelta=1000000; xNice=0; yNice=0;
    efInterest=(PartFragmentDefinition *)list[fragNo];
    for (i=0; i<fragNo; i++) {
      ef=(PartFragmentDefinition *)list[i];
      //Insert right
      x=ef->fragLeft+ef->fragWidth+1;
      y=ef->fragTop;
      if (! isOverlapped(list,fragNo,x,y)) {
        if (((x+efInterest->fragWidth) <= xMax) && ((y+efInterest->fragHeight) <= yMax)) {
          efInterest->fragLeft=x; efInterest->fragTop=y;
          list[fragNo]=efInterest;
          return;
        };
        xNew=x+efInterest->fragWidth; if (xMax > xNew) xNew=xMax;
        yNew=y+efInterest->fragHeight; if (yMax > yNew) yNew=yMax;
        r=(yNew-yMin)/(xNew-xMin);
        if (abs(r-aspOptimal) < aspDelta) {
          xNice=x; yNice=y;
          aspDelta=abs(r-aspOptimal);
        };
      };
      x=ef->fragLeft;
      y=ef->fragTop+ef->fragHeight+1;
      if (! isOverlapped(list,fragNo,x,y)) {
        if (((x+efInterest->fragWidth) <= xMax) && ((y+efInterest->fragHeight) <= yMax)) {
          efInterest->fragLeft=x; efInterest->fragTop=y;
          list[fragNo]=efInterest;
          return;
        };
        xNew=x+efInterest->fragWidth; if (xMax > xNew) xNew=xMax;
        yNew=y+efInterest->fragHeight; if (yMax > yNew) yNew=yMax;
        r=(yNew-yMin)/(xNew-xMin);
        if (abs(r-aspOptimal) < aspDelta) {
          xNice=x; yNice=y;
          aspDelta=abs(r-aspOptimal);
        };
      };
    };
    //if here - maxX,0 and 0,MaxY have to be tested...
    x=xMax; y=0;
    xNew=x+efInterest->fragWidth; if (xMax > xNew) xNew=xMax;
    yNew=y+efInterest->fragHeight; if (yMax > yNew) yNew=yMax;
    r=(yNew-yMin)/(xNew-xMin);
    if (abs(r-aspOptimal) < aspDelta) {
      xNice=x; yNice=y;
      aspDelta=abs(r-aspOptimal);
    };
    x=0; y=yMax;
    xNew=x+efInterest->fragWidth; if (xMax > xNew) xNew=xMax;
    yNew=y+efInterest->fragHeight; if (yMax > yNew) yNew=yMax;
    r=(yNew-yMin)/(xNew-xMin);
    if (abs(r-aspOptimal) < aspDelta) {
      xNice=x; yNice=y;
      aspDelta=abs(r-aspOptimal);
    };
    efInterest->fragLeft=xNice; efInterest->fragTop=yNice;
    list[fragNo]=efInterest;
  };

  void TemplateRedraw::arrangeMolecules(std::vector<PartFragmentDefinition *>& extendedList, double aspOptimal) {

    unsigned int i, j;
    PartFragmentDefinition * ef;
    PartFragmentDefinition * efTemp;
    double maxX,minY,minX,maxY,r,r1;

    if (extendedList.size() > 1) {
      //Search for Max Width and MaxHeight fragments
      for (i=0; i<(extendedList.size()-1); i++) for (j=i+1; j<extendedList.size(); j++) {
          ef=(PartFragmentDefinition *)extendedList[i];
          efTemp=(PartFragmentDefinition *)extendedList[j];
          if (efTemp->fragWidth > ef->fragWidth) {
            extendedList[j]=ef;
            extendedList[i]=efTemp;
          };
        };
      if (extendedList.size() > 2) {
        ef=(PartFragmentDefinition *)extendedList[1];
        for (i=2; i<extendedList.size(); i++) {
          efTemp=(PartFragmentDefinition *)extendedList[i];
          if (efTemp->fragHeight > ef->fragHeight) {
            extendedList[i]=ef;
            extendedList[1]=efTemp;
            ef=efTemp;
          };
        };
      };
      //Try to arrange 1-st and 2-nd fragments....
      ef=(PartFragmentDefinition *)extendedList[0];
      efTemp=(PartFragmentDefinition *)extendedList[1];
      maxX=ef->fragWidth+efTemp->fragWidth;
      minY=efTemp->fragHeight;
      if (ef->fragHeight > minY) minY=ef->fragHeight;
      r=minY/maxX;
      minX=ef->fragWidth;
      maxY=ef->fragHeight+efTemp->fragHeight;
      r1=maxY/minX;
      if (abs(r-aspOptimal) < abs(r1-aspOptimal)) {
        if (ef->fragHeight > efTemp->fragHeight) {
          efTemp->fragLeft=ef->fragWidth;
          extendedList[1]=efTemp;
        } else {
          ef->fragLeft=efTemp->fragWidth;
          extendedList[0]=ef;
        };
      } else {
        efTemp->fragTop=ef->fragHeight;
        extendedList[1]=efTemp;
      };
      //Arranging of 3-rd and more frgments...
      if (extendedList.size()>2) for (i=2; i<extendedList.size(); i++) arrangeFragments(extendedList,i,aspOptimal);
    };
  };


  int TemplateRedraw::coordinatesPrepare(TEditedMolecule& sm, int kk, int anTemplateNo) {

    TEditedMolecule * em=nullptr;
    int i, j, k, fragmentAN, templateAN;
    int atomClean;
    int bondClean;
    std::vector<int> templateAtomNumber(0);
    std::vector<int> fragmentAtomNumber(0);
    bool test,test1;
    std::vector<TEditedMolecule *> groupsFind(0);
    TEditedMolecule tm;
    TEditedMolecule * emTemplate;
    std::vector<int> enumerator(0);
    TSingleBond * sb;
    int nFound;
    TEditedMolecule * smFragment;
    TEditedMolecule * smRest;
    int naStore;
    int result;


    sm.defineAtomConn();
    sm.allAboutCycles();


    result=-1;


    for (i=kk; i<queryData.size(); i++) if (queryData[i]->fragmentSearch(&sm,nullptr)) {
        em=queryData[i].get();
        if (! internalBondsPresent(em,&sm)) {
          result=i+1;
          break;
        };
        em=nullptr;
      };


    if (em == nullptr) {
      if (anTemplateNo >= 0) {
        sm.addAtom(6,0,0.0,0.0);
        sm.addBond(1,anTemplateNo,sm.nAtoms()-1);
        sm.defineAtomConn();
      };
      sm.redrawMolecule();
      if (anTemplateNo >= 0) {
        sm.deleteBond(sm.nBonds());
        sm.deleteAtom(sm.nAtoms()-1);
        sm.defineAtomConn();
      };
    } else {
      //Hurrah! Found! Redraw from template
      templateAtomNumber.resize(0);
      fragmentAtomNumber.resize(0);
      //Atom list formation
      atomClean=0;
      vector<int> listAtomClean;
      for (i=0; i<sm.nAtoms(); i++) {
        test=false;
        for (j=0; j<em->nAtoms(); j++) {
          k=em->queryAQTested[j];
          if (i==k) {
            //Coordinates assigning
            sm.getAtom(i)->rx=em->getAtom(j)->rx;
            sm.getAtom(i)->ry=em->getAtom(j)->ry;
            test=true;
            break;
          };
        };
        if (test) {   //Only those atoms, defined at template, are cleaned.....
          listAtomClean.push_back(i);
          atomClean++;
        };
      };

      enumerator.resize(sm.nAtoms());  //index-old number value-new number
      for (i=0; i<enumerator.size(); i++) enumerator[i]=-1;
      for (i=0; i<atomClean; i++) enumerator[listAtomClean[i]]=i;
      k=atomClean;
      for (i=0; i<enumerator.size(); i++) if (enumerator[i]==-1) {
          enumerator[i]=k;
          k++;
        };
      //Atom and bond enumeration...

      for (i=0; i<sm.nAtoms(); i++) {
        k=0;
        for (j=0; j<enumerator.size(); j++)  if (enumerator[j]==i) {
            k=j;
            break;
          };
        tm.addAtom(sm.getAtom(k)->clone());
      };
      //Bond enumeration
      for (i=0; i<sm.nBonds(); i++) {
        sb=sm.getBond(i)->clone();
        sb->at[0]=enumerator[sb->at[0]];
        sb->at[1]=enumerator[sb->at[1]];
        tm.addBond(sb);
      };

      nFound=atomClean;
      //now tm is the same as sm (simplemolecule) on input, but coordinates will be taken from template for first nFound atoms
      tm.defineAtomConn();
      tm.allAboutCycles();
      //search for connected bonds
      test=true;
      while (test) {
        test=false;
        for (i=tm.nBonds()-1; i>=0; i--) {
          test1=((tm.getBond(i)->at[0]<nFound) && (tm.getBond(i)->at[1]>=nFound)) || ((tm.getBond(i)->at[1]<nFound) && (tm.getBond(i)->at[0]>=nFound));
          if (test1) if (tm.getBond(i)->db<=1) { //acyclic bond
              test=true;
              emTemplate=new TEditedMolecule();
			  if (tm.getBond(i)->at[1] < nFound) {
				templateAN=tm.getBond(i)->at[0];
				fragmentAN=tm.getBond(i)->at[1];
			  } else {
			    templateAN=tm.getBond(i)->at[1];
				fragmentAN=tm.getBond(i)->at[0];
			  }
              templateAtomNumber.push_back(tm.getAtom(templateAN)->enumerator);  //in template....
              fragmentAtomNumber.push_back(tm.getAtom(fragmentAN)->enumerator);
              tm.deleteBond(i);  //must be called prior extract fragment
              tm.defineAtomConn();
              smFragment=tm.extractFragment(fragmentAN,nullptr);
              smRest=tm.extractFragment(templateAN,nullptr);
              tm.moleculeCopy(*smRest);
              //I have to delete unnecessary atoms and bond here...
              emTemplate->moleculeCopy(*smFragment);
              groupsFind.push_back(emTemplate);
              delete(smFragment);
              delete(smRest);
            };
          if (test) break;
        };
      };
      //Atom clean list formation
      atomClean=tm.nAtoms()-nFound;
      listAtomClean.resize(0);
      for (i=0; i<atomClean; i++) listAtomClean.push_back(nFound+i);

      vector<int> listBondClean;
      bondClean=0;
      for (i=0; i<tm.nBonds(); i++) {
        test=false;
        for (j=0; j<atomClean; j++) {
          if (listAtomClean[j]==tm.getBond(i)->at[0]) test=true;
          if (listAtomClean[j]==tm.getBond(i)->at[1]) test=true;
          if (test) break;
        };
        if (test) {
          listBondClean.push_back(i);
          bondClean++;
        };
      };
      //and cleaning....
      tm.defineAtomConn();
      tm.redraw(listAtomClean,listBondClean,atomClean,bondClean,4,0,0,false);
      for (i=0; i<groupsFind.size(); i++) {
        emTemplate=(TEditedMolecule *)groupsFind[i];
        fragmentAN=-1;
        for (j=0; j<emTemplate->nAtoms(); j++) if (emTemplate->getAtom(j)->enumerator==fragmentAtomNumber[i]) {
            fragmentAN=j;
            break;
          };

        emTemplate->refofs=sm.refofs;

        coordinatesPrepare(*emTemplate,0,fragmentAN);  //recursive call
        templateAN=-1; fragmentAN=-1;
        for (j=0; j<tm.nAtoms(); j++) if (tm.getAtom(j)->enumerator==templateAtomNumber[i]) {
            templateAN=j;
            break;
          };
        for (j=0; j<emTemplate->nAtoms(); j++) if (emTemplate->getAtom(j)->enumerator==fragmentAtomNumber[i]) {
            fragmentAN=j;
            break;
          };
		if ((templateAN>=0) && (fragmentAN>=0)) {
          naStore=tm.nAtoms();
          tm.refofs=sm.refofs;
          tm.addAsTemplate(*emTemplate,templateAN,fragmentAN,-1,-1,true);
		};
      };
      sm.moleculeCopy(tm);
      sm.defineAtomConn();
      sm.allAboutCycles();
    };
    for (i=0; i<groupsFind.size(); i++) delete(groupsFind[i]);
    return result;
  };


  class StereoBondStore {
  public:
    int bn,w;
  };

  void TemplateRedraw::redrawFine(TSimpleMolecule& smIn) {

    int i,j,n;
    std::vector<int> atomTested(smIn.nAtoms());
    std::vector<int> atomList;
    std::vector<StereoBondStore *> stereoBondList(0);
    int w;
    PartFragmentDefinition * pf;
    std::vector<PartFragmentDefinition *> frList(0);
    double xMin,xMax,yMin,yMax;
    double oldBondLength,newBondLength;
    std::vector<TEditedMolecule *> molList(0); //contains list of molecules...
    TEditedMolecule * sm;
    TEditedMolecule smCopy;
    TEditedMolecule smCopy2;
    int frCount,nA;
    TSingleAtom * sA;
    TSingleBond * sB;
    StereoBondStore * sbs;
    int nOverlapped, nOverlappedMin;

    //smIn will be clear-nothing

	for (int i=0; i<smIn.nAtoms(); i++) {
	  smIn.getAtom(i)->rx=cos(2*PI*i/smIn.nAtoms());
	  smIn.getAtom(i)->ry=-sin(2*PI*i/smIn.nAtoms());
	};
	smIn.defineAtomConn();
	smIn.allAboutCycles();
	smIn.redrawMolecule();



    oldBondLength=smIn.averageBondLength();
    if (oldBondLength < 0.1) oldBondLength=1.0;

    smCopy.moleculeCopy(smIn);

    for (i=0; i<smIn.nBonds(); i++) if ((smIn.getBond(i)->tb == 9)  || (smIn.getBond(i)->tb == 10)) {
        w=0;  //!!!! add for STEREO later !!!! w.value=ProcessStereo.analizeRS(smIn,smIn.fBond.getAT(i,1));

        if (w>0) {
          sbs=new StereoBondStore();
          sbs->bn=i;
          sbs->w=w;
          stereoBondList.push_back(sbs);
        };
      };

    for (i=0; i<smCopy.nAtoms(); i++) smCopy.getAtom(i)->anum=intToStr(i);

    for (i=0; i<smCopy.nAtoms(); i++) atomTested[i]=0;

    bool testSingleAtom=false;
    for (i=0; i<smCopy.nAtoms(); i++) if (atomTested[i] == 0) {
        smCopy.makeFragment(atomList,i,-1);
        for (j=0; j<atomList.size(); j++) {
          n=atomList[j];
          atomTested[n]=1;
        };
        sm=smCopy.extractFragment(i,nullptr);
        sm->defineAtomConn();
        if ((i == 0) && (sm->nAtoms() == 1)) testSingleAtom=true;
        molList.push_back(sm);
      };
    //Bug conversion reported by Chris 08.08.2010-Illegal Atomic Coordinates. Reason-zero bond length for single atom
    if (testSingleAtom  && (molList.size() > 1)) {
      n=-1;
      for (frCount=0; frCount<molList.size(); frCount++) {
        sm=(TEditedMolecule *)molList[frCount];
        if (sm->nAtoms() > 1) {
          n=frCount;
          break;
        };
      };
      if (n > 0) {
        sm=(TEditedMolecule *)molList[n];
        molList[n]=molList[0];
        molList[0]=sm;
      };
    };

    int qq=0;

    for (frCount=0; frCount<molList.size(); frCount++) {
      sm=(TEditedMolecule *)molList[frCount];
      for (i=0; i<sm->nAtoms(); i++) sm->getAtom(i)->enumerator=i;
      n=0;
      nOverlappedMin=10000000;
      smCopy2.moleculeCopy(*sm);
      while (n >=0) {
        qq++;
        sm->refofs=smIn.refofs;
        n=coordinatesPrepare(*sm,n,-1);

        sm->correctDblBondStereo();
        nOverlapped=sm->correctOverlapped();
        if (nOverlapped < nOverlappedMin) {
          smCopy2.moleculeCopy(*sm);
          nOverlappedMin=nOverlapped;
        } else sm->moleculeCopy(smCopy2);

        if (nOverlappedMin == 0) n=-1;
      };

      sm->defineAtomConn();
      atomList.resize(sm->nAtoms());
      for (i=0; i<atomList.size(); i++) atomList[i]=i;
      selectFragmentConfiguration(sm,&atomList);
      newBondLength=sm->averageBondLength();
      if (newBondLength > 0)  for (i=0; i<sm->nAtoms(); i++) {
          sm->getAtom(i)->rx=sm->getAtom(i)->rx*oldBondLength/newBondLength;
          sm->getAtom(i)->ry=sm->getAtom(i)->ry*oldBondLength/newBondLength;
        };
      //stereo input try
    };

    frList.resize(0);


    smCopy.clear();
    nA=0;
    for (frCount=0; frCount<molList.size(); frCount++) {
      sm=(TEditedMolecule *)molList[frCount];
      for (i=0; i<sm->nAtoms(); i++) {
        sA=sm->getAtom(i)->clone();
        smCopy.addAtom(sA);
      };
      for (i=0; i<sm->nBonds(); i++) {
        sB=sm->getBond(i)->clone();
        sB->at[0]=sm->getBond(i)->at[0]+nA;
        sB->at[1]=sm->getBond(i)->at[1]+nA;
        smCopy.addBond(sB);
      };
      //dimensions store....


      xMin=RUNDEF; xMax=RUNDEF; yMin=RUNDEF; yMax=RUNDEF;
      for (j=0; j<sm->nAtoms(); j++) {
        if ((sm->getAtom(j)->rx < xMin) || (xMin == RUNDEF)) xMin=sm->getAtom(j)->rx;
        if ((sm->getAtom(j)->rx > xMax) || (xMax == RUNDEF)) xMax=sm->getAtom(j)->rx;
        if ((sm->getAtom(j)->ry < yMin) || (yMin == RUNDEF)) yMin=sm->getAtom(j)->ry;
        if ((sm->getAtom(j)->ry > yMax) || (yMax == RUNDEF)) yMax=sm->getAtom(j)->ry;
      };
      pf=new PartFragmentDefinition();
      pf->fragID1=0;
      pf->fragID2=0;
      pf->fragID3=0;
      pf->fragFirstAtomNo=nA; // Was nA+1, lead to off-by-one problems with fragments
      pf->fragmentCount=1;
      pf->fragWidth=xMax-xMin;
      pf->fragHeight=yMax-yMin;
      pf->fragTop=0;
      pf->fragLeft=0;
      frList.push_back(pf);
      //Prepare for new get
      nA=nA+sm->nAtoms();
    };
    smCopy.defineAtomConn();
    //arrange fragments
    if (frList.size()>1) {
      newBondLength=smCopy.averageBondLength();
      for (i=0;i<frList.size(); i++) {
        pf=(PartFragmentDefinition *)frList[i];
        pf->fragWidth=pf->fragWidth+newBondLength;
        pf->fragHeight=pf->fragHeight+newBondLength;
      };
      arrangeMolecules(frList,1/1.5);
      //rescaling in fragments....
      for (i=0; i<frList.size(); i++) {
        pf=(PartFragmentDefinition *)frList[i];
        smCopy.makeFragment(atomList,pf->fragFirstAtomNo,-1);
        rescaleSingleFragment(&smCopy,&atomList,*pf,newBondLength/2);
      };
    };
    //rescaling to satisfy bond length
    newBondLength=smCopy.averageBondLength();
    if (newBondLength>0) for (i=0; i<smCopy.nAtoms(); i++) {
        smCopy.getAtom(i)->rx=smCopy.getAtom(i)->rx*oldBondLength/newBondLength;
        smCopy.getAtom(i)->ry=smCopy.getAtom(i)->ry*oldBondLength/newBondLength;
      };
    for (i=0; i<smCopy.nAtoms(); i++) {
      n=atoi(smCopy.getAtom(i)->anum.c_str());
      if (n >= 0) {
        smIn.getAtom(n)->rx=smCopy.getAtom(i)->rx;
        smIn.getAtom(n)->ry=smCopy.getAtom(i)->ry;
      };
    };
    for (i=0; i<stereoBondList.size(); i++) {
      sbs=(StereoBondStore *)stereoBondList[i];
      //w=ProcessStereo.analizeRS(smIn,smIn.fBond.getAT(sbs->bn,1)); !!!! add for STEREO later !!!!
      w = 0; // Added by Noel as the previous line assigning w has been commented out
      if ((w > 0) && (w != sbs->w)) {
        if (smIn.getBond(sbs->bn)->tb == 9) smIn.getBond(sbs->bn)->tb=10; else smIn.getBond(sbs->bn)->tb=9;
      };
    };
    for (i=0; i<stereoBondList.size(); i++) delete(stereoBondList[i]);
    for (i=0; i<frList.size(); i++) delete(frList[i]);
    for (i=0; i<molList.size(); i++) delete(molList[i]);
  };


  //-----------------------------------------------------------------------
  //***********************************************************************
  /*
    Diagram is generated using templates, which are stored in SD file templates.sdf
    The SD file is usual SD file, which contain chemical structures and might contain data.
    Only chemical structures are used. Subgraph isomorphisme search is executed and coordinates
    of atoms are determined from templates. See Molecules, 11, 129-141 (2006) for algorithm decription.
    Structures in SD file are converted in next manner:
    1. All atoms, except explicit hydrogens, are replaced with generic ANY_ATOM (matched with any atom in subgraph isomorphisme search)
    2. All bonds are replaces with generic ANY_BOND, which can be matched with any bond in molecule
    3. All hydrogen are removed, but they are used for search-query and structure atom matching is believed fo be
    successful if chemical structure contains more or equal number of hydrogens, than query. Using explicitly-defined hydrogens
    on query enables ones to remove substitutors attachment for atom, which are sterically hidden on templates
    if the file will not be found, predefined templates will be used
  */
  void generateDiagram(OBMol * pmol, std::ostream & ofs) {
    TEditedMolecule sm;
    OBAtom * atom;

    sm.readOBMol(pmol);
    sm.refofs=&ofs;

    TemplateRedraw tr;
    tr.redrawFine(sm);
    for (unsigned int i=1; i<=pmol->NumAtoms(); i++) {
      atom=pmol->GetAtom(i);
      atom->SetVector(sm.getAtom(i-1)->rx,-sm.getAtom(i-1)->ry,0.0);
    };
    sm.getMolfile(ofs);
  };

  void generateDiagram(OBMol * pmol) {
    TEditedMolecule sm;
    OBAtom * atom;

    sm.readOBMol(pmol);

    TemplateRedraw tr;
    tr.redrawFine(sm);
    for (unsigned int i=1; i<=pmol->NumAtoms(); i++) {
      atom=pmol->GetAtom(i);
      atom->SetVector(sm.getAtom(i-1)->rx,-sm.getAtom(i-1)->ry,0.0);
    };
  };

  void generateDiagram(const std::vector<int> iA1, const std::vector<int> iA2,
                       std::vector<double>& rx, std::vector<double>& ry, int nAtoms, int nBonds) {

    TEditedMolecule sm;

    sm.readConnectionMatrix(iA1,iA2,nAtoms,nBonds);
    TemplateRedraw tr;
    tr.redrawFine(sm);

    sm.normalizeCoordinates(1.0);
    rx.resize(nAtoms);
    ry.resize(nAtoms);
    for (int i=0; i<nAtoms; i++) {
      rx[i]=sm.getAtom(i)->rx;
      ry[i]=-sm.getAtom(i)->ry;
    };
  };

  bool fragmentSearch(OBMol * query, OBMol * structure) {

    TEditedMolecule sm;
    TEditedMolecule em;
    bool result=false;

    sm.readOBMol(query);
    sm.defineAtomConn();
    sm.allAboutCycles();
    em.prepareQuery(sm);
    sm.clear();
    sm.readOBMol(structure);
    sm.defineAtomConn();
    sm.allAboutCycles();

    result=em.fragmentSearch(&sm,nullptr);
    return result;
  };

  bool fragmentSearch(const std::vector<int> aPositionQuery, const std::vector<int> iA1Query,
                      const std::vector<int> iA2Query,  const std::vector<int> bondTypesQuery, const std::vector<int> aPositionStructure, const std::vector<int> iA1Structure,
                      const std::vector<int> iA2Structure,  const std::vector<int> bondTypesStructure, int nAtomsQuery, int nBondsQuery, int nAtomsStructure, int nBondsStructure) {

    TEditedMolecule sm;
    TEditedMolecule em;
    bool result=false;
    TSingleAtom * sa;
    TSingleBond * sb;
    int i;

    sm.readConnectionMatrix(iA1Query,iA2Query,nAtomsQuery,nBondsQuery);
    for (i=0; i<sm.nAtoms(); i++) {
      sa=sm.getAtom(i);
      sa->na=aPositionQuery[i];
    };
    for (i=0; i<sm.nBonds(); i++) {
      sb=sm.getBond(i);
      sb->tb=bondTypesQuery[i];
    };
    sm.defineAtomConn();
    sm.allAboutCycles();
    em.prepareQuery(sm);
    sm.clear();
    sm.readConnectionMatrix(iA1Structure,iA2Structure,nAtomsStructure,nBondsStructure);
    for (i=0; i<sm.nAtoms(); i++) {
      sa=sm.getAtom(i);
      sa->na=aPositionStructure[i];
    };
    for (i=0; i<sm.nBonds(); i++) {
      sb=sm.getBond(i);
      sb->tb=bondTypesStructure[i];
    };
    sm.defineAtomConn();
    sm.allAboutCycles();

    result=em.fragmentSearch(&sm,nullptr);
    return result;
  };


  void equivalenceList(const std::vector<int> aPosition,const std::vector<int> aCharge,
                       const std::vector<int> aRad, const std::vector<int> iA1, const std::vector<int> iA2,
                       const std::vector<int> bondTypes,  std::vector<int>& eqList, int nAtoms, int nBonds) {

    TEditedMolecule sm;
    TSingleAtom * sa;
    TSingleBond * sb;
    int i;

    sm.readConnectionMatrix(iA1,iA2,nAtoms,nBonds);
    for (i=0; i<sm.nAtoms(); i++) {
      sa=sm.getAtom(i);
      sa->na=aPosition[i];
      sa->nc=aCharge[i];
      sa->rl=aRad[i];
    };
    for (i=0; i<sm.nBonds(); i++) {
      sb=sm.getBond(i);
      sb->tb=bondTypes[i];
    };
    sm.defineAtomConn();
    sm.allAboutCycles();
    sm.makeEquivalentList(eqList,false);
  };


  void equivalenceList(OBMol * pmol,  std::vector<int>& eqList) {
    TEditedMolecule sm;

    sm.readOBMol(pmol);
    sm.defineAtomConn();
    sm.allAboutCycles();
    sm.makeEquivalentList(eqList,false);
  };

  void addFragment(OBMol * molecule, OBMol * fragment, int molAN, int fragAN, int molBN, int fragBN, bool isAddition) {
    TEditedMolecule eMol;
    TEditedMolecule eFrag;
    OBAtom sa;
    int i;

    if (molecule == fragment) return;
    eMol.readOBMol(molecule);
    eFrag.readOBMol(fragment);
    eMol.addAsTemplate(eFrag,molAN,fragAN,molBN,fragBN,isAddition);
    molecule->Clear();
    for (i=0; i<eMol.nAtoms(); i++) {
      sa.Clear();
      sa.SetAtomicNum(eMol.getAtom(i)->na);
      sa.SetFormalCharge(eMol.getAtom(i)->na);
      if (eMol.getAtom(i)->rl != 0) sa.SetSpinMultiplicity(1);
      sa.SetVector(eMol.getAtom(i)->rx,eMol.getAtom(i)->ry,0.0);
      molecule->AddAtom(sa);
    };
    for (i=0; i<eMol.nBonds(); i++) molecule->AddBond(eMol.getBond(i)->at[0]+1,eMol.getBond(i)->at[1]+1,eMol.getBond(i)->tb);
    molecule->EndModify();
  };


  void createStereoLists(OBMol * pmol, std::vector<int>& bondStereoList, std::vector<int>& atomStereoList, std::vector<int>& eqList) {
    TEditedMolecule sm;
    int n,m,i,j,n1,n2;
    bool test;

    //checking if multiply stereocenters or acyclic double=bonds are present
    sm.readOBMol(pmol);
    sm.defineAtomConn();
    sm.allAboutCycles();
    n=0;
    m=0;
    for (i=0; i<sm.nBonds();  i++) {
      if ((sm.getBond(i)->tb == 9) || (sm.getBond(i)->tb == 10)) n++;
      if ((sm.getBond(i)->tb == 2) && (sm.getBond(i)->db < 2)) m++;
      if ((m > 0) || (n > 1)) break;
    };
    sm.makeEquivalentList(eqList,false);
    bondStereoList.resize(sm.nBonds());
    for (i=0; i<sm.nBonds(); i++) bondStereoList[i]=0;
    for (i=0; i<sm.nBonds(); i++) if ((sm.getBond(i)->tb == 2) && (sm.getBond(i)->db < 2)) {
        //possible YES!
        n=sm.getBond(i)->at[0];
        test=(sm.getAtom(n)->nb > 1) && (sm.getAtom(n)->nb <= 3);
        if (test) {
          n=sm.getBond(i)->at[1];
          test=(sm.getAtom(n)->nb > 1) && (sm.getAtom(n)->nb <= 3);
        };
        n=sm.getBond(i)->at[0];
        m=sm.getBond(i)->at[1];
        if (test && (sm.getAtom(n)->nb == 3)) {  //checking if equivalent substitutors are present....
          n1=-1;
          n2=-1;
          for (j=0; j<sm.getAtom(n)->nb; j++) if (sm.getAtom(n)->ac[j] != m) {
              if (n1 == -1) n1=sm.getAtom(n)->ac[j]; else n2=sm.getAtom(n)->ac[j];
            };
          if ((n1 >= 0) && (n2 >= 0)) {
            if (eqList[n1] == eqList[n2]) test=false;
          };
        };
        n=sm.getBond(i)->at[1];
        m=sm.getBond(i)->at[0];
        if (test && (sm.getAtom(n)->nb == 3)) {  //checking if equivalent substitutors are present....
          n1=-1;
          n2=-1;
          for (j=0; j<sm.getAtom(n)->nb; j++) if (sm.getAtom(n)->ac[j] != m) {
              if (n1 == -1) n1=sm.getAtom(n)->ac[j]; else n2=sm.getAtom(n)->ac[j];
            };
          if ((n1 >= 0) && (n2 >= 0)) {
            if (eqList[n1] == eqList[n2]) test=false;
          };
        };
        if (test) bondStereoList[i]=1;
      };  //end of double bond stereo list formation

    //Formation of atoms, which have stereo notation....
    atomStereoList.resize(sm.nAtoms());
    for (i=0; i<sm.nAtoms(); i++) atomStereoList[i]=0;
    for (i=0; i<sm.nBonds(); i++) if ((sm.getBond(i)->tb == 9) || (sm.getBond(i)->tb == 10)) {
        n=sm.getBond(i)->at[0];
        atomStereoList[n]=1;
      };
  };

  int compareStringsNumbers(string s1, string s2) {

    int result;
    unsigned int n, i;

    n=s1.length();
    if (s2.length()>n) n=s2.length();
    if (s1.length()<n) for (i=s1.length(); i<n; i++) {
        if ((s1.at(0) >= '0') && (s1.at(0) <= '9')) s1="0"+s1; else s1=s1+"0";
      };
    if (s2.length()<n) for (i=s2.length(); i<n; i++) {
        if ((s2.at(0) >= '0') && (s2.at(0) <= '9')) s2="0"+s2; else s2=s2+"0";
      };
    //lowest priority -zz

    result=s1.compare(s2);
    return result;
  }


  std::string getAtomSymbol(TSimpleMolecule & sm, int atAtom, int atEx, int priority, string ndData) {
    //!  nepravil'no
    //For given atom AtAtom returns atom symbol with given prioritate. AtEx-do not take part into calculations
    string result="";
    std::vector<string> collectedSymbols(15);
    //string collectedSymbols [] = new string [15];
    int nPrior=0;
    int i,j,n;
    bool test;

    //result=aSymb[sm.getAtom(atAtom)->na];
    //result="at="+intToStr(atAtom)+" nt="+intToStr(sm.nAtoms())+" na="+intToStr(sm.getAtom(atAtom)->na);

    for (i=0; i<sm.getAtom(atAtom)->nb; i++) {
      n=sm.getAtom(atAtom)->ac[i];
      if (n != atEx) {
        nPrior++;
        test=false;
        if (sm.getAtom(n)->anum.length() > 0) test=true;
        if (test) collectedSymbols[nPrior-1]=sm.getAtom(n)->anum; else collectedSymbols[nPrior-1]=aSymb[sm.getAtom(n)->na];
      };
    };
    n=sm.getNH(atAtom);
    for (i=0; i<n; i++) {
      nPrior++;
      collectedSymbols[nPrior-1]="H";
    };
    if (nPrior < 4) for (i=0; i<4; i++) {
        nPrior++;
        collectedSymbols[nPrior-1]=ndData;//"zz";  //instead of 0 - less prioritate....
        if (nPrior == 4) break;
      };
    for (i=0; i<(nPrior-1); i++) for (j=i+1; j<nPrior; j++) if (compareStringsNumbers(collectedSymbols[i],collectedSymbols[j])>0) {
          result=collectedSymbols[i];
          collectedSymbols[i]=collectedSymbols[j];
          collectedSymbols[j]=result;
        };
    if ((priority > 0) && (priority <= nPrior)) result=collectedSymbols[priority-1];
    return result;
  };


  std::string getAtomSymbol(TSimpleMolecule & sm, int atAtom) {
    bool test=false;
    string result="";

    if (sm.getAtom(atAtom)->anum.length() > 0) test=true;
    if (test) result=sm.getAtom(atAtom)->anum; else result=aSymb[sm.getAtom(atAtom)->na];
    return result;
  };

  int indexOf(const string instring, const string substring, int fromPos=0) {
    int result=instring.find(substring,fromPos);
    if (result == string::npos) result=-1;
    if (result >= instring.length()) result=-1;
    return result;
  };

  std::string removeZeroeth(std::string instring) {
    string result=instring;
    int n;

    n=indexOf(result,",0");
    while (n>=0) {
      result=result.substr(0,n+1)+result.substr(n+2);
      n=indexOf(result,",0");
    };
    return result;
  };

  int analizeParity(string data) {
    int result=0;  //Unknown parity
    int n,m,n1;
    string s1="";
    string s2="";
    bool test=true;

    n1=0;
    n=data.length();
    m=0;
    while (test) {
      n--;
      if (data.at(n) == ',') {
        n1++;
        if (s2.length() == 0) {
          s2=data.substr(n+1);
          m=n;
        };
      };
      test=(n1 < 2) && (n > 1);
    };
    if ((n1 == 2) && (n > 0) && (m > 0)) s1=data.substr(n+1,m);
    if ((s1.length() >0 ) && (s2.length() > 0)) {
      n=compareStringsNumbers(s1,s2);
      if (n > 0) result=1; else if (n < 0) result=-1;
    };
    return result;
  };

  int analizeParityBond(string data) {
    int result=0;  //Unknown parity
    int n,m;
    string s1="";
    string s2="";
    string s3="";
    bool test;

    n=data.length();
    m=0;
    test=true;
    while (test) {
      n--;
      if (data.at(n) == ',') {
        test=false;
        s3=data.substr(n+1);
        m=n;
      };
    };
    test=n>1;
    while (test) {
      n--;
      if (data.at(n) == ',') {
        test=false;
        s2=data.substr(n+1,m);
        m=n;
      };
    };
    test=n>1;
    while (test) {
      n--;
      if (data.at(n) == ',') {
        test=false;
        s1=data.substr(n+1,m);
        m=n;
      };
    };
    if ((s1.length() > 0) && (s2.length() > 0)) {
      n=compareStringsNumbers(s1,s2);
      if (n > 0) result=1; else if (n < 0) result=-1;
    };
    return result;
  };


  std::string changeParity(std::string data) {
    string result="";
    int n,m,n1;
    string s1="";
    string s2="";
    bool test=true;

    n1=0;
    n=data.length();
    m=0;
    while (test) {
      n--;
      if (data.at(n) == ',') {
        n1++;
        if (s2.length() == 0) {
          s2=data.substr(n+1);
          m=n;
        };
      };
      test=(n1 < 2) && (n > 1);
    };
    if ((n1 == 2) && (n > 0) && (m > 0)) {
      s1=data.substr(n+1,m);
      result=data.substr(0,n)+","+s2+","+s1;
    };
    return result;
  };

  std::string changeParityBond(std::string data) {
    string result="";
    int n,m;
    string s1="";
    string s2="";
    string s3="";
    bool test;

    n=data.length();
    m=0;
    test=true;
    while (test) {
      n--;
      if (data.at(n) == ',') {
        test=false;
        s3=data.substr(n+1);
        m=n;
      };
    };
    test=n>1;
    while (test) {
      n--;
      if (data.at(n) == ',') {
        test=false;
        s2=data.substr(n+1,m);
        m=n;
      };
    };
    test=n>1;
    while (test) {
      n--;
      if (data.at(n) == ',') {
        test=false;
        s1=data.substr(n+1,m);
        m=n;
      };
    };
    if ((s1.length() > 0) && (s2.length() > 0) && (s3.length() > 0)) {
      result=data.substr(0,n)+","+s2+","+s1+","+s3;
    };
    return result;
  };

  std::string getAtomMCDL(OBMol * pmol, int ntatoms, const std::vector<int> ix, const std::vector<int> aNumber, const std::vector<int> atomStereoList, const std::vector<int> eqList) {

    TEditedMolecule sm;
    int i,j,k,n,atn,n1,m;
    string result="";
    string data="";
    string as1,as2,s,s1,s2;
    std::vector<int> priority(4);
    std::vector<string> v(0);
    std::vector<int> anumStereo(0);
    bool testParity;

    sm.readOBMol(pmol);

    for (i=0; i<sm.nAtoms(); i++) sm.getAtom(i)->anum="";
    for (i=0; i<ntatoms; i++) {
      n=ix[i];        //new numeration
      atn=aNumber[i]; //numeration in sm
      sm.getAtom(atn)->anum=intToStr(n);
    };

    for (i=0; i<ntatoms; i++) {
      atn=aNumber[i]; //atom number in sm (initial molecule)
      if (atomStereoList[atn] != 0) {  //Contains stereo information
        n=ix[i];        //central atom, new numeration
        data=""+intToStr(n);
        for (j=0; j<priority.size(); j++) priority[j]=0;
        as1=""; as2="";
        //cleaning fragIndex - addition from June 2008
        for (j=0; j<sm.getAtom(atn)->nb; j++) {
          k=sm.getAtom(atn)->ac[j];
          sm.getAtom(k)->fragIndex=0;
        }
        //end addition


        for (j=1; j<=4; j++) {
          s=getAtomSymbol(sm,atn,-1,j,"00");
          //Search through bonds...
          n1=-1;
          s1="";
          for (k=0; k<sm.nBonds(); k++) if ((sm.getBond(k)->at[0] == atn) || (sm.getBond(k)->at[1] == atn)) {
              if (sm.getBond(k)->at[0] == atn) m=sm.getBond(k)->at[1]; else m=sm.getBond(k)->at[0];
              s1=getAtomSymbol(sm,m);
              if (s.compare(s1) == 0) {
                sm.getAtom(m)->fragIndex=5-j;
                n1=k;
                break;
              };
            };
          if (n1 > 0) priority[j-1]=n1; else if (j<4) priority[j-1]=-1;
          if (j <= 2) data=data+","+s;  else if (j == 3) as1=s; else as2=s;
        };

        int bn=-1;
        for (j=0; j<sm.nBonds(); j++) if ((sm.getBond(j)->tb == 9) || (sm.getBond(j)->tb == 10)) {
            if (sm.getBond(j)->at[0] == atn) {
              bn=j;
              break;
            };
          };
        m=sm.singleAtomicDescriptor(atn,bn,true);
        if (m == 1) data=data+","+as2+","+as1; else data=data+","+as1+","+as2;
        v.push_back(data);
        anumStereo.push_back(atn);  //accumulation of atomic numbers in sm to check meso-forms...
      };
    };

    //meso-isomer handling
    string ss="";
    bool presentOtherStereo=false;
    if (anumStereo.size() > 1) for (i=0; i<(anumStereo.size()-1); i++) if (anumStereo[i] >= 0) {
          n=0;
          for (j=i+1; j<anumStereo.size(); j++) if ((anumStereo[i] >= 0) && (anumStereo[j] >= 0)) if (eqList[anumStereo[i]] == eqList[anumStereo[j]]) n++;
          if ((n % 2) != 1) presentOtherStereo=true;
          if (n>=1) {  //meso-forms search...
            s=v[i];
            k=analizeParity(s);
            testParity=false;
            for (j=i+1; j<anumStereo.size(); j++) if ((anumStereo[i] >= 0) && (anumStereo[j] >= 0)) if (eqList[anumStereo[i]] == eqList[anumStereo[j]]) {
                  s1=v[j];
                  if (! testParity) {
                    m=analizeParity(s1);
                    if (k*m == -1) testParity=true;
                  };
                  if (s.compare(s1) > 0) s=s1;
                };
            if (testParity) {
              if ((ss.length() == 0) || (ss.compare(s) > 0)) ss=s;
              for (j=i+1; j<anumStereo.size(); j++) if ((anumStereo[i] >= 0) && (anumStereo[j] >= 0)) if (eqList[anumStereo[i]] == eqList[anumStereo[j]]) anumStereo[j]=-1;
              anumStereo[i]=-1;
            } else {
              for (j=i+1; j<anumStereo.size(); j++) if ((anumStereo[i] >= 0) && (anumStereo[j] >= 0)) if (eqList[anumStereo[i]] == eqList[anumStereo[j]]) anumStereo[j]=-2;
              anumStereo[i]=-2;
              presentOtherStereo=true;
            };
          } else anumStereo[i]=-2;
        };
    //Do not analyze meso-forms for complex molecules....
    if (presentOtherStereo) ss="";

    if (ss.length() > 0) {  //some meso-isomers were found-analyze their parity and change if necessary
      k=analizeParity(ss);
      if (k == 1) for (i=0; i<anumStereo.size(); i++) if (anumStereo[i] == -1) {  //all parities should be changed to satisfy..
            s=v[i];
            s1=changeParity(s);
            v[i]=s1;
          };
    };

    //end meso-isomers handling
    //sorting vectors...
    if (v.size() > 1) for (i=0; i<(v.size() - 1); i++) for (j=i+1; j<v.size(); j++) {
          s1=v[i];
          s2=v[j];
          if (compareStringsNumbers(s1,s2) > 0) {
            v[j]=s1;
            v[i]=s2;
          };
        };
    if (v.size() > 0) {
      result=fsastart;
      for (i=0; i < v.size(); i++) {
        s1=v[i];
        while (indexOf(s1,"zz") > 0) {  //Substitite temporary lowest-priority 00 to zero
          n=indexOf(s1,"zz");
          s1=s1.substr(0,n)+"0"+s1.substr(n+2);
        };
        while (indexOf(s1,"00") > 0) {  //Substitite temporary lowest-priority 00 to zero
          n=indexOf(s1,"00");
          s1=s1.substr(0,n)+"0"+s1.substr(n+2);
        };
        if (i > 0) result=result+";";
        s1=removeZeroeth(s1);
        result=result+s1;
      };
      result=result+"}";
    };
    return result;
  };

  bool bondEquivalent(int bn1, int bn2, const std::vector<int> eqList, TSimpleMolecule & sm) {
    bool result=false;
    int n1,n2,n3,n4;

    if ((bn1 >= sm.nBonds()) || (bn2 > sm.nBonds())) return result;
    n1=sm.getBond(bn1)->at[0];
    n2=sm.getBond(bn1)->at[1];
    n3=sm.getBond(bn2)->at[0];
    n4=sm.getBond(bn2)->at[1];
    result=(((eqList[n1] == eqList[n3]) && (eqList[n2] == eqList[n4])) ||
            ((eqList[n1] == eqList[n4]) && (eqList[n2] == eqList[n3])));
    return result;
  };


  std::string getBondMCDL(OBMol * pmol, int nbStore, int ntatoms, const std::vector<int> ix, const std::vector<int> aNumber, int bonds[MAXBONDS][4], const std::vector<int> bondStereoList, const std::vector<int> eqList) {
    TSimpleMolecule sm;
    std::vector<int> anumStereo(0);
    std::vector<string> v(0);
    int i,j,n,m,n1,n2,n3,n4,an1,an2,an3,an4,k;
    string s,s1,s2,as1,as2,as3,as4;
    bool testDouble,testParity;
    string data="";
    string result="";

    sm.readOBMol(pmol);

    for (i=0; i<sm.nAtoms(); i++) sm.getAtom(i)->anum="";
    for (i=0; i<ntatoms; i++) {
      n=ix[i];        //new numeration
      k=aNumber[i];   //numeration in sm
      sm.getAtom(k)->anum=intToStr(n);
    };



    for (i=0; i<nbStore; i++) if (bonds[i][2] == 2) {
        n=bonds[i][3]-1; //Old bond number
        testDouble=bondStereoList[n] == 1;  //bondStereoList is filled on input-stereonotation can be used for acyclic double-bond with non-equivalent substitutors....
        if (testDouble) {
          n1=ix[bonds[i][0]-1];
          n2=ix[bonds[i][1]-1];
          if (n1>n2) {
            k=bonds[i][0];
            bonds[i][0]=bonds[i][1];
            bonds[i][1]=k;
          };
          //1-st atom has minimal number now. Search for minimal number, attached to first
          n1=ix[bonds[i][0]-1];
          n2=ix[bonds[i][1]-1];

          data=""+intToStr(n1)+"d"+intToStr(n2);
          n1=-1;  //to 1-st atom
          n2=-1;
          n3=-1;  //to 2-nd atom
          n4=-1;
          an1=-1; an2=-1; an3=-1; an4=-1;
          // search for the attached atoms...
          for (j=0; j<nbStore; j++) if (i != j) {
              if ((bonds[j][0] == bonds[i][0]) || (bonds[j][1] == bonds[i][0])) {
                if (n1 == -1) n1=j; else n2=j;
                if (bonds[j][0] == bonds[i][0]) {
                  if (an1 == -1) an1=ix[bonds[j][1]-1]; else an2=ix[bonds[j][1]-1];
                } else {
                  if (an1 == -1) an1=ix[bonds[j][0]-1]; else an2=ix[bonds[j][0]-1];
                };
              };
              if ((bonds[j][0] == bonds[i][1]) || (bonds[j][1] == bonds[i][1])) {
                if (n3 == -1) n3=j; else n4=j;
                if (bonds[j][0] == bonds[i][1]) {
                  if (an3 == -1) an3=ix[bonds[j][1]-1]; else an4=ix[bonds[j][1]-1];
                } else {
                  if (an3 == -1) an3=ix[bonds[j][0]-1]; else an4=ix[bonds[j][0]-1];
                };
              };
            };
          if ((an1 >= 0) && (an2 >= 0)) if (an1 > an2) {
              k=n1; n1=n2; n2=k;
              k=an1; an1=an2; an2=k;
            };
          //Now n1,n2 contains bond numbers in bonds array, connected to bonds[i][0] atom. n3,n4-bond numbers, connected to bonds[i][1] atom.
          //I have to use corresponding elements bonds[n1][3] to determine bond numbers in initial molecule sm.
          if (an1 >= 0) as1=""+intToStr(an1); else {
            //Hydrogens MUST not be...
            as1=getAtomSymbol(sm,aNumber[bonds[i][0]-1],aNumber[bonds[i][1]-1],1,"zz");
          };
          if (an2 >= 0) as2=""+intToStr(an2); else {
            as2=getAtomSymbol(sm,aNumber[bonds[i][0]-1],aNumber[bonds[i][1]-1],2,"zz");
            if (as2.compare("zz") == 0) {
              as2="00";
            };
          };
          if (an3 >= 0) as3=""+intToStr(an3); else {
            //Hydrogens MUST not be...
            as3=getAtomSymbol(sm,aNumber[bonds[i][1]-1],aNumber[bonds[i][0]-1],1,"zz");
          };
          if (an4 >= 0) as4=""+intToStr(an4); else {
            as4=getAtomSymbol(sm,aNumber[bonds[i][1]-1],aNumber[bonds[i][0]-1],2,"zz");
            if (as4.compare("zz") == 0) {
              as4="00";
            };
          };

          if (n1 < 0) {  //bond is connected with undefined atom - search for it....
            an1=aNumber[bonds[i][0]-1];
            an2=aNumber[bonds[i][1]-1]; //excluded atom...
            for (j=0; j<sm.nBonds(); j++) {
              an3=sm.getBond(j)->at[0];
              an4=sm.getBond(j)->at[1];
              if ((an3 == an1) || (an4 == an1)) {
                if (an3 == an1) k=an4; else k=an3;
                if (k != an2) {
                  s=getAtomSymbol(sm,k);
                  if (s.compare(as1) == 0) n1=j;
                };
              };
              if (n1 >= 0) break;
            };
            //Searching for anum!
          } else n1=bonds[n1][3]-1;
          if (n3 < 0) {  //bond is connected with undefined atom - search for it....
            an1=aNumber[bonds[i][1]-1];
            an2=aNumber[bonds[i][0]-1]; //excluded atom...
            for (j=0; j<sm.nBonds(); j++) {
              an3=sm.getBond(j)->at[0];
              an4=sm.getBond(j)->at[1];
              if ((an3 == an1) || (an4 == an1)) {
                if (an3 == an1) k=an4; else k=an3;
                if (k != an2) {
                  s=getAtomSymbol(sm,k);
                  if (s.compare(as3) == 0) n3=j;
                };
              };
              if (n3 >= 0) break;
            };
            //Searching for anum!
          } else n3=bonds[n3][3]-1;

          //above OK

          if ((n1 < 0) || (n3 < 0)) {
            //my error in logic. raise an exception
            //or do nothing...
            data="";
          } else {
            //sign determine...
            //Then I can to determine scalar product
            //and angle between bonds n1 and n3
            k=sproduct(sm,bonds[i][3]-1,n1,n3);
            if (as2.compare("00") == 0) {
              data=data+","+as2;
              if (k == 1) {  //cis
                data=data+","+as4;
                data=data+","+as3;//an3;
                data=data+","+as1;
              } else if (k == 2) {  //trans
                data=data+","+as3;
                data=data+","+as4;
                data=data+","+as1;
              } else data="";  //collinear
            } else {
              data=data+","+as1;//an1;
              if (k == 1) {  //cis
                data=data+","+as3;//an3;
                data=data+","+as4;
                data=data+","+as2;
              } else if (k == 2) {  //trans
                data=data+","+as4;
                data=data+","+as3;
                data=data+","+as2;
              } else data="";  //collinear
            };
          };
          if (data.length() > 0) {
            v.push_back(data);
            anumStereo.push_back(n);
          };
        }
      };


    //Identical double-bonds search, like cis,trans-hexa-2,4-diene
    if (anumStereo.size() > 1) for (i=0; i<(anumStereo.size()-1); i++) if (anumStereo[i] >= 0) {
          n=0;
          for (j=i+1; j<anumStereo.size(); j++) if (bondEquivalent(anumStereo[i],anumStereo[j],eqList,sm)) n++;
          if (n>=1) {  //bond searching...
            s=v[i];
            k=analizeParityBond(s);
            testParity=false;
            for (j=i+1; j<anumStereo.size(); j++) if (bondEquivalent(anumStereo[i],anumStereo[j],eqList,sm)) {
                s1=v[j];
                if (! testParity) {
                  m=analizeParityBond(s1);
                  if (k*m == -1) testParity=true;
                };
                if (compareStringsNumbers(s,s1)>0) s=s1;
              };
            if (testParity) {
              k=analizeParityBond(s);
              if (k == 1) {  //all parities should be changed to satisfy..
                s=v[i];
                s1=changeParityBond(s);
                v[i]=s1;
                for (j=i+1; j<anumStereo.size(); j++) if (bondEquivalent(anumStereo[i],anumStereo[j],eqList,sm)) {
                    s=v[j];
                    s1=changeParityBond(s);
                    v[j]=s1;
                  };
              };
            };
            // set all anumStereo processed to 0 to indicate, that no processing is required
            for (j=i+1; j<anumStereo.size(); j++) if (bondEquivalent(anumStereo[i],anumStereo[j],eqList,sm)) anumStereo[j]=-1;
          };
          anumStereo[i]=-1;
        }; //end symmetrical bonds

    if (v.size() > 1) for (i=0; i<(v.size() - 1); i++) for (j=i+1; j<v.size(); j++) {
          s1=v[i];
          s2=v[j];
          if (compareStringsNumbers(s1,s2) > 0) {
            v[j]=s1;
            v[i]=s2;
          };
        };
    if (v.size() > 0) {   //stereobonds present
      result=fsbstart;
      for (i=0; i < v.size(); i++) {
        s1=v[i];
        while (indexOf(s1,"zz") > 0) {  //Substitite temporary lowest-priority 00 to zero
          n=indexOf(s1,"zz");
          s1=s1.substr(0,n)+"0"+s1.substr(n+2);
        };
        while (indexOf(s1,"00") > 0) {  //Substitite temporary lowest-priority 00 to zero
          n=indexOf(s1,"00");
          s1=s1.substr(0,n)+"0"+s1.substr(n+2);
        };
        if (i > 0) result=result+";";
        s1=removeZeroeth(s1);
        result=result+s1;
      };
      result=result+"}";
    } else result="";
    return result;
  };

  std::string addZeroeth(std::string instring, std::string stringAdd) {
    string result=instring;
    int n;

    n=indexOf(result,",,");
    while (n>=0) {
      result=result.substr(0,n+1)+stringAdd+result.substr(n+1);
      n=indexOf(result,",,");
    };
    return result;
  };


  void setUpDownBonds(int atomNo, int parity, TSimpleMolecule & sm, std::vector<int>& iA1, std::vector<int>& iA2, std::vector<int>& stereoBonds) {
    int i,k;

    for (i=0; i<sm.nBonds(); i++) if (stereoBonds[i] == -1) {
        if ((sm.getBond(i)->at[0] == atomNo) || (sm.getBond(i)->at[1] == atomNo)) {
          if (sm.getBond(i)->at[1] == atomNo) {  //change atomic order...
            k=sm.getBond(i)->at[0];
            sm.getBond(i)->at[0]=sm.getBond(i)->at[1];
            sm.getBond(i)->at[1]=k;
            k=iA1[i];
            iA1[i]=iA2[i];
            iA2[i]=k;
          };
          sm.getBond(i)->tb=9;  //up
          k=sm.singleAtomicDescriptor(atomNo,i,false);
          //!!! By unknown reason inversion of configuration took place.
          if (k == parity) stereoBonds[i]=2; else stereoBonds[i]=1;
          break;
        };
      };
  };


  void implementAtomStereo(std::vector<int>& iA1, std::vector<int>& iA2, std::vector<int>& stereoBonds, const std::vector<double>rx, const std::vector<double> ry, int acount, int bcount, std::string astereo) {
    //onInput stereoBonds contains only those bonds, which might be stereo
    TSimpleMolecule sm;

    string ss,s,temp;
    int n1,atn;
    bool threeCoor;

    if (astereo.length() == 0) return;
    sm.readConnectionMatrix(iA1,iA2,rx,ry,acount,bcount);

    ss=astereo;
    astereo=addZeroeth(astereo,"-1");
    while (astereo.length() >0 ) {
      s="";
      n1=indexOf(astereo,";");
      if (n1 > 0) {
        s=astereo.substr(0,n1);
        if (n1 < (astereo.length()-1)) astereo=astereo.substr(n1+1); else astereo="";
      } else {
        s=astereo;
        astereo="";
      };
      //analize s
      if (s.length() > 0) {
        //save data in Astereo... Bond reconfiguring is possible only after re-drawing and chain rotations
        //      s=removeSpaces(s);
        n1=indexOf(s,",");
        if (n1 > 0) {
          threeCoor=(indexOf(s,"-1") > 0);
          temp=s.substr(0,n1);
          s=s.substr(n1+1);
          atn=atoi(temp.c_str())-1;  //one-based-has to be corrected to zero-based
          n1=indexOf(s,",");
          if (n1 > 0) s=s.substr(n1+1);
          n1=indexOf(s,",");
          if (n1 > 0) s=s.substr(n1+1);
          n1=indexOf(s,"H");
          if (n1<0) {
            n1=indexOf(s,"0");
            if (n1 > 0) n1=indexOf(s,",0"); //occupy last position
          };
          if (n1 == 0) {
            setUpDownBonds(atn,1,sm,iA1,iA2,stereoBonds);
          } else if (n1 > 0) {
            setUpDownBonds(atn,2,sm,iA1,iA2,stereoBonds);
          } else {
            //Priority analizing
            n1=indexOf(s,",");
            if (n1 > 0) {
              temp=s.substr(0,n1);
              s=s.substr(n1+1);
              if (temp.compare("0") == 0) temp="zz";
              if (s.compare("0") == 0) s="zz";
              if (threeCoor) {
                if (compareStringsNumbers(temp,s) < 0) /*result.fAtom.setAStereo(atn,(byte)1)*/setUpDownBonds(atn,1,sm,iA1,iA2,stereoBonds); else setUpDownBonds(atn,2,sm,iA1,iA2,stereoBonds)/*result.fAtom.setAStereo(atn,(byte)2)*/;
              } else {
                if (compareStringsNumbers(temp,s) > 0) /*result.fAtom.setAStereo(atn,(byte)1)*/setUpDownBonds(atn,1,sm,iA1,iA2,stereoBonds); else setUpDownBonds(atn,2,sm,iA1,iA2,stereoBonds)/*result.fAtom.setAStereo(atn,(byte)2)*/;
              };
            };
          };
        };
      };
    };
  };

  // The following function is used by MCDLformat.cpp
  void implementBondStereo(const std::vector<int> iA1, const std::vector<int> iA2, std::vector<double>& rx, std::vector<double>& ry, int acount, int bcount, std::string bstereo) {
    TEditedMolecule sm;
    string ss,s,sF,sa1,sa2,temp;
    int i,n1,n2,k,bn;
    bool hasStereo=false;
    bool coorChanged=false;
    if (bstereo.length() == 0) return;
    sm.readConnectionMatrix(iA1,iA2,rx,ry,acount,bcount);
    ss=bstereo;
    bstereo=addZeroeth(bstereo,"0");
    while (bstereo.length() >0 ) {
      s="";
      n1=indexOf(bstereo,";");
      if (n1 > 0) {
        s=bstereo.substr(0,n1);
        if (n1 < (bstereo.length()-1)) bstereo=bstereo.substr(n1+1); else bstereo="";
      } else {
        s=bstereo;
        bstereo="";
      };
      //analize s
      if (s.length() > 0) {
        //save data in Bstereo... Bond reconfiguring is possible only after re-drawing
        //      CommonRout.RemoveSpaces(s);
        n1=indexOf(s,",");
        if (n1 > 0) {
          temp=s.substr(0,n1);
          s=s.substr(n1+1);
          n1=indexOf(temp,"d");
          if (n1 < 0) n1=indexOf(temp,"D");
          if (n1 > 0) {
            n2=atoi(temp.substr(0,n1).c_str());
            n1=atoi(temp.substr(n1+1).c_str());
            //search for bond...
            bn=-1;
            for (i=0; i<sm.nBonds(); i++) if (((sm.getBond(i)->at[0] == (n1-1)) && (sm.getBond(i)->at[1] == (n2-1))) || ((sm.getBond(i)->at[0] == (n2-1)) && (sm.getBond(i)->at[1] == (n1-1)))) {
                bn=i;
                break;
              };
            n1=-1;
            n2=-1;
            k=indexOf(s,",");
            sF="";
            if (k > 0)  {
              sF=s.substr(0,k);
              s=s.substr(k+1);  //removing 1-st fragment, added to an1
            };
            k=indexOf(s,",");
            sa1=""; sa2="";
            if (k > 0) {                    //and analizing of order of two remaining fragments, connected to an2
              sa1=s.substr(0,k);
              s=s.substr(k+1);
              try {
                n1=atoi(sa1.c_str());
                if (n1 == 0) {
                  n1=-1;
                  sa1="00";//"zz";
                };
              } catch (exception &ex) {
                n1=-1;
              };
            };
            k=indexOf(s,",");
            if (k > 0) {
              sa2=s.substr(0,k);
              s=s.substr(k+1);
              try {
                n2=atoi(sa2.c_str());
                if (n2 == 0) {
                  n2=-1;
                  sa2="00";//"zz";
                };
              } catch (exception &ex) {
                n2=-1;
              };
            };
            if (bn >= 0) {
              if ((n1 < 0) && (n2 < 0)) {
                if (compareStringsNumbers(sa1,sa2) > 0) k=1; else k=2;
              } else {
                if (n1 < 0) k=1; else //E
                  if (n2 < 0) k=2; else { //Z
                    if (n1 < n2) k=2; else k=1;
                  };
              };
              if (sF.compare("0") == 0) k=3-k;
              sm.getBond(bn)->bstereo=k;
              hasStereo=true;
            };
          };
        };
      };
    };
    if (hasStereo) {
      coorChanged = sm.correctDblBondStereo();
      if (coorChanged) for (i=0; i<sm.nAtoms(); i++) {
          rx[i]=sm.getAtom(i)->rx;
          ry[i]=sm.getAtom(i)->ry;
        };
    };
  };

  //****************************************************************************
  //Group redraw - generate 2D coordinates  for chemical group
  //****************************************************************************
  int OBMCDL groupRedraw(OBMol * pmol, int bondN, int atomN, bool atomNInGroup) {
    /*
      bondN - index of acyclic bond in pmol (zero-based).
      atomN - index of atom attached to bond bondN to start redraw from it (1-based)
      atomNInGroup - if true it is assumed, that atom atomN, attached to bond bondN
      is inside group to be redrawn, false otherwise
      Atoms at both ends of the bond should have coordinates before calling this function.
      returns 0 - all OK, =1 - number of atoms or bond are outside defined, = 2-cyclic bond
    */
    TSimpleMolecule sm;
    int result=0;

    std::vector<int> bondList;
    OBAtom * atom;
    int i,n,at,atEx,nb;

    sm.readOBMol(pmol);
    atomN--; //TSimpleMolecule: numeration of atoms is started from 0, while for OBMOl from 1;
    if ((bondN >= sm.nBonds())  || (bondN < 0) || (atomN >= sm.nAtoms()) || (atomN < 0)) {
      result=1;
      return result;
    };

    if (sm.getBond(bondN)->db > 0) {
      result=2;
      return result;
    };
    if (! atomNInGroup) {
      n=sm.getBond(bondN)->at[0];
      if (n == atomN) n=sm.getBond(bondN)->at[1];
      atomN=n;
    };
    std::vector<int> allAtomList(sm.nAtoms(), 0);
    std::vector<int>    atomList(sm.nAtoms(), 0);
    n=0;
    if (sm.getBond(bondN)->at[0] == atomN) {
      at=sm.getBond(bondN)->at[0];
      atEx=sm.getBond(bondN)->at[1];
    } else {
      at=sm.getBond(bondN)->at[1];
      atEx=sm.getBond(bondN)->at[0];
    };
    if (sm.makeFragment(atomList,at,atEx)) {
      //addition of atom in non-cleaned fragment at last position
      atomList.push_back(atEx);
      for (i=0; i<atomList.size(); i++) allAtomList[atomList[i]]=1;
      nb=0;
      for (i=0; i<sm.nBonds(); i++) if ((allAtomList[sm.getBond(i)->at[0]] == 1) && (allAtomList[sm.getBond(i)->at[1]] == 1)) {
          bondList.push_back(i);
          nb++;
        };
      sm.redraw(atomList,bondList,atomList.size(),nb,3,atEx,bondN,false);
      //Setting OBMOL coordinates
      for (int i=0; i<atomList.size(); i++) {
        n=atomList[i];
        atom=pmol->GetAtom(n+1);  //1-based
        atom->SetVector(sm.getAtom(n)->rx,sm.getAtom(n)->ry,0.0);
      };
    } else result=3;  //unknown error
    return result;
  };
  /*
    int groupRedrawFrameAtom(OBMol * pmol, int bondN, int atomInFrame) {
    int atomN;
    atomN=pmol->GetBond(bondN)->GetBeginAtomIdx();
    if (atomN == atomInFrame) atomN=pmol->GetBond(bondN)->GetEndAtomIdx();
    int result=groupRedraw(pmol,bondN,atomN);
    return result;
    };
  */
  //****************************************************************************
  //assept a lot of structures on input and remove duplicates and non-connected
  //****************************************************************************
  bool parseFormula(const std::string formulaString, std::vector <int>& enumber, int & valency) {
    //vector<string> items;
    int i,n,k,n1,n2;//,j,nStart;
    string s;
    bool test;
    string asym;
    string value=formulaString;

    valency=-1;

    for (i=0; i<NELEMMCDL; i++) enumber[i]=0;

    for (i=1; i<NELEMMCDL; i++) if (aSymb[i].length()==2) {
        test=true;
        asym=aSymb[i];
        while (test) {
          test=false;
          n=indexOf(value,asym);
          if (n>=0) {
            test=true;
            value=value.substr(0,n)+value.substr(n+asym.length(),value.length());
            k=1;
            if (n<value.length()) if ((value.at(n)>='0') && (value.at(n)<='9')) {
                n1=n;
                n2=n;
                while ((n2<(value.length()-1)) && (value.at(n2)>='0') && (value.at(n2)<='9')) n2++;
                if (! ((value.at(n2)>='0') && (value.at(n2)<='9'))) n2--;
                s=value.substr(n1,n2+1);
                k=atoi(s.c_str());
                value=value.substr(0,n1)+value.substr(n2+1,value.length());
              };
            enumber[i]=enumber[i]+k;
            if ((n == 0) && (valency == -1)) valency=i;
          };
        };
      };
    for (i=1; i<NELEMMCDL; i++) if (aSymb[i].length() == 1) {
        test=true;
        asym=aSymb[i];
        while (test) {
          test=false;
          n=indexOf(value,asym);
          if (n>=0) {
            test=true;
            value=value.substr(0,n)+value.substr(n+asym.length(),value.length());
            k=1;
            if (n<value.length()) if ((value.at(n)>='0') && (value.at(n)<='9')) {
                n1=n;
                n2=n;
                while ((n2<(value.length()-1)) && (value.at(n2)>='0') && (value.at(n2)<='9')) n2++;
                if (! ((value.at(n2)>='0') && (value.at(n2)<='9'))) n2--;
                s=value.substr(n1,n2+1);
                k=atoi(s.c_str());
                value=value.substr(0,n1)+value.substr(n2+1,value.length());
              };
            enumber[i]=enumber[i]+k;
            if ((n == 0) && (valency == -1)) valency=i;
          };
        };
      };
    if (valency > 0) {
      n=valency;
      valency=hVal[n];
      if (valency == 0) valency=1;
      for (i=1; i<NELEMMCDL; i++) if ((i != n) && (enumber[i] > 0)) {
          k=hVal[i];
          if (k == 0) k=1;
          k=k*enumber[i];
          valency=valency-k;
        };
      if (valency <= 0) valency=1;
    };
    return (value.length() == 0);
  };


  int canonizeMCDL(const std::string /*atomBlock*/, std::vector<std::string>& /*structureList*/) {
    return 0;
  };


  //****************************************************************************
  //*******************Tested routines, wiil be deleted*************************
  //****************************************************************************

  void prepareTest(OBMol * pmol, std::ostream & ofs) {
    TEditedMolecule * sm;

    sm=new TEditedMolecule();
    sm->refofs=&ofs;

    sm->readOBMol(pmol);

    TemplateRedraw tr;
    tr.redrawFine(*sm);

    sm->getMolfile(ofs);

    delete(sm);
  };


} // namespace OpenBabel

//! \file mcdlutil.cpp
//! utilities for mcdl format, might be useful for another

/// @file mcdlutil.cpp
/// @brief 2D molecule coordinate generation.
