/* -*-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/mcdlutil.h>
#include <openbabel/data.h>
#include <openbabel/obconversion.h>

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

using namespace std;

namespace OpenBabel {

#define CONNMAX 15
#define NATOMSMAX 255
#define NBONDSMAX 255

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

typedef adjustedlist neigbourlist[NATOMSMAX];

#define PI 3.141592653589793238462
#define blDenominator 4.0   //Controls bond legth in bondEnlarge
#define nRotBondsMax 20     //Determines no. rotating bonds 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 147

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",
"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*/
    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];
      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*/
    short int bstereo;   /* =0 - no, =1 - E , = 2 - Z, =3 E/Z*/
    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->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=hVal[na];
  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 == NULL) || (query == NULL)) 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->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 <=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=NULL;
    };

    int nAtoms();
    int nBonds();
    TSingleAtom * getAtom(int index);
    TSingleBond * getBond(int index);
    void defineAtomConn();
    void defineBondConn(neigbourlist & bondConnection);
    void newB(neigbourlist & bk, int bnum, int anum, int & total, int * e, int * e1);
    void singleVawe(neigbourlist & 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, neigbourlist & 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(int& n, 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);
 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<int>& atomCycle, std::vector<int>& cycleAddress,
      std::vector<int>& cycleSize, 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<int>& cycleSize, std::vector<int>& cycleAddress, 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 neigbourlist bk, std::vector<int>& wSphere);
    bool threeBondResolve(int an, int bondExcluded, double& xv, double& yv, neigbourlist* bkExt);
    bool unitVectorCoincident(int aN, double xV, double yV);
};

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];
  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, neigbourlist* bkExt) {
  //Addition from 16 April 2006
  int bondNoList [3];
  bool result=false;
  double centerX[3];
  double centerY[3];
  int nBondNo;
  neigbourlist* bk;
  std::vector<int>bondList(listarSize());
  std::vector<int>* blStore=NULL;
  bool testBad,testOK;
  int m,j,n1,n2,n,k;
  int rs;
  double dist,x,y,minDist;
  int i;
  bool test;
  int at;
  double r1,r2,s1,s3;

  if (bkExt != NULL) bk=bkExt; else {
    bk=(neigbourlist *)malloc((CONNMAX+1)*NBONDSMAX*4);
    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 == NULL) {
          //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 == NULL) free(bk);
  if (blStore != NULL) 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];
  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,NULL)) {
	    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 (int i=0; i<fAtom.size(); i++) delete(fAtom.at(i));
  fAtom.clear();
  for (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(),NULL,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(),NULL,10);
    sa->rx=(double)k/10000.0;
    s=value.substr(n,4);
    n=n+4;
    k=strtol(s.c_str(),NULL,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(),NULL,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(),NULL,10);
    sb->at[0]=k-1;
    s=value.substr(n,2);
    n=n+2;
    k=strtol(s.c_str(),NULL,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 == NULL) 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]=NULL;
  };
  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());
  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]=NULL;
  };
  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]=NULL;
    } 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() {
  int result=10;  //Minimal vector size 10
  if (nAtoms() > result) result=nAtoms();
  if (nBonds() > result) result=nBonds();
  return result;
};

bool TSimpleMolecule::makeFragment(int& n, 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 array. Total number of such atoms is stored in N. 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;

  test=false;
  if ((nAtoms() ==0 ) || (aT < 0) || (aT >= nAtoms())) {
    n=0;
    list[0]=-1;;
    return test;
  }
  n=1;
  list[0]=aT;
  for (i=0; i<getAtom(aT)->nb; i++) if (getAtom(aT)->ac[i] != aTEx) {
    list[n]=getAtom(aT)->ac[i];
    n++;
  }
  if (n == 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<n; j++) if (list[j] == l) test1=true;
      } else test=true;
      if ((! test1) && (l != aTEx) && (l >= 0) && (l < nAtoms())) {
        list[n]=l;
        n++;
      }
    }
    k=k+1;                             //atoms which are connected with AT}
  } while (k<n);
  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;

  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();
	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;
	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 (i=0; i<nBonds(); i++) {
	n1=getBond(i)->at[0]; n2=getBond(i)->at[1];
	sa=getAtom(n1);
	sa->ac[sa->nb]=n2;
	sa->nb++;
	sa->currvalence=sa->currvalence+getBond(i)->getValence();
	sa=getAtom(n2);
	sa->ac[sa->nb]=n1;
	sa->nb++;
	sa->currvalence=sa->currvalence+getBond(i)->getValence();
  };
};

