	//itesttime=true

/*
code1.js  --load prior to code2.js or codep.js and periodic.js, info.js and mo.js ;provides mo() and creates data structures MO and other lists

bh 9:09 AM 7/9/2004 added more vibrational modes

this and associated .JS, .XLS, .MO, .PDF, .MOL files copyright 2001,2003 Robert M. Hanson hansonr@stolaf.edu and Scot Wherland scot_wherland@wsu.edu

Glist, METHOD, RA, ABBR are all defined in info.js

  commandline: ?query=...&shape=...&method=...&r=1(range)&r1=[min]&r2=[max]&d=1(detail)1&c=1(centered)

?id=FOJBUB02
 
general data format:

//mo("(BRC6H4)BR2AS-S1",3,"(BRC6H~1,As;C1999;Br2341;2351","CBr951;Br978;CBr995","I.A.Litvinov,V.A.Naumov,N.A.Chadaeva,Zh.Strukt.Khim.,27,185-1,1986","x","FAFWAK","As(BrPh)Br2;dibromo(2-bromophenyl)arsine;")
molfile,geom#, "pdfroot,centeratom;bondinfo",angleinfo,ref,method,"CCDCcode or PDBcode","form;name"

*/


slog="Loading database. This may take a few seconds. . ."
status=slog

chemsyms="H HeLiBeB C N O F NeNaMgAlSiP S ClArK CaScTiV CrMnFeCoNiCuZnGaGeAsSeBrKrRbSrY ZrNbMoTcRuRhPdAgCdInSnSbTeI XeCsBaLaCePrNdPmSmEuGdTbDyHoErTmYbLuHfTaW ReOsIrPtAuHgTlPbBiPoAtRnFrRaAcThPaU NpPuAmCmBkCfEsFmMdNoLrDbJlRfBhHnMt" 
NONMETALS=" H He B C N O F Ne Si P S Cl Ar Ge As Se Br Kr Sb Te I Xe At Rn "
FIRSTTEN=chemsyms.substring(0,20)
GASLIST=" uv ed mw "

//see initinfo() for search globals


function newElem(n,sym){	//overloaded in codep.js
 //just for when used without codep.js
}

//MO data

MO=new Array()	//uncompressed MO data; one per structure
MOpt=new Array()	//pointer for .XXX refs
//X-ref to element list

HasMO=new Array()  //(iscentral:file) 1:CIF3-1.mol 0:F3CIF4-1.mol
BondList=new Array()
ShapeList=new Array()
DistList=new Array()
sourcelist=";CCDC;NIST;PDB"
methodlist=""
MethodList=new Array()
Modelist=new Array()
TheList=new Array()

ifirstone=0
lastbondi=-1
shapelist="0;"
missingrefs=""

ismodatainitialized=0
ndata=0		//number of DATA records
nstruc=0	//number of structures
sort1=0
sort2=0



function fixname(s){
 for(var i in ABBRS){if(s.indexOf(i)>=0){s=s.replace(rAbbrs[i],ABBRS[i])}}
 s=s.replace(/\~/g,"^")
 while(s.indexOf("^")>=0)s=s.replace(/\^/,"<SUP>").replace(/\^/,"</SUP>")
 s=s.replace(/\-/g,"- ")
 return s
}

sdigits="0123456789"
snosub=",#("