void TSimpleMolecule::defineBondConn(neigbourlist & 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];
    bondConnection[n1].adjusted[bondConnection[n1].nb]=i;
    bondConnection[n1].nb++;
    bondConnection[n2].adjusted[bondConnection[n2].nb]=i;
    bondConnection[n2].nb++;
  };
};

void TSimpleMolecule::newB(neigbourlist & 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(neigbourlist & 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, neigbourlist & 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(NBONDSMAX);
  std::vector<int>pB(NBONDSMAX);
  std::vector<int>oD(NBONDSMAX);
  std::vector<int>curBond(NBONDSMAX);
  std::vector<int>curAtom(NBONDSMAX);
  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[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(NBONDSMAX);
  std::vector<int>bondList(NBONDSMAX);
  std::vector<int>ar(NBONDSMAX);
  std::vector<int>rSize(NBONDSMAX);
  std::vector<int>ar1(NBONDSMAX);
  std::vector<int>cycleDescription(3*NBONDSMAX);
  std::vector<int>cycleAddress(NBONDSMAX);

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

  bk=(neigbourlist *)malloc((1+CONNMAX)*NBONDSMAX*4);


  if (nBonds() == 0) return;
  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;
    ar[i]=0;;
    bondTested[i]=0;
  };
  n=0;
  cycleAddress[0]=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);
      n++;
      cycleAddress[n]=cycleAddress[n-1]+cycleSize;  //store cycle definitions
      rSize[n-1]=cycleSize;
      for (j=0; j<cycleSize; j++) cycleDescription[cycleAddress[n-1]+j]=bondList[j];
      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
        cycleSize=rSize[i];
        for (k=0; k<cycleSize; k++) bondList[k]=cycleDescription[cycleAddress[i]+k];
        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
      cycleSize=rSize[i];
      for (k=0; k<cycleSize; k++) bondList[k]=cycleDescription[cycleAddress[i]+k];  //!!!
      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
      cycleSize=rSize[i];
      for (k=0; k<cycleSize; k++) bondList[k]=cycleDescription[cycleAddress[i]+k];  //!!!
      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<int>& atomCycle, std::vector<int>& cycleAddress,
  std::vector<int>& cycleSize, 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<cycleSize[i]; j++) if (atomDefine[atomCycle[cycleAddress[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 (cycleSize[i]<cycleSize[cN]) cN=i;
      };
    };
    if (cN>=0) if (maxAtDef==cycleSize[cN]) {
      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[cycleAddress[cN]]]>0) &&
      (atomDefine[atomCycle[cycleAddress[cN]+cycleSize[cN]-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[cycleAddress[cN]];
        for (j=1; j<cycleSize[cN]; j++) atomCycle[cycleAddress[cN]+j-1]=atomCycle[cycleAddress[cN]+j];
        atomCycle[cycleAddress[cN]+cycleSize[cN]-1]=aA;
        test=(atomDefine[atomCycle[cycleAddress[cN]]]>0) &&
        (atomDefine[atomCycle[cycleAddress[cN]+cycleSize[cN]-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;j<cycleSize[cN]-maxAtDef; j++) {
//          for each undefined atom from selected cycle}
        //atom is added to priority list}
        dsATN[currNumDef]=atomCycle[cycleAddress[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[cycleAddress[cN]+maxAtDef-1];
        dsNA2[currNumDef]=atomCycle[cycleAddress[cN]];
	    dsSC[currNumDef]=cycleSize[cN]-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<int>& cycleSize, std::vector<int>& cycleAddress, 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 (cycleSize[i]<j) {
      rC=i;
      j=cycleSize[i];
    };
    if (rC>0) i=atomCycle[cycleAddress[rC]]; 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];
};

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

  xv=0; yv=1;
  nBondNo=0;
  testBad=false;
  testOK=true;
  testStore=false;
  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 (! testStore) {
          //Save
          blStore.clear();
		  for (j=0; j<rs; j++) blStore.push_back(bondList[j]);
          testStore=true;
        } 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/(double)nAtoms();
      y=y/(double)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) 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
  return result;
};
*/

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) {

  std::vector<int> dsATN(NBONDSMAX);
  std::vector<int> dsTP(NBONDSMAX);
  std::vector<int> dsSC(NBONDSMAX);
  std::vector<int> dsNA1(NBONDSMAX);
  std::vector<int> dsNA2(NBONDSMAX);
  /*
  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;
  std::vector<int> atomCycle(3*nBonds());
  std::vector<int> cycleDescription(3*nBonds());
  std::vector<int> cycleAddress(nBonds());
  std::vector<int> atomDefine(NBONDSMAX);
  std::vector<int> cycleSize(NBONDSMAX);
  std::vector<int> cycleDefine(NBONDSMAX);
  std::vector<int> tempArray(NBONDSMAX);
  double r,cf,fi,ux,uy,ux1,uy1,ux2,uy2,uvX,uvY,c,s;
  double xCenterOld,yCenterOld,xCenterNew,yCenterNew,bondLengthOld,bondLengthNew;
  neigbourlist 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;
  defineAtomConn();
  allAboutCycles();

  test=true;
  defineBondConn(bk);
  //{Start clean for LISTATOMCLEAN and LISTBONDCLEAN atoms and bonds}
  cycleAddress[0]=0;
  baseCycle=0;
  cs=0;
  ux=0;
  uy=0;
  uvX=0;
  uvY=0;
  atomSecond=0;

  for (i=0; i<bondClean; i++) {
    vaweBond(listBondClean[i],bk,cs,atomDefine); //If I-th bond belongs to cycle}

    if (cs>0) {
      canonizeCycle(cs,atomDefine);
	  test=false;
	  for (j=0; j<baseCycle; j++) if(cycleSize[j] == cs) {
        test=true;
		for (k=0; k<cycleSize[j]; k++) if (atomDefine[k] != cycleDescription[cycleAddress[j]+k]) {
          test=false;
		  break;
		};
		if (test) break;
	  };
      if (! test) {     //{not found-the cycle is added to cycle's list}
        baseCycle++;
        cycleAddress[baseCycle]=cycleAddress[baseCycle-1]+cs;
        cycleSize[baseCycle-1]=cs;
        for (j=0; j<cs; j++) cycleDescription[cycleAddress[baseCycle-1]+j]=atomDefine[j];
      };
    };

  };

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

    if ((getBond(k)->at[0]==getBond(j)->at[0]) || (getBond(k)->at[0]==getBond(j)->at[1])) atomCycle[cycleAddress[i]+0]=getBond(k)->at[0];
	else atomCycle[cycleAddress[i]+0]=getBond(k)->at[1];
	n=atomCycle[cycleAddress[i]+0]; //previoulsly putted atom
    for (j=1; j<cycleSize[i]; j++) {
      k=cycleDescription[cycleAddress[i]+j];
	  if (getBond(k)->at[0]==n) atomCycle[cycleAddress[i]+j]=getBond(k)->at[1]; else atomCycle[cycleAddress[i]+j]=getBond(k)->at[0];
	  n=atomCycle[cycleAddress[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) {
      for (i=0; i<nAtoms(); i++) tempArray[i]=0;
      for (i=0; i<atomClean; i++) {
        k=listAtomClean[i];
        tempArray[k]=1;
      };
      n=0;
      for (i=0; i<nAtoms(); i++) if (tempArray[i]==0) {
		xCenterOld=xCenterOld+getAtom(i)->rx;
        yCenterOld=yCenterOld+getAtom(i)->ry;
        n++;
      };
      xCenterOld=xCenterOld/(double)n; yCenterOld=yCenterOld/(double)n;
      for (i=0; i<nBonds(); i++) tempArray[i]=0;
      for (i=0; i<bondClean; i++) {
        k=listBondClean[i];
		tempArray[k]=1;
      };
      n=0;
      bondLengthOld=1E10;
      r1=0;
      for (i=0; i<nBonds(); i++) if (tempArray[i] == 0) {
        r=this->bondLength(i);
        if (r < bondLengthOld) bondLengthOld=n;
        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;

  };

  for (i=0; i<nAtoms(); i++) atomDefine[i]=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;
  i=0;
  while (currNumDef<atomClean) {
    //start recursion-priority list formation}
    defC(currNumDef,baseCycle,atomClean,cycleDefine,atomDefine,atomCycle,cycleAddress,cycleSize,dsATN,dsTP,dsSC,dsNA1,dsNA2);
    defA(currNumDef,atomClean,spn,baseCycle,atomDefine,listAtomClean,cycleDefine,cycleSize,cycleAddress,atomCycle,dsATN,dsTP,dsNA1,dsNA2);
    i++;
  }; //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}

          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;
  };
};


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;
  int nB1;

  if (cHB < 0) return;

  test=makeFragment(nB1,list1,getBond(cHB)->at[1],getBond(cHB)->at[0]);
  if (nB1 > 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<nB1; 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) {
  int nB;
  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(nB,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<nB; i++) { //coordinates change
    n=list[i];
    getAtom(n)->rx=getAtom(n)->rx+xc1+r*xc;
    getAtom(n)->ry=getAtom(n)->ry+yc1+r*yc;
  };
};

bool compareAtoms(int a1, int a2, const std::vector<std::vector<int> *> aeqList) {
  std::vector<int> * l1;
  std::vector<int> * l2;
  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 == NULL) || (l2 == NULL)) 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 neigbourlist 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]];
        l3=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;
  neigbourlist 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;
  };

  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();
  delete(em);
};

bool incrementValues(std::vector<int>& currentValues, const std::vector<int> maxValues) {
  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;
      return result;
    } else currentValues[i]=0;
   };
  return result;
};



int TSimpleMolecule::correctOverlapped() {
  double r;
  TSimpleMolecule * smCopy=new TSimpleMolecule();
  TSimpleMolecule * bestStore=NULL;
  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;
  int nn;


  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)  {  //multiply bonds rotation...
    smCopy->moleculeCopy(*this);

    for (i=0; i<rotBondList.size(); i++) rotBondList[i]=0;
    for (i=0; i<nBonds(); i++) if (getBond(i)->db == 0) {
      at1=getBond(i)->at[0];
      at2=getBond(i)->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;
	  };
	};

    nn=0;
    for (i=0; i<rotBondList.size(); i++) if (rotBondList[i] == 1) nn++;
    if ((nn <= nRotBondsMax) && (nn>0)) {  //All possible combinations of rotations...
      currentValues.resize(nn);
      maxValues.resize(nn);
      for (i=0; i<nn; i++) {
        currentValues[i]=0;
        maxValues[i]=1;
      };
      bestStore= new TSimpleMolecule();
      bestStore->moleculeCopy(*smCopy);
      test=true;
      while (test && (k>0)) {
        moleculeCopy(*smCopy);
        n=0;
        for (i=0; i<rotBondList.size(); i++) if (rotBondList[i] != 0) {
          n++;
          if (currentValues[n-1] == 1) flipSmall(i);
        };
        kk=hasOverlapped(r,false);
        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
  if (smCopy != NULL) delete(smCopy);
  if (bestStore != NULL) delete(bestStore);

  return result;
};

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

  void deleteIntElement(std::vector<int> * source, int index) {
    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:
    neigbourlist queryBK;
    neigbourlist structureBK;
    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;

    bool aEQ[NATOMSMAX][NATOMSMAX];
    bool bEQ[NBONDSMAX][NBONDSMAX];
    void removeHydrogen(std::vector<int> * qHydr, std::vector<int> * qEnumerator);
    void atomBondChange();
    bool stereoBondChange();
    void directBondAss(int& bnq, bool& test, bool& test1, const bool beq[NBONDSMAX][NBONDSMAX],
      const bool aeq[NATOMSMAX][NATOMSMAX], 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 neigbourlist bqconn, const neigbourlist 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=NULL;
    };

    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;
  std::vector<int> bTested(NBONDSMAX);
  std::vector<int> bList(NBONDSMAX);
  std::vector<int> aList(NBONDSMAX);
  TSingleAtom * sa=NULL;
  TSingleBond * sb=NULL;
  int result=0;



  //return result;
  //Analizing on boundaries}
  k2=1; k1=1;
  if ((nAtoms()+naDEF) >= NATOMSMAX) {
    result=1;
    return result;
  }

  //Analizing of bond's
  nb=0;
  emBLength=0;
  for (i=0; i<eMolecule.nAtoms(); i++) bList[i]=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;

  if ((nb+nBonds()) >= NBONDSMAX) {
    result=2;
    return result;
  }
  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;
  int naNum;
  bool test,test1,test2;
  std::vector<int> list(NBONDSMAX);
  std::vector<int> listA(NBONDSMAX);
  std::vector<int> listB(NBONDSMAX);
  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;
  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(naNum,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,naNum,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,naNum,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;
  int na;
  bool test;
  TSingleAtom * sa;
  TSingleBond * sb;
  TEditedMolecule * result=NULL;

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


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

  result= new TEditedMolecule();
  if (na > 0) for (i=0; i<na; i++) {
    sa=this->getAtom(list[i])->clone();
	result->addAtom(sa);
    if (enumerator != NULL) (*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
  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,NULL);  //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);
  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 != NULL) {
    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 != NULL) (*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 != NULL) && (i<(nAtoms()-1))) deleteIntElement(qHydr,i);

      if (i1>i)  i1=i1-1;
      //shift of attribute's arrays
      if (qEnumerator != NULL) {
        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 != NULL)) (*qHydr)[i1]=(*qHydr)[i1]+1;
      //counter of explicitly defined hydrogens
      i--;
    };
    i++;
  };
  if (test1) {
    defineAtomConn();
    //Inverse enumerator creation... New QA->OldQA array}
    if (qEnumerator != NULL) {
      //??? 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, const bool beq[NBONDSMAX][NBONDSMAX],
  const bool aeq[NATOMSMAX][NATOMSMAX], 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 neigbourlist bqconn, const neigbourlist 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
  //BQCONN,BSCONN-for each atom containes list of connected bonds in query and
  //              structure respectively.
  //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 successfull, 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,stereoS;
  int aq1,aq2,as1,as2,j1,i1;
  int ii;
  bool result=false;
  bool whiletest1,whiletest2;

  if ((molecule1==NULL) || (! 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());
  for (int i=0; i<molecule1->nAtoms(); i++) for (j=0; j<nAtoms(); j++) aEQ[i][j]=false;
  for (int i=0; i<molecule1->nBonds(); i++) for (j=0; j<nBonds(); j++) bEQ[i][j]=false;
  cycleNumber=0;
  //Formula filter
  test2=false;
  /*
  if (fBruttoFormula.nD>0) {
    j=0;
    if (molecule1.fBruttoFormula.nD>0) {
      whiletest1=true;
      while (whiletest1) {
        j++; k=0;
        test1.value=(fBruttoFormula.eList[j]==104) && (! fIOPT11);
        whiletest2=true;
        if ((fBruttoFormula.eList[j] != 1) && (! test1.value)) while (whiletest2) {
          k++;
          test2=((fBruttoFormula.eList[j]==molecule1.fBruttoFormula.eList[k])
          && (fBruttoFormula.eNumber[j]<=molecule1.fBruttoFormula.eNumber[k]));
          whiletest2=test2 || (k==molecule1.fBruttoFormula.nD);
          whiletest2=! whiletest2;
        } else test2=true;
        whiletest1=(! test2) || (j==fBruttoFormula.nD);
        whiletest1=! whiletest1;
      };
    } else test2=false;
  } else test2=true;
  */ test2=true;   //turn of molecular formula filter

  molecule1->fIOPT11=fIOPT11;
  molecule1->fIOPT12=fIOPT13;
  molecule1->fIOPT13=fIOPT13;
  if (test2) {

    //{R/S/Z/E description are removed: they are not used in substructure search}
    if (fIOPT13) molecule1->atomBondChange(); //Semipolar bond conversion
    molecule1->defineAtomConn();
    molecule1->defineBondConn(structureBK);
    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 != NULL) {
        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,queryBK,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 != NULL) && (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;
  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();
//  virtual ~TemplateRedraw() {
//    clear();
//  };
  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:
  static std::vector<TEditedMolecule *> queryData;
  void clear();
  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, int alCount, PartFragmentDefinition& pf, double offset);
  void arrangeMolecules(std::vector<PartFragmentDefinition *>& extendedList, double aspOptimal);
  bool loadTemplates();
};

//Initialization of static member variable
std::vector<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.push_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
  {
    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.push_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=(TEditedMolecule *)queryData[i];
	  em2=(TEditedMolecule *)queryData[j];
	  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) {
	    queryData[i]=em2;
	    queryData[j]=em1;
      }
    }
  }
}

void TemplateRedraw::clear() {
  for (int i=0; i<queryData.size(); i++) {
    delete(queryData[i]);
  };
};


bool TemplateRedraw::internalBondsPresent(TEditedMolecule * mQuery, TSimpleMolecule * mStructure) {
  std::vector<int> aList(mStructure->nAtoms());
  std::vector<int> bList(mStructure->nBonds());
  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(NATOMSMAX);
  int i,n,n1,n2;
  bool test;
  double rX,rY,r;
  std::vector<double> coorX(NATOMSMAX);
  std::vector<double> coorY(NATOMSMAX);
  double xMin,xMax,yMin,yMax;



  xSize=0;
  ySize=0;
  c1=1; s1=0;
  xCenter=0; yCenter=0;
  nVert=0;
  for (i=0; i<sm->nAtoms(); i++) atomList[i]=false;
  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(NATOMSMAX);
  int i,j,n,n1,n2,w;
  bool test;

  if (atomList == NULL) {
    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, int alCount, 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<alCount; 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;
  };
  if ((xMax == xMin) && (yMax == yMin)) {
    for (i=0; i<alCount; i++) {
      n=(*atomList)[i];
      sm->getAtom(n)->rx=(pf.fragLeft+pf.fragWidth/2);
      sm->getAtom(n)->ry=(pf.fragTop+pf.fragHeight/2);
    };
    return;
  };
  if (xMin == xMax) {         //y should be scaled
    scale=(pf.fragHeight-2*offset)/(yMax-yMin);
  } else if (yMin == yMax) { //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<alCount; 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) {

  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=NULL;
  int i, j, k, fragmentAN, templateAN;
  int atomClean;
  int bondClean;
  std::vector<int> listAtomClean(NBONDSMAX);
  std::vector<int> listBondClean(NBONDSMAX);
  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 ((TEditedMolecule *)queryData[i]->fragmentSearch(&sm,NULL)) {
    em=(TEditedMolecule *)queryData[i];
    if (! internalBondsPresent(em,&sm)) {
      result=i+1;
      break;
    };
    em=NULL;
  };


  if (em == NULL) {
    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
    listAtomClean.resize(NBONDSMAX);
    listBondClean.resize(NBONDSMAX);
    templateAtomNumber.resize(0);
    fragmentAtomNumber.resize(0);
    //Atom list formation
    atomClean=0;
    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[atomClean]=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) && (tm.getAtom(tm.getBond(i)->at[0])->nb > 1) && (tm.getAtom(tm.getBond(i)->at[1])->nb > 1)) {   //acyclic bond
          test=true;
          emTemplate=new TEditedMolecule();
          if (tm.getBond(i)->at[1] >nFound) fragmentAN=tm.getBond(i)->at[1]; else fragmentAN=tm.getBond(i)->at[0];  //Error is absent! Really 2-nd atom is compared in both operators!
          if (tm.getBond(i)->at[1] >nFound) templateAN=tm.getBond(i)->at[0]; else templateAN=tm.getBond(i)->at[1];
		  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,NULL);
          smRest=tm.extractFragment(templateAN,NULL);
          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;
    for (i=0; i<atomClean; i++) listAtomClean[i]=nFound+i;
    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[bondClean]=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;
      };
      naStore=tm.nAtoms();

      tm.refofs=sm.refofs;

      tm.addAsTemplate(*emTemplate,templateAN,fragmentAN,-1,-1,true);
      if ((naStore+emTemplate->nAtoms()) == tm.nAtoms()) for (j=0; j<emTemplate->nAtoms(); j++) {
        tm.getAtom(naStore+j)->enumerator=emTemplate->getAtom(j)->enumerator;
      };
    };
    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(NATOMSMAX);
  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




  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(w,atomList,i,-1);
    for (j=0; j<w; j++) {
      n=atomList[j];
      atomTested[n]=1;
    };
    sm=smCopy.extractFragment(i,NULL);
    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);

     //Contrary to Delphi project - block of storing double-bonds is absent here.
     //I need to create AnalizeZE rpocedure to handle double-bond
      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+1;
    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
  atomList.resize(NATOMSMAX);
  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(w,atomList,pf->fragFirstAtomNo,-1);
      rescaleSingleFragment(&smCopy,&atomList,w,*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 !!!!
    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
     sucessfukk 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) {
  TSimpleMolecule sm;
  OBAtom * atom;

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

  TemplateRedraw tr;
  tr.redrawFine(sm);
  for (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);
//	ofs<<sm.getAtom(i-1)->rx<<" "<<sm.getAtom(i-1)->ry<<endl;
  };
  sm.getMolfile(ofs);
};

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

  sm.readOBMol(pmol);

  TemplateRedraw tr;
  tr.redrawFine(sm);
  for (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) {

  TSimpleMolecule 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,NULL);
  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,NULL);
  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;
  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;
};


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 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)*/;
            };
          };
        };
      };
    };
  };
};