function fixformula(sform,isclean){
 sform=sform.replace(/\~/g," ") //same formula, different name
 if(sform.indexOf("<SU")>=0){
	if(isclean){
		sform=sform.replace(/\<SUP\>/g,"(").replace(/\<\/SUP\>/g,")").replace(/\//g,"").replace(/\<SUB\>/g,"")
	}
	return sform
 }
 var s=""
 var sf=""
 var slast=" "
 var isdigit=0
 var isnosub=0
 var wasdigit=0
 for (var i=0;i<sform.length;i++){
  s=sform.charAt(i)
  isdigit=(sdigits.indexOf(s)>=0)
  sf=sf+(slast!=" " && isdigit?"_"+s+"@":s)
  if(wasdigit && (s=="+"||s=="-"))sf=sf.substring(0,sf.length-4)+"^"+(slast=="1"?"":slast)+s+"$"
  slast=(snosub.indexOf(s)>=0?" ":s)
  wasdigit=isdigit
 }
 sf=sf.replace(/\@\_/g,"").replace(/\_1\@/g,"")
 if(isclean){
	sf=sf.replace(/\@|\_/g,"").replace(/\^/g,"(").replace(/\$/g,")")
 }else{
	sf=sf.replace(/\_/g,"<SUB>").replace(/\@/g,"</SUB>").replace(/\^/g,"<SUP>").replace(/\$/g,"</SUP>")
 }
 return sf
}

//elements of MO[] *don't mess with these 
ROOT=0
FORMULA=1
NAME=2
CODE=3
SHAPE=4 // *
ISHAPE=5
METHOD=6
MOLFILE=7
CENTER=8 // *
STRUCTURE=9
 ATOMS=0
 BONDS=1
  DESC=0
  VAL=1
 ANGLES=2
  DESC=0
  VAL=1
PDBFILE=10
REF=11
FLAGS=12
 ISGAS=1
 FIRSTROWCENTER=2
 HASMETAL=4
 LEVEL1SHAPE=8
 LEVEL2SHAPE=16
 LEVEL3SHAPE=32
 ANYSHAPE=32+16+8
 SMALLMOLECULE=64
 ISPDF=128
TABLEPT=13
TABLEPREV=14
TABLENEXT=15
VIBMODEL=16
VIBINFO=17
MODELIST=18
DATA=19
THISBONDTYPE=20
THISBONDLEN=21
NOF=22
SRC=23
 SRC_OTHER = ""
 SRC_CCDC = "ccdc"
 SRC_NIST = "nist"
 SRC_PDB = "pdb"
 
function prescreen(elist,mode,moreinfo){
 //mode=1 ==> center only
 //mode=-1 ==> moreinfo=thisqgeom
 //mode=-2 ==> moreinfo=thisqmethod
 //mode=-3 ==> moreinfo=searchtext
 //mode=-4 ==> moreinfo=filenames separated by commas
 //mode=-5 ==> morerinfo=thisqsrc
 if(!elist && !moreinfo)return "0"
 if(!mode)mode=0
 var t=new Date()
 var slist=";"
 var s=""
 var L 
 var n=0
 var i=0
 var S=new Array()
 var H=new Array()
 var isshape=(mode==-1)
 var ismethod=(mode==-2)
 var issrc=(mode==-5)
 var sformula=""
 if(mode>=0)for(var i=0;i<MO.length;i++)MO[i][THISBONDLEN]=0
 if(mode==-5){
	moreinfo=moreinfo.toLowerCase()
	if(elist)elist=","+elist+","
	var M;
	for(var i=0;i<MO.length;i++){if((M=MO[i])[FLAGS]){
		s=M[CENTER]
		if((!elist||elist.indexOf(","+s+",")>=0) && M[SRC]==moreinfo){
			slist+=s+":"+i+";"
			n++
		}
	}}
 }else if(mode==-4){
	S=moreinfo.split(",")
	for(var j=0;j<S.length;j++){
		i=MOpt["."+S[j]]
		slist+=":"+i+";"
		n++
	}
 }else if(mode==-3){
	moreinfo=moreinfo.toLowerCase()
	if(moreinfo.substring(0,5)=="form:"){
		sformula=moreinfo.substring(5,moreinfo.length)
		moreinfo="form"
	}else if(moreinfo.substring(0,5)=="file:"){
		sformula=moreinfo.substring(5,moreinfo.length)
		moreinfo="file"
	}
	if(elist)elist=","+elist+","
	var M;
	for(var i=0;i<MO.length;i++){if((M=MO[i])[FLAGS]){
		s=M[CENTER]
		if((!elist||elist.indexOf(","+s+",")>=0) && searchtext(M,moreinfo,sformula)){
			slist+=s+":"+i+";"
			n++
		}
	}}
 }else if(elist.indexOf("-")<0){
	S=elist.split(",")
 	for(var i=0;i<S.length;i++){
	 if(isshape){
		if((L=ShapeList[moreinfo])&&(L=L[S[i]]))n+=L
	 }else if(ismethod){
		if((L=MethodList[moreinfo])&&(L=L[S[i]]))n+=L.length
	 }else{
		H=HasMO[S[i]]
		if(H){
			for(var j=0;j<H.length;j++){
				s=(mode?H[j]:H[j].substring(1,5))+";"
				if(slist.indexOf(s)<0 && (!mode||s.charAt(0)=="1")){
					n++
					slist+=s
				}
			}
		}
	 }
	}
 }else{ //bond search
	S=elist.split("-").sort()
	if(!S[0])return prescreen(S[1])
	if(!(H=BondList[S[0]])||!(H=H[S[1]]))return "0 "+elist
	for(var j=0;j<H.length;j++){
		i=H[j][0]
		s=":"+i+";"
		if(slist.indexOf(s)<0){
			n++
			slist+=s
			MO[i][THISBONDLEN]=H[j][1]
		}
	}
 }
 s=n+" "+elist+(mode==1?" centered":mode<0?" "+mode+" "+moreinfo:"")+" ms="+((new Date())-t)+slist
 return s
}

function addMethod(meth,i,acent){
	if(meth=="spec")meth="uv"
	var S=meth.split(",")
	for(var j=0;j<S.length;j++){
		var m=S[j]
		if(GASLIST.indexOf(m)>=0)MO[i][FLAGS]|=ISGAS
		if(!MethodList[m])MethodList[m]=new Array()
		if(!MethodList[m][acent])MethodList[m][acent]=new Array()
		MethodList[m][acent][MethodList[m][acent].length]=i
	}
}

function addShape(ig,s,i,a){
	//i not used

	if(shapelist.indexOf(";"+ig+";")<0)shapelist+=ig+";"

	if(!ShapeList[s])ShapeList[s]=new Array()
	if(!ShapeList[s][a])ShapeList[s][a]=0
	ShapeList[s][a]++
}

function checkmoflags(acenter,formula,shape){
 var iflags=(FIRSTTEN.indexOf(acenter)>=0?FIRSTROWCENTER:0) 
 if((iflags & FIRSTROWCENTER)==0 && mustbe1strowcenter)return 0
 var i=shape.indexOf("X-ar")
 if(cpshapesonly && i<0||nocp && i>=0)return 0
 if(LEVEL1SHAPES.indexOf(shape)>=0){
	if(nolevel1shapes)return 0
	iflags|=LEVEL1SHAPE
	if(onlysmallmolecules && (formula.replace(/\(CH3\)/,"").indexOf("(")>=0||formula.indexOf("11")>=0))return 0
	iflags|=SMALLMOLECULE
 }else if(LEVEL2SHAPES.indexOf(shape)>=0){
	iflags|=LEVEL2SHAPE
	if(nolevel2shapes)return 0
 }else{
	if(nolevel3shapes)return 0
	iflags|=LEVEL3SHAPE
 }
 return iflags
}

function getandcheckatoms(Atoms){
 var dv=""
 var d=0
 var p=1
 var a=""
 var isextra=0
 //also splits Atom info into name,value
 if(nometals && NONMETALS.indexOf(Atoms[0]+" ")<0)return 0
 for(var j=1;j<Atoms.length;j++){
	dv=Atoms[j]
	if(dv.charAt(0)=="+"){
		dv=dv.substring(1,dv.length)
		isextra=1
	}
	if(dv.length){
		d=parseInt(dv)
		p=0
		if(isNaN(d)){
			p=2
			s=dv.substring(0,2)
			if(chemsyms.indexOf(s)<0)p=1
		}
		s=dv.substring(0,p)
	 	if(nometals && s.length && NONMETALS.indexOf(s+" ")<0)return 0
		if(!isextra)Atoms[j]=[s,parseInt(dv.substring(p,dv.length))]
	}else{
		Atoms[j]=["",0]
	}		
 }
 return 1
}

function getangleinfo(i){
	var M=MO[i]
	var S=M[STRUCTURE]
	S[ANGLES]=new Array()
	if(!M[DATA][1])return
	var slast=M[DATA][2]
	var A=S[ANGLES]
	var acenter=M[CENTER]
	S=M[DATA][1].split(";")
	var dv=""
	var d=0
	var p=0
	var s=""
	var s1=""
	var s2=""
	var nlast=""
	var slist=""
	var nc=0
	for(var j=0;j<S.length;j++){
		dv=S[j]
		if(dv=="")dv=slast+nlast
		d=parseInt(dv)
		if(!isNaN(d))dv=slast+dv
		d=parseInt(dv.substring(dv.length-1,dv.length))
		if(isNaN(d))dv+=nlast
		p=1
		while(p<dv.length && isNaN(parseInt(dv.charAt(p))))p++
		s=dv.substring(p,dv.length)
		d=parseInt(s)
		if(d>180)d=d/10
		s2=dv.substring(0,p)
		slast=s2
		nlast=s
		s1=s2.substring(0,(s2.charAt(1)<"a"?1:2))
		s2=s2.substring(s1.length,s2.length)
		if(s2=="")s2=s1
		if(s1>s2){s=s1;s1=s2;s2=s}
		s=s1+"-"+acenter+"-"+s2+"-"
		if(s1=="C" && s2=="C"){
			nc++
			if(nc>5)d=0
		}
		s1=s+d
		if(d && slist.indexOf(s1)<0){
			A[A.length]=new Array(s,d)
			slist+=s1
		}
	}
}

function getgeomlist(defshape,nsize,onchange){
 var shape=""
 var s=" onchange="+onchange+" onkeyup=\"setTimeout('"+onchange+"',10)\""
 s="<select name=glist size="+(nsize?nsize:1)+(onchange?s:"")+"><option value=\"\""+(defshape?"":" selected")+">any"
 var S=shapelist.substring(0,shapelist.length-1).split(";")
 for(var i=0;i<S.length;i++)S[i]=parseInt(S[i]) 
 S=S.sort(nsort)
 for(var i=1;i<S.length;i++){
	shape=Glist[S[i]]
	if(shape)s+="\n<option"+(defshape && shape==defshape?" selected":"") +">"+shape
 }
 s+="</select>"
 return s
}

function nsort(a,b){
	return(a<b?-1:a>b?1:0)
}

function getmethodlist(defmethod,nsize,onchange){
 var s=" onchange="+onchange+" onkeyup=\"setTimeout('"+onchange+"',10)\""
 s="<select name=mlist size="+(nsize?nsize:1)+(onchange?s:"")+"><option value=\"\""+(defmethod?"":" selected")+">any"
 var S=methodlist.split(";").sort()
 var m=""
 var ssel=""
 for(var i=1;i<S.length;i++){if(S[i]!=m){
	m=S[i]
	ssel=(defmethod && m==defmethod?" selected":"")
	if(METHODS[m]){
		s+="\n<option"+ssel+" value=\""+m+"\">"+METHODS[m]
	}else{
		s+="\n<option"+ssel+" value=\""+m+"\">"+m
	}
 }}
 s+="</select>"
 return s
}

function getsourcelist(defsrc,nsize,onchange){
 var s=" onchange="+onchange+" onkeyup=\"setTimeout('"+onchange+"',10)\""
 s="<select name=srclist size="+(nsize?nsize:1)+(onchange?s:"")+"><option value=\"\""+(defsrc?"":" selected")+">any"
 var S=sourcelist.split(";").sort()
 var m=""
 var ssel=""
 for(var i=1;i<S.length;i++){if(S[i]!=m){
	m=S[i]
	ssel=(defsrc && m==defsrc?" selected":"")
	s+="\n<option"+ssel+" value=\""+m+"\">"+m
 }}
 s+="</select>"
 return s
}

function getstructurename(slist,n){

 //.....:name;...:name;....
 if(!n)n=1
 var ch=(slist.indexOf(":")>=0? ":" : ";")
 var i=parseInt(slist.split(ch)[n])
 return getformula(i)
}

function getformula(i,isclean){
 var s=MO[i][FORMULA]
 var sg=(MO[i][FLAGS]&ISGAS?" (g)":"")
 s=fixformula(s,isclean)+sg
 return s
}

function rootof(i){
	return (MO[i][ROOT]?MO[i][ROOT]:MO[i][MOLFILE].split(".")[0]).toLowerCase()+"."
}

function searchfor(query,prescreenlist){
	var S=new Array()
	var s=""
	var isq=1
	var stext=""
	initinfo(query)
	if(sq=="" && isrange){
		isbondsearch=true
		issearch=true
		isq=false
	}else if(iselementsearch && isrange){
		iselementsearch=false
		isbondsearch=true
		issearch=true
		sq+="-"
	}else if(isbondsearch){
		S=sq.split("-")
		if(S[1]<S[0])sq=S[1]+"-"+S[0]
		sq+="-"
	}else if(iselementsearch){
	}else{
		istextsearch=true
		if(sq.indexOf("|")<0)sq="|"+sq
		stext=sq.split("|")[1].toLowerCase().replace(/\`/g,"+")
		if(stext.toLowerCase().indexOf(".mol")>=0 && stext.toLowerCase().indexOf("file:")<0)stext="file:"+stext
		sq=sq.split("|")[0]
	}

	if(isbondsearch && sq && !prescreenlist)prescreenlist=prescreen(sq)
	if(iselementsearch && !prescreenlist){
		prescreenlist=prescreen(sq.replace(/\-/g,","),iscenter)
	}
	if(istextsearch && !prescreenlist)prescreenlist=prescreen(sq,-3,stext)
	s=getmollist(isq,prescreenlist)
	sheader=(is2atoms && s?"<span class=high>In this data set, the "+sq+(isbondsearch?"  bond":"  angle")+" ranges in length between "+rmin+" and "+rmax+(isbondsearch?" pm":" degrees")+".</span><br>":"")
	sheader=sheader.replace(/\- /,"")
	return s
}

function getmollist(isq,prescreenlist){
	var s=""
	var d=0
	var sout=""
	var isok=0
	var isthisqshape=0
	var isthisqmethod=0
	var isthisqsrc=0
	ifirstone=-1
	var M;
	for(var i=0;i<MO.length;i++){if((M=MO[i])[FLAGS]){
	 isok=false
	 if(!prescreenlist||prescreenlist.indexOf(":"+i+";")>=0){
		isthisqshape=(thisqshape==""||getshape(i)==thisqshape)
		isthisqmethod=(thisqmethod==""||M[METHOD].indexOf(thisqmethod)>=0)
		isthisqsrc=(thisqsrc==""||M[SRC]==thisqsrc)
		if(isthisqshape && isthisqmethod && isthisqsrc){
			if(iselementsearch){
				isok=1
			}else if(isbondsearch){
				isok=checkinfo(M[STRUCTURE][BONDS],isq)
			}else if(istextsearch){
				isok=1
			}
		}
		if(isok){
			sout+=":"+i+";"
			if(ifirstone<0)ifirstone=i
		}
	 }
	}}
	return sout
}

function searchtext(M,stext,swhat){
	if(stext=="form")return (M[FORMULA].toLowerCase()==swhat)
	if(stext=="file")return (M[MOLFILE].toLowerCase()==swhat)
	if(stext=="src")return (M[SRC]==swhat)
	return (M[NAME].toLowerCase().indexOf(stext)>=0||M[FORMULA].toLowerCase().indexOf(stext)>=0||M[CODE].toLowerCase().indexOf(stext)==0||M[REF].toLowerCase().indexOf(stext)>0)
}

function checkinfo(AorB,isq){
	var v=false
	for(var j=0;j<AorB.length;j++){
		var d=AorB[j][VAL]
		var s=AorB[j][DESC]
		if(!isq||s.indexOf(sq)>=0||sq2&&s.indexOf(sq2)>=0){
			if(d>rmax)rmax=d
			if(d<rmin)rmin=d
			if(!isrange||d>=r1 && d<=r2)v=true
		}
	}
	return v
}

///display of records:

function getNistRef(text, code) {
	code=code.substring(2,20)
	return href(text,nistserver.replace(/CODE/,code))
}

function getPdbRef(text,code) {
	return href(text,pdbserver.replace(/CODE/,code))
}

function methrefof(ii){
 var sname=MO[ii][MOLFILE]
 var code=MO[ii][CODE]
 var S=new Array()
 var ref=MO[ii][REF]
 var smeth=MO[ii][METHOD]
 var src=MO[ii][SRC]
 var ispdb=(src==SRC_PDB)
 var isnist=(src==SRC_NIST)
 var isccdc=(src==SRC_CCDC)
 if(isnist)
	code=getNistRef(code, code)
 else if(ispdb && ilinkpdbfiles)
	code=getPdbRef(code, code)
 if(!ref){
	ref="NO REF for "+sname
	missingrefs+=sname+"\n"
 }
 for(var r in RR)ref=ref.replace(RR[r],RA[r])
 ref=ref.replace(/\,/g,", ").replace(/\'/g,"")
 if(METHODS[smeth]){
	smeth=METHODS[smeth]
 }else if(smeth.indexOf(",")>=0){
	S=smeth.split(",")
	smeth=""
	for(var i=0;i<S.length;i++)smeth+=(smeth==""?"":"<br>")+(METHODS[S[i]]?METHODS[S[i]]:S[i])
 }
 var s="<table colpadding=3>"
 s+="<tr><td nowrap valign=top class=info><b>name</b></td><td class=info>"+fixname(MO[ii][NAME])+"</td></tr>"
 s+="<tr><td nowrap valign=top class=info><b>shape</b></td><td class=info>"+getshape(ii)+"</td></tr>"
 s+="<tr><td nowrap valign=top class=info><b>method</b></td><td class=info>"+smeth+"</td></tr>"
 s+="<tr><td nowrap valign=top class=info><b>reference</b></td><td class=info>"+ref+"</td></tr>"

 if(code)s+="<tr><td nowrap valign=top class=info><b>"+(ispdb?"PDB":isnist?"NIST":ccdcref)+" entry</b></td><td class=info>"+code+"</td></tr>"
 if(showmolfilename){
	s+="<tr><td class=info><b>filename</b></td><td class=info><a target=_blank href=data/"+sname+">"+sname+"</a></td></tr>"
	s+="<tr><td class=info><b>direct link</b></td><td class=info><a target=_blank href=./index.htm?list="+sname.split(".")[0]+"&view=1>"+sname.split(".")[0]+"&view=1</a></td></tr>"
 }
 s+="</table>"
 return s
}

function bondinfo(i){

 var S=MO[i][STRUCTURE]
 var s=("distance "+(S.length>BONDS?S[BONDS].join(" pm|distance "):"")+" pm").split("|").sort().join("\n")
 if(!S[ANGLES])getangleinfo(i)
 s+=(S[ANGLES]?"||angle "+S[ANGLES].join("|angle "):"").split("|").sort().join("\n")
 if(s.indexOf(",")<0)return ""
 s=s.replace(/\-\,/g," = ")
 return s
}

function getshape(i){
	return MO[i][SHAPE]
}

function cleantags(s){
	s=">"+s.replace(/\<SUP\>/g,"(").replace(/\<\/SUP\>/g,")").replace(/\<tr/g,"\n<").replace(/\<td/g," <")
	var S=s.split("<")
	s=""
	for(var i=0;i<S.length;i++)s+=S[i].split(">")[1]
	return s.replace(/\&nbsp\;/g," ")
}

function getapplet(pathorinline,src){
 if(usejmol){
	var s='\n<applet name="jmol" code="JmolApplet"'
	//s+='\ncodebase="'+codebase+'"'
	s+='\narchive="JmolApplet.jar" PickCallback="jmolpick"'
	+'\n'+jmoldefaults+'"  mayscript="true" />'
	+'\n<param name="progressbar"   value="true" />'
	if(src){
		s+='\n<param name="load"      value="'+pathorinline+src+'" />'
	}else{
		s+='\n<param name="loadInline"      value="'+pathorinline+'" />'
	}
	s+='\n<param name="script"    value="'+jmolscript+'" />'
	+'\n</applet>'
 	return s
 }else{
	return "<embed "+chimedefaults+" src="+path+src+"></embed>"
 }
}

function getmolinfo(i){
	var s=getformula(i)+"<br><br>"
	s+=methrefof(i)
	s+="\n\n<pre>"+bondinfo(i)+"\n</pre>"
	return s
}

function initinfo(query){

 //search/display globals

	rmin=1000	//data min
	rmax=0		//data max
	sq=fieldof(query,"query")
	r1=fieldof(query,"r1")
	r2=fieldof(query,"r2")
	if(r1.length)r1=parseFloat(r1)
	if(r2.length)r2=parseFloat(r2)
	if(r1<50)r1=r1*100
	if(r2<50)r2=r2*100
	ishowdetail=(fieldof(query,"d")=="1")
	isrange=(fieldof(query,"r")=="1" && r1>=0 && r2>r1)
	iscenter=(fieldof(query,"c")=="1")
	thisqshape=fieldof(query,"shape")
	thisqsrc=fieldof(query,"src").toLowerCase()
	thisqmethod=fieldof(query,"method")
	issearch=((sq+thisqshape+thisqmethod+thisqsrc).length>0)
	var i=sq.indexOf("-")

	istextsearch=(sq.indexOf("|")>=0)
	is2atoms=(i==1||i==2)
	iselementsearch=(!istextsearch && i<0 && sq>="A" && sq<="Zz")
	isbondsearch=(!istextsearch && is2atoms && sq.indexOf("-")==sq.lastIndexOf("-"))
	istextsearch=(istextsearch||sq!="" && !iselementsearch && !isbondsearch)
	iscenter=(iscenter && iselementsearch)
	sheader=""	//displays ranges
	ithispt=0	//pt for table
	ishighlighted=-1
	sq2=""
}initinfo(docsearch)

function jmolpick(){}

function getmoflags(sep){
	var s=""
	if(mustbe1strowcenter)s+=sep+"1st-row centers"
	if(onlysmallmolecules)s+=sep+"small species only"
	if(nometals)s+=sep+"no metals"
	if(cpshapesonly)s+=sep+"aromatic complexes only"
	if(nolevel1shapes && nolevel2shapes){
		s+=sep+"just the really cool shapes"
	}else if(nolevel2shapes && nolevel3shapes){
		s+=sep+"just the six simplest shapes"
	}else{
		if(nolevel1shapes)s+=sep+"no simple shapes"
		if(nolevel2shapes)s+=sep+"no expanded valence"
		if(nolevel3shapes)s+=sep+"standard shapes only"
	}
	return s
}


function listsort(a,b){
	var ia=TheList[a][0]
	var ib=TheList[b][0]
	if(sort1>=0){
		var sa=MO[ia][sort1]
		var sb=MO[ib][sort1]
	}else{
		var sa=ia
		var sb=ib
	}
	if(sa<sb)return -1
	if(sa>sb)return 1
	if(sort2>=0){
		var sa=MO[ia][sort2]
		var sb=MO[ib][sort2]
	}else{
		var sa=ia
		var sb=ib
	}
	return(sa<sb?-1:sa>sb?1:0)
}

function createthelist(slist,isbsearch,bondinfo,atom1,Range){
	var scol1=""
	var scol2=""
	var n=0
	var iprev=-1
	ifirststructure=-1
	TheList=new Array()
	for(var i=0;i<MO.length;i++){
		if(slist.indexOf(":"+i+";")>=0){
			MO[i][TABLEPREV]=iprev
			MO[i][TABLENEXT]=-1
			MO[i][NOF]=(++n)
			if(iprev>=0)MO[iprev][TABLENEXT]=i
			if(iprev<0)ifirststructure=i
			iprev=i
			if(isbsearch){
				if(!MO[i][THISBONDLEN])findbond(i,bondinfo,Range)
				scol1=MO[i][THISBONDTYPE]
				scol1=(isNaN(scol1)?scol1:bondinfo)
				scol2=roundoff(MO[i][THISBONDLEN],0)
			}else{
				scol1=MO[i][CENTER]
				scol2=""
			}
			TheList[TheList.length]=getinfo(i,scol1,scol2)
		}
	}
}

function gettable(isrevised,sortcallback,isbsearch,bondinfo){
	ifirststructure=-1
	if(TheList.length==0)return ""
	var s="sort by: "
	if(isbsearch){
		if(bondinfo.indexOf("-")<0)s+=" \n<label><input type=radio name=sortby value=\"bytype\"  onclick="+sortcallback+"(3) BYT>"+bondinfo+" bonded atoms</label>"
		s+=" \n<label><input type=radio name=sortby value=\"bylength\"  onclick="+sortcallback+"(2) BYL>"+bondinfo+" bond length</label>"
	}else{
		s+="\n<label><input type=radio name=sortby value=\"bycenter\" onclick="+sortcallback+"(0) BYC>center atom</label>"
	}
	s+=" \n<label><input type=radio name=sortby value=\"byshape\"  onclick="+sortcallback+"(1) BYS>shape</label>"

	var isbyshape=(displayorder=="byshape")
	var isbytype=(displayorder=="bytype")
	var isbylength=(displayorder=="bylength"||displayorder=="bycenter" && isbsearch)
	var isbycenter=(!isbyshape && !isbylength && !isbsearch)
	s=s.replace("BYS",(isbyshape?"checked":"")).replace("BYT",(isbytype?"checked":"")).replace("BYC",(isbycenter?"checked":"")).replace("BYL",(isbylength?"checked":""))
	var sortheader=s
	var iblock=0
	ithispt=0
	ishighlighted=-1	
	if(isbycenter){
		sort1=CENTER
		sort2=-1
		iblock=ISHAPE
//		by center, then shape, shape, then thisbond[1] or i, blocked by shape
	}else if(isbyshape){
		sort1=ISHAPE
		sort2=(isbsearch?THISBONDLEN:-1)
		iblock=ISHAPE
//		by shape, then thisbond[1] or i, blocked by shape
	}else if(isbylength){
		sort1=THISBONDLEN
		sort2=-1
		iblock=CENTER
//		by thisbond[1], then i, blocked by center
	}else if(isbytype){
		sort1=THISBONDTYPE
		sort2=THISBONDLEN
		iblock=THISBONDTYPE
//		by thisbond[0], then thisbond[1], blocked by thisbond[0]
	}
	var S=new Array()
	for(var i=0;i<TheList.length;i++)S[i]=i
	S=S.sort(listsort)
	if(S.length<2)sortheader=""
	//TheList[i,s1,s2,s3]  // will be s1 form name s2
	var scaption=""
	var ipt=0
	var s2=""
	var sclass=0
	var sline=""
	var slineprev=""
	var isnew=0
	var ithispt=0
	var iprev=-1
	var n=0
	var s=""
	for(var j=0;j<S.length;j++){
		ipt=S[j]
		i=TheList[ipt][0]
		MO[i][TABLEPREV]=iprev
		MO[i][TABLENEXT]=-1
		MO[i][NOF]=(++n)
		if(iprev>=0)MO[iprev][TABLENEXT]=i
		if(j==0 || (!isbsearch||isbyshape||isbytype) && MO[i][iblock]!=MO[iprev][iblock] )s+="<tr><td colspan=8 bgcolor=#000000></td></tr>"
		sline=TheList[ipt][2]
		if(!ishowdetail && iprev>=0 && MO[i][FORMULA]==MO[iprev][FORMULA]){
			sline="<td class=cCLS></td><td class=cCLS></td>"
		}else{
			slineprev=sline
			sclass=1-sclass
			ithispt=i
		}
		MO[i][TABLEPT]=ithispt
		sline=TheList[ipt][1]+sline+TheList[ipt][3]
		s+="\n<tr>"+sline.replace(/CLS/g,sclass)+"</tr>"
		if(iprev<0)ifirststructure=i
		iprev=i
	}
	s="<tr><td colspan="+(isbsearch?5:4)+">"+sortheader+"</td><td align=center><a onclick=doview() title=\"Click here to view the structures starting with the first one on the list.\">View All</a></td><td colspan=3><input type=checkbox name=chkdetail onclick="+sortcallback+"("+(ishowdetail?-2+") checked":-1+")")+">details&nbsp;&nbsp;&nbsp;</td></tr>"+s
	s="<center><form id=showp name=showp>"+sheader+"<table cellspacing=0>"+s+"\n</table></form></center>"
	return s
}

function getinfo(i,scol1,scol2){
 var s=""
 var st=""
 var sref=""
 var nshown=0
 var ispdb=0
 var smolfile=""
 var sall=""
 var methref=""
 var L=[i,s,s,s]
 var M = MO[i]

	//TheList[i,s1,s2,s3]  // will be s1 form name s2

 var shtml=getformula(i)
 var sthisqname=M[NAME]
 if(shortnamesonly){
	if(sthisqname.length>maxsmallnamelength)sthisqname=""
 }
 var td="<td valign=top class=cCLS"

//center,shape
 s=td+"><img id=tpt0_"+i+" src="+imagedir+"t1.gif></td>"
 s+=td+" valign=top nowrap>"+scol1+"</td>"
 s=s.replace(/\-\</,"<")

 if(scol2)s+=td+" valign=top align=right>&nbsp;"+scol2+"</td>"
 s+=td+" nowrap>&nbsp;<i>"+getshape(i)+"&nbsp;&nbsp;</i></td>"
 L[1]=s

//formula & name
 s=td+" width=150 nowrap><span id=tf"+i+">&nbsp;"+shtml+"&nbsp;&nbsp;</span></td>"
 s+=td+" width=500><span id=tn"+i+">"
 if(sthisqname.length>2)sthisqname=fixname(sthisqname)
 s+=sthisqname
 s+="&nbsp;</span></td>"
 L[2]=s

//links
 s=td+" nowrap>&nbsp;"
 smolfile=M[MOLFILE]
 var src = M[SRC]
 s+=jref("info","doshowtxtinfo("+i+")")+"&nbsp;&nbsp;"
 s+=jref("view","doshowmolinfo("+i+")")+"&nbsp;&nbsp;"
 if (src != "")
   s+= (src == SRC_CCDC ? ccdcref : src == SRC_NIST ? getNistRef("NIST",M[CODE]) 
	: src== SRC_PDB ? getPdbRef("PDB",M[CODE]):"")+"&nbsp;&nbsp;"
 methref=methrefof(i)
 s+="</td>"
 s+=td+">"
 if(M[FLAGS]&ISPDF)s+=href("pdf",moserver+rootof(i)+"pdf")+"&nbsp;&nbsp;"
 if(ilinkmo && M[FLAGS]&ISPDF)s+=href("mo",moserver+rootof(i)+"mo")+"&nbsp;&nbsp;"
 s+="</td>"
 s+=td+"><img id=tpt1_"+i+" src="+imagedir+"t1.gif></td>"
 //detail
 if(ishowdetail){
	st="</tr><tr>"+td+" colspan=8><table><tr>"+td+"></td>"+td+">&nbsp;"+bondinfo(i)+"</td></tr></table>"+methref+"<p>&nbsp;</td>"
	s+=st.replace(/\n/g,"<br>&nbsp;")
 }
 L[3]=s
 return L
}

function doshowmolinfo(i,selectedmode,loadinlineinfo){ //from the user clicking "mol"
	if(!selectedmode)selectedmode=""
	var app=(loadinlineinfo?getapplet(loadinlineinfo):getapplet(molserver,MO[i][MOLFILE]))
	var s=getmolinfo(i,selectedmode)
	highlight(i)
	showthetext(app,s,i,selectedmode) // must be provided elsewhere
}

function doshowtxtinfo(i){
 var s=""
 highlight(i)
 if(isdebug){
	alert("THIS IS FOR DEBUGGING ONLY RIGHT NOW. \n\n"+MO[i][THISBOND]+" MO["+i+"]=\n"+MO[i].join('\n'))
 }else{
	alert(cleantags("STRUCTURE "+(i+1)+":\n\n"+getmolinfo(i)))
 }
 return 
}

function movemoinfo(i,s,iwhat,swhat){
 var j=MOpt[s]
 if(isNaN(j))alert("Problem with "+swhat+" for #"+i+": "+s+" NAME NOT FOUND.")
 MO[i][iwhat]=(isNaN(j)?"???":MO[j][iwhat])
}

function addAtom(a,i,iscenter){
	var n=AtomNum[a]
	if(n){
		Elements[n].hasstruc=true
		if(iscenter){
			if(!Elements[n].iscenter)Elements[n].iscenter=0
			Elements[n].iscenter++
		}
	}
	if(!HasMO[a])HasMO[a]=new Array()
	HasMO[a][HasMO[a].length]=iscenter+":"+i
}

function addBond(a,b,i,d,slist){
	//return ""//: IE 4.9 sec
	var s=""
	var s1=""
	if(a>b){s=b;b=a;a=s}
	s=a+"-"+b+"-"
	s1=s+d
	if(slist.indexOf(s1)>=0)return ""

	//return "" //6.1 sec

	if(slist.indexOf(s)<0){
		if(!BondList[a])BondList[a]=new Array()
		if(!BondList[a][b])BondList[a][b]=new Array()
		BondList[a][b][BondList[a][b].length]=[i,d]
	}
	var A=MO[i][STRUCTURE][BONDS]
	A[A.length]=[s,d]

	//return ""//: IE 9.5 sec

	var n=Math.floor(d/pm_per_bin)+"_"
	var s0=n+s1
	s1=n+s
	if(slist.indexOf(s1)>=0)return s0
	if(!DistList[n])DistList[n]=new Array()
	if(!DistList[n][s])DistList[n][s]=new Array()
	DistList[n][s][DistList[n][s].length]=i
	return s1

	//return//: IE 11.8 sec
}

function mo(mfile,ishape,binfo,ainfo,ref,meth,code,formula_name){
 var S=new Array()
 var i=0
 var j=0
 var s=""
 var slast=""
 var nlast=""
 var s=""
 var n=""
 var dv=""
 var p=0
 var d=0
 var s1=""
 var s2=""
 var Atoms=new Array()
 var M=new Array()
 var alist=""
 var iflags=0
 var slist=""
 var nc=0

 if(arguments.length==0){

	if(ismodatainitialized)return
	ismodatainitialized=true
	for(var i=0;i<MO.length;i++){

		s=MO[i][NAME]
		if(s.charAt(0)==".")movemoinfo(i,s,NAME,"name")
		s=MO[i][REF]
		if(s.charAt(0)==".")movemoinfo(i,s,REF,"reference")

	}
	status="Molecular Structure Explorer loaded in "+(((new Date())-loadtime0)/1000)+" seconds"
	return
 }

 //read structure data
 i=MO.length
 if(i%100==0){
	slog+=" ."
	status=slog
 }
 var Binfo=binfo.split(",")
 var s83=(Binfo[0]!="M"?Binfo[0]:"")
 binfo=Binfo[1]
 var acenter=binfo.substring(0,2).replace(/\;/,"")

 MO[i]=new Array()
 var M=MO[i]
 MOpt["."+mfile]=i
 M[ROOT]=s83
 M[FLAGS]=(ishape>0?ISPDF:0)
 if(ishape<0)ishape=-ishape
 M[ISHAPE]=ishape
 M[SHAPE]=Glist[ishape]
 M[CENTER]=acenter
 M[CODE]=code
 M[SRC]=(code.length == 0 ? SRC_OTHER : code.length==4 ? SRC_PDB : code.charAt(0)==":" ? SRC_NIST : SRC_CCDC)
 M[MOLFILE]=mfile+"."+(Binfo[0]=="M"||mfile.indexOf("F-")==0?"MOL":"mol")

 meth=meth.toLowerCase()
 if(methodlist.indexOf(";"+meth)<0)methodlist+=";"+meth.replace(/\,/g,";")

 M[METHOD]=meth

 ref=ref.replace(/,,/g,"").replace(/, ,/g,"")
 for(var r in RR)ref=ref.replace(RR[r],RA[r])

 S=formula_name.split(";")
 s=(S[0]?S[0]:MO[i-1][FORMULA])
 M[FORMULA]=s
 if(s.charAt(0)=="."){
	M[NAME]=s
	M[REF]=(ref?ref:s)
	if(s.charAt(0)==".")movemoinfo(i,s,FORMULA,"formula")
 }else{
	M[NAME]=(S[1]?S[1]:MO[i-1][NAME])
	M[REF]=(ref?ref:MO[i-1][REF])
 }
 M[DATA]=[binfo,ainfo,""]

//now here

	acenter=M[CENTER]
	shape=M[SHAPE]
	Atoms=M[DATA][0].split(";")
	alist=";"+acenter+";"
	iflags=checkmoflags(acenter,M[FORMULA],shape)

	if(iflags && !getandcheckatoms(Atoms))iflags=0  //adds 4 sec in IE
	M[FLAGS]=(iflags?M[FLAGS]+iflags:0)
	if(M[FLAGS]){

 //0 here means no good--don't define anything more

		nstruc++ 
		addAtom(acenter,i,1)
		addShape(M[ISHAPE],shape,i,acenter)
		addMethod(M[METHOD],i,acenter)
		M[STRUCTURE]=new Array()
		S=M[STRUCTURE]
		S[BONDS]=new Array()
		slist=""
		slast=""
		nlast=0
		nc=0
		S[ATOMS]=acenter
		for(var j=1;j<Atoms.length;j++){
			s=Atoms[j][0]
			d=Atoms[j][1]
			if(!d)d=nlast
			if(s=="")s=slast
			if(d>500)d=d/10
			slast=s
			nlast=d
			if(alist.indexOf(";"+s+";")<0){
				addAtom(s,i,0) //1 sec
				S[ATOMS]+=";"+s
			}
			alist+=s+";"
			if(s=="C"){
				nc++
				if(nc>5)d=0
			}
			if(d)slist+=addBond(acenter,s,i,d,slist) //6 sec with IE!
		}
		M[DATA][2]=slast
	}
}

function getmodelist(i,selectedmode){

 if(!MO[i][MODELIST])MO[i][MODELIST]=new Array("")
 var s=""
 var S=new Array()
 var A=new Array()
 var model=MO[i][VIBMODEL]
 var shape=getshape(i)+":"
 var pt=fullmodellist.indexOf(shape)
 var b1=0
 var a1=0
 var a2=0
 var a3=0
 if(pt<0)return ""
 if(MO[i][FORMULA].indexOf("(")>=0)return ""
 if(!model){
	S=MO[i][STRUCTURE]
	A=S[ATOMS].split(";")
	if(!S[ANGLES])getangleinfo(i)
	if(S[ANGLES].length==0 && S[BONDS].length==1){
		//XX or XA
		s="X="+MO[i][CENTER]
		if(MO[i][CENTER]==A[0]){
			model="diatomic: X2"
			s+="?d=X-X="
		}else{
			model="diatomic: XA"
			s+="?A="+A[1]+"?d=X-A="
		}
		MO[i][VIBINFO]=s+S[BONDS][0][VAL]
 	}else if(S[ANGLES].length==1 && S[BONDS].length==1){
		//XAn
		model=fullmodellist.substring(pt,pt+50).split(";")[0]
		s="X="+MO[i][CENTER]+"?A="+A[1]
		s+="?d=X-A="+S[BONDS][0][VAL]+"?d=A-X-A="+S[ANGLES][0][VAL]
		MO[i][VIBINFO]=s
 	}else if(S[ANGLES].length==2 && S[BONDS].length==2 && A.length==3){
		//XAnB
		s=shape+" XA2B"
		if(fullmodellist.indexOf(s+";")<0)s=shape+" XA3B"
		if(fullmodellist.indexOf(s+";")>=0){
			model=s			 
			s="X="+MO[i][CENTER]+"?A="+A[b1+1]+"?B="+A[2-b1]
			if(S[ANGLES][0][DESC]==A[1]+"-"+A[0]+"-"+A[1]+"-"){
				b1=0;a1=0
			}else if(S[ANGLES][1][DESC]==A[1]+"-"+A[0]+"-"+A[1]+"-"){
				b1=0;a1=1
			}else if(S[ANGLES][0][DESC]==A[2]+"-"+A[0]+"-"+A[2]+"-"){
				b1=1;a1=0
			}else if(S[ANGLES][1][DESC]==A[2]+"-"+A[0]+"-"+A[2]+"-"){
				b1=1;a1=1
			}
			s+="?d=X-A="+S[BONDS][b1][VAL]+"?d=X-B="+S[BONDS][1-b1][VAL]+"?d=A-X-A="+S[ANGLES][a1][VAL]+"?d=A-X-B="+S[ANGLES][1-a1][VAL]
			MO[i][VIBINFO]=s
		}
 	}else if(S[ANGLES].length==3 && S[BONDS].length==2 && A.length==3){
		//XA2B2
		s=shape+" XA2B2"
		if(fullmodellist.indexOf(s+";")>=0){
			model=s			 
			s="X="+MO[i][CENTER]+"?A="+A[1]+"?B="+A[2]
			s+="?d=X-A="+S[BONDS][0][VAL]+"?d=X-B="+S[BONDS][1][VAL]
			S=S[ANGLES]
			for(var j=0;j<S.length;j++){if(S[j][DESC]==A[1]+"-"+A[0]+"-"+A[1]+"-")a1=j}
			for(var j=0;j<S.length;j++){if(S[j][DESC]==A[2]+"-"+A[0]+"-"+A[2]+"-")a2=j}
			for(var j=0;j<S.length;j++){if(S[j][DESC]==A[1]+"-"+A[0]+"-"+A[2]+"-")a3=j}
			for(var j=0;j<S.length;j++){if(S[j][DESC]==A[2]+"-"+A[0]+"-"+A[1]+"-")a3=j}
			s+="?d=A-X-A="+S[a1][VAL]+"?d=B-X-B="+S[a2][VAL]+"?d=A-X-B="+S[a3][VAL]
			MO[i][VIBINFO]=s
		}
	}
 }
 if(!model)return ""
 if(selectedmode=="")selectedmode="None"
 MO[i][VIBMODEL]=model
 s="<form id=vinfo name=vinfo>show vibration:<select name=themode onchange=doshowthevibration() onkeyup=\"setTimeout('doshowthevibration()',10)\">"
 +"<option"+(selectedmode=="None"?" selected":"")+">None</option>"
 for(var m in Models[model].Modes){
	MO[i][MODELIST][MO[i][MODELIST].length]=m
	s+="<option"+(selectedmode==m?" selected":"")+">"+m+"</option>"
 }
 s+="</select></form>"
 return s
}

function findbond(i,a,Range){
	var B=MO[i][STRUCTURE][BONDS]
	for(var j=0;j<B.length;j++){
		if(!a || B[j][DESC].indexOf(a+"-")>=0){
			if(!Range || B[j][VAL]>=Range[0] && B[j][VAL]<=Range[1]){
				MO[i][THISBONDTYPE]=B[j][DESC]
				MO[i][THISBONDLEN]=B[j][VAL]
				return
			}
		}
	}
	MO[i][THISBONDTYPE]="??"
	MO[i][THISBONDLEN]=0
}