bool restoreDoubleBonds(TEditedMolecule& sm, bool putEither/*, const std::vector<int>eqList*/) {
  bool hasStereoDouble=false;
  bool hasAcyclic=false;
  bool result=false;
  int i,j,an,an1,an2,bn2,bn3,n;

  for (i=0; i<sm.nBonds(); i++) {
    if (sm.getBond(i)->bstereo != 0) hasStereoDouble=true;
    if (sm.getBond(i)->db <=1 ) hasAcyclic=true;
  };
    //Flip bonds to show Z/E orientation
  if (hasStereoDouble) for (i=0; i<sm.nBonds(); i++) if (sm.getBond(i)->bstereo != 0) {
    //try to calculate...
    if (sm.getBond(i)->at[0] < sm.getBond(i)->at[1]) {
      an1=sm.getBond(i)->at[0];
      an2=sm.getBond(i)->at[1];
    } else {
      an2=sm.getBond(i)->at[0];
      an1=sm.getBond(i)->at[1];
    };
    //an1 - minimal atomic number; an2-next
    //search for minimal an, connected to an1
    an=10000000;
    for (j=0; j<sm.getAtom(an1)->nb; j++) {
      n=sm.getAtom(an1)->ac[j];
      if ((n != an2) && (n < an)) an=n;
    };
    //search for corresponding bn
    bn2=-1;
    for (j=0; j<sm.nBonds(); j++) if (((sm.getBond(j)->at[0] == an1) && (sm.getBond(j)->at[1] == an)) || ((sm.getBond(j)->at[1] == an1) && (sm.getBond(j)->at[0] == an))) {
      bn2=j;
      break;
    };
    //search for minimal an, connected to an2
    an=10000000;
    for (j=0; j<sm.getAtom(an2)->nb; j++) {
      n=sm.getAtom(an2)->ac[j];
      if ((n != an1) && (n < an)) an=n;
    };
    bn3=-1;
    for (j=0; j<sm.nBonds(); j++) if (((sm.getBond(j)->at[0] == an2) && (sm.getBond(j)->at[1] == an)) || ((sm.getBond(j)->at[1] == an2) && (sm.getBond(j)->at[0] == an))) {
      bn3=j;
      break;
    };
    if ((bn2 >= 0) && (bn3 >= 0)) {
      n=sproduct(sm,i,bn2,bn3);
      n=3-n;
      if (n != sm.getBond(i)->bstereo) {
        sm.flipSmall(i);
        result=true;
      };
    };
  };

  //Put Either bonds where no stereodescriptors
  //Exception v etom bloke. Iskat' oshibku
/*
  if (hasStereoDouble || (putEither && hasAcyclic)) {
    if (equivalentList != null) eqList=equivalentList; else eqList=new Listar(0);
    ChainRotate.makeEquivalentList(sm,eqList,false);
    for (i=1; i<=sm.fBond.maxIndex(); i++) if ((sm.fBond.getTB(i) == 2)  && (sm.fBond.getDB(i) < 2) && (sm.fBond.getBStereo(i) == 0)) {
      an1=sm.fBond.getAT(i,1);
      an2=sm.fBond.getAT(i,2);
      test=(sm.fAtom.getNB(an1) > 1) && (sm.fAtom.getNB(an2) > 1);
      n=-1;
      if (test) for (j=1; j<=sm.fAtom.getNB(an1); j++) {  //if equivalent substitutors are at the first atom
        k=sm.fAtom.getAC(an1,j);
        if (k != an2) {
          if (n < 0) n=eqList.getValue(k); else {
            if (n == eqList.getValue(k)) test=false;
          };
        };
      };
      n=-1;
      if (test) for (j=1; j<=sm.fAtom.getNB(an2); j++) {  //if equivalent substitutors are at the second atom
        k=sm.fAtom.getAC(an2,j);
        if (k != an1) {
          if (n < 0) n=eqList.getValue(k); else {
            if (n == eqList.getValue(k)) test=false;
          };
        };
      };
      if (test) {  //equivalent substitutors were not found-make bond either
        at1=0; at2=0;
        for (j=1; j<=sm.fAtom.getNB(an1); j++) {
          k=sm.fAtom.getAC(an1,j);
          if ((k != an2) && (sm.fAtom.getAStereo(k) == 0)) {
            at2=k;
            if (sm.fAtom.getNB(k) == 1) at1=k;
          };
        };
        if (at1 == 0) {
          for (j=1; j<=sm.fAtom.getNB(an2); j++) {
            k=sm.fAtom.getAC(an2,j);
            if ((k != an1) && (sm.fAtom.getAStereo(k) == 0)) {
              at2=k;
              if (sm.fAtom.getNB(k) == 1) at1=k;
            };
          };
          n=an2;
        } else n=an1;
        if (at1 == 0) at1=at2;
        //Search for bond between at1 and n
        for (j=1; j<=sm.fBond.maxIndex(); j++) if (((sm.fBond.getAT(j,1) == at1) && (sm.fBond.getAT(j,2) == n)) || ((sm.fBond.getAT(j,2) == at1) && (sm.fBond.getAT(j,1) == n))) {
          sm.fBond.setTB(j,(byte)11);
          break;
        };
      };
    };
  };
*/
  return result;
}

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=restoreDoubleBonds(sm,false);
    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> allAtomList(NATOMSMAX);
	std::vector<int> atomList(NATOMSMAX);
	std::vector<int> bondList(NBONDSMAX);
    OBAtom * atom;
	int i,n,at,atEx,na,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;
	};
	for (i=0; i<sm.nAtoms(); i++) allAtomList[i]=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];
	};
	na=0;
	if (sm.makeFragment(na,atomList,at,atEx)) {
	  //addition of atom in non-cleaned fragment at last position
	  atomList[na]=atEx;
      na++;
      for (i=0; i<na; 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[nb]=i;
		nb++;
	  };
	  sm.redraw(atomList,bondList,na,nb,3,atEx,bondN,false);
	  //Setting OBMOL coordinates
	  for (int i=0; i<na; 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.
