/*
Bevat volgende classes / functies:
	Html keys getkeys BestekClass
*/
	/*onloadhandler*/
	var addonload=function(anonymusfunc){
		var c = /(^\s*function\s*\w*\s*\([^\)]*\)\s*\{)|(\s*}\s*$)/g
		var f 	= String(anonymusfunc).replace(c,"")
		var o 	= String(window.onload).replace(c,"")
		window.onload = Function (o+";\n"+f)
	}
	var bestek=function(id,reset){
		if(typeof _bestekobjecten=="undefined"){_bestekobjecten=[]}
		if(reset||!_bestekobjecten[id]){_bestekobjecten[id] = new BestekClass()}
		return _bestekobjecten[id]
	}
	var BestekClass=function(){
			/*keys
		var keys=function(){
			this.values=[]
			this.setvalue=function(key,value,force){
				if((force&&this.values[key])||this.values[key]==null){
					this.values[key]=value
				}return value
			}
			this.getvalue=function(key){
				return (this.values[key]==null)?null:this.values[key]
			}
			this.deletekey=function(key){
				if(this.getvalue(key)){delete this.values[key]}
			}
			this.test=function(w){
				var a=[]
				for(var i in this.values){
					a[a.length]= i+" = " + this.values[i]
				}
				if(w==true){document.write(a.join("<br>"));return}
				alert(a.join("\n"))
			}
		}*/
		/*
		aangepaste versie van keys ivm firefox: 
		numerieke keys zullen worden omgezet tot 
		strings om alleen associatieve keys te houden...
		*/
		var keys=function(){
			this.values=[]
			this.keypretext = "numerieke_key_"
			this.setvalue=function(key,value,force){
				if((force&&this.values[key])||this.values[key]==null){
					if(isNaN(key)){
						this.values[key]=value
					}
					else{
						this.values[this.keypretext+key]=value
					}
				}return value
			}
			this.getvalue=function(key){
				if(isNaN(key)){
					return (this.values[key]==null)?null:this.values[key]
				}
				else{
					return (this.values[this.keypretext+key]==null)?null:this.values[this.keypretext+key]
				}
			}
			this.deletekey=function(key){
				if(this.getvalue(key)){
					if(isNaN(key)){
						delete this.values[key]
					}
					else{
						delete this.values[this.keypretext+key]
					}
				}
			}
			this.test=function(w){
				var a=[]
				for(var i in this.values){
					a[a.length]= i+" = " + this.values[i]
				}
				if(w==true){document.write(a.join("<br>"));return}
				alert(a.join("\n"))
			}
		}
		
		
		var getkeys=function(id,force){
			if(!top[id]||force){top[id]=new keys(id)}
			return top[id]
		}
		/*Html*/
		Html=function(){
			this.uitvoeren=function(obj,str){
				var u ="",param
				if(str){
				var arr=str.match(/\$\w+/g)
					if(arr){
						for(var i=0;i<arr.length;i++){
							param=arr[i].substr(1)
							try{
							str = str.replace(eval("/\\\$"+param+"/g"),obj(param))
							} catch(e){}
						}
					}
				return str
				}
			return ""
			}
			this.repeat=function(o,str,max){
				var length=(o.count||o.recordcount||o.length)
				max=(!max||max>length)?length:max
				var output=""
				if(o.count){for(var i=0;i<max;i++){output += this.uitvoeren(o,str)}}
				else if(o.recordcount){if(o.eof){return ""};for(var i=0;i<max;i++){output += this.uitvoeren(o,str);o.movenext()}}
				else if(o.length){for(var i=0;i<max;i++){output+=this.uitvoeren(o,str)}}
				return output
			}
			this.tag=function(id,a){
				var str = "<"+id+(a[0]?" "+a[0]:"")+">"
				if(!id.match(/^img|br|input$/))str+=(a[1]||"")+"<"+"/"+id+">"
				return str
			}
			this.param=[]
			this.addparam=function(a,ispreset){
				a=ispreset?a.replace(/(=)([^ ]+)?/gi,'$1"$2"'):a.replace(/(=)(.+)/gi,'$1"$2"')
				this.param[this.param.length]=a
			}
			this.getparam=function(){var a=this.param.join(" ");this.param=[];return a}
			this.read=function(args,presets){
				var temp,content="",key,naam,size,quot="'"
				var re=/^\w+\s*=\s*[^<>=]+|^nowrap/
				for(var i=0;i<args.length;i++){
					args[i]=String(args[i]).replace(/\s*=\s*/g,"=")//.replace(eval("/"+quot+"/g"),"\\'")// ruimtes bij issen weg
					if(args[i].match(re)){/*het is een parameter*/
						temp=args[i].split(/&/)// was ;|&
						inner:for(var j=0;j<temp.length;j++){
							if(presets){
								if(presets.indexOf(naam=temp[j].match(/^\w+=/))!=-1){
									presets=presets.replace(eval("/"+naam+"\\w+/"),temp[j])
									continue inner
								}
							}
							this.addparam(temp[j])
						}
					}
					else {content+=args[i]}
				}
				if(presets){this.addparam(presets,true)}
				return [this.getparam(),content]
			}
			var lijst=[["a"],["b"],["i"],["u"],["br"],["img","border=0"],["table","border=0 cellpadding=0 cellspacing=0"],["td"],["tr"],["span"],["div"],["p"],["form"],["option"],["select"],["input"],["button"],["textarea"],["li"],["ol"],["ul"],["dl"],["dd"],["dt"],["sub"],["sup"],["script","language=javascript"],["xmp"],["link"],["style","type=text/css"],["frame"],["frameset"],["iframe"],["body"],["html"],["head"],["title"]]
			for(var i=0;i<lijst.length;i++){var a=lijst[i]
				this[a[0]]=Function("return this.tag('"+a[0]+"',this.read(arguments,'"+(a[1]||"")+"'))")
			}	
		}
		
		/*EINDE HTML*/
		
		this.schrijftekst=function(divid,id){
			var elm = document.getElementById(divid)
			if(elm){
				if(this.browser=="ff"){
					elm.innerHTML=this.gettext(id||"")
				}
				else if(this.browser=="ie"){
					elm.innerText=this.gettext(id||"")
				}
			}
			
		}
		this.schrijfopsomming=function(divid,id){
			var elm = document.getElementById(divid)
			if(elm){
				if(this.browser=="ff"){
					elm.innerHTML=this.getopsomming(id||"")
				}
				else if(this.browser=="ie"){
					elm.innerText=this.getopsomming(id||"")
				}
			}
		}
		
		this.stabu_tekstinspring="    "
		this.stabu_tekstafbreek=53
		this.vervangtekens=function(html){
			var set=[["€","‘","’","’","“","”","–","—","¡","¢","£","¤","¥","¦","§","¨","©","ª","«","¬","­","®","¯","°","±","²","³","´","µ","¶","·","¸","¹","º","»","¼","½","¾","¿","À","Á","Â","Ã","Ä","Å","Æ","Ç","È","É","Ê","Ë","Ì","Í","Î","Ï","Ð","Ñ","Ò","Ó","Ô","Õ","Ö","×","Ø","Ù","Ú","Û","Ü","Ý","Þ","ß","à","á","â","ã","ä","å","æ","ç","è","é","ê","ë","ì","í","î","ï","ð","ñ","ò","ó","ô","õ","ö","÷","ø","ù","ú","û","ü","ü","ý","þ","ÿ","&","<",">"],["&euro;","&lsquo;","&rsquo;","&rsquo;","&ldquo;","&rdquo;","&ndash;","&mdash;","&iexcl;","&cent;","&pound;","&curren;","&yen;","&brvbar;","&sect;","&uml;","&copy;","&ordf;","&laquo;","&not;","­","&reg;","&macr;","&deg;","&plusmn;","&sup2;","&sup3;","&acute;","&micro;","&para;","&middot;","&cedil;","&sup1;","&ordm;","&raquo;","&frac14;","&frac12;","&frac34;","&iquest;","&Agrave;","&Aacute;","&Acirc;","&Atilde;","&Auml;","&Aring;","&AElig;","&Ccedil;","&Egrave;","&Eacute;","&Ecirc;","&Euml;","&Igrave;","&Iacute;","&Icirc;","&Iuml;","&ETH;","&Ntilde;","&Ograve;","&Oacute;","&Ocirc;","&Otilde;","&Ouml;","&times;","&Oslash;","&Ugrave;","&Uacute;","&Ucirc;","&Uuml;","&Yacute;","&THORN;","&szlig;","&agrave;","&aacute;","&acirc;","&atilde;","&auml;","&aring;","&aelig;","&ccedil;","&egrave;","&eacute;","&ecirc;","&euml;","&igrave;","&iacute;","&icirc;","&iuml;","&eth;","&ntilde;","&ograve;","&oacute;","&ocirc;","&otilde;","&ouml;","&divide;","&oslash;","&ugrave;","&uacute;","&ucirc;","&uuml;","&uuml;","&yacute;","&thorn;","&yuml;","&amp;","&lt;","&gt;"]]
			if(html){
				for(var j=0;j<set[0].length;j++){
					html=html.replace(eval("/"+set[1][j]+"/g"),set[0][j])
				}
			}
		return html
		}
		/*spaties e.d. weghalen bij begin en einde*/
		this.trim=function(str){
			return str.replace(/^\s+/,"").replace(/\s+$/,"")
		}
		this.getpostenlijst=function(){
			var posten=this.posten.values,post,text=[]
			// eerst posten sorteren
			var postid=[]
			for(var i in posten){
				postid[postid.length]=i
            }
			/*
			postsorteerfunctie: werking ...
				bestekcodes worden zodanig omgezet zodat gesorteerd kan worden volgens de stabuvolgorde
				codes worden voor sortering omgezet naar een getal waarbij elk teken zijn 
				eigen positie behoud binnen de eigen tekenset. hoofdletters worden kleine letters.
				tekens en spaties worden nullen. het cijfer z krijgt bijv. positie 25 (00-25)
				"610032 .102" ==> "0601000003020000010002"
				"615115e.101" ==> "0601050101050500010001"
			*/
			return postid.sort(
				function(a,b){
					var zetom=function(str){
						var naarnr=function(d){
							d=String(d).replace(/[^a-z0-9]/i,"0")
							d=isNaN(d)?(d.toLowerCase().charCodeAt(0)-97):d
							return String(d).length==1?("0"+d):d
						}
						var x=String(str).split("")
						for(var i=0;i<x.length;i++){x[i]=naarnr(x[i])}
						return x.join("")
					}
					return zetom(a)-zetom(b)
				}
			)
		}
		var gekkebreaks=function(str){
			var nl=String.fromCharCode(13)+String.fromCharCode(10)
			var lijst=str.split("\n")
			var out=""
			for(var i=0;i<lijst.length;i++){
				out+=lijst[i]+nl
			};return out
		}
		this.gettext=function(id){
			var posten=this.posten.values,post,text=[]
			// eerst posten sorteren
			var postid = id?[id]:this.getpostenlijst()
			for(var i=0;i<postid.length;i++){
                post=posten[postid[i]]
				if(post.visible==true){
					text[text.length]=post.postgettext()
				}
            }
			var d=new Date()
			var dag		= d.getDate();dag=dag<10?("0"+dag):dag
			var maand	= (d.getMonth()+1);maand=maand<10?("0"+maand):maand
			var commentaar="#Bestek  STABU UITWISSELFORMAAT\n"+
							"#102\n"+
							"#\n"+
							"#Bestekservice\n"+
							"#datum: "+dag+"/"+maand+"/"+d.getFullYear()+"\n"+
							"#BESTEK\n"+
							"#\n"+
							"#\n"
							
			var output=commentaar+"@ST_BEGIN:\n"+text.join("\n\n")+"\n\n@ST_END"
			output=output.replace(/\`\'/g,"")
			return output		
		}
		this.getopsomming=function(id){
			var posten=this.posten.values,post,text=[]
			// eerst posten sorteren
			var postid = id?[id]:this.getpostenlijst()
			for(var i=0;i<postid.length;i++){
                post=posten[postid[i]]
				if(post.visible==true){
					text[text.length]=post.getopsomming()
				}
            }
			var strtext = text.join("\n\n")
			if(strtext.match(/R0\.06/)){
				strtext = strtext.replace(/Bandrasterprofielen\:\n/,"")
			}
			if(strtext.match(/R0\.11/)){
				strtext = strtext.replace(/Hoofdliggers\:\n/,"")
			}
			strtext = strtext.replace(/Bandrasterprofielen\:\nHoofdliggers\:/,"Hoofdliggers:")
			strtext= strtext.replace(/\$[a-z0-9\.]+\$?\./ig,"").replace(/\$/g,"")
			return strtext
		}
		this.posten=new keys()
		this.post=function(id){
			var r,t=this.posten
			if((r=t.getvalue(id))==null){
				r=t.setvalue(id,new PostClass(this,id))
			};return r
		}
		this.p=this.post
		this.deletepost=function(arrayargument){
			for(var i=0;i<arrayargument.length;i++){
                this.posten.deletekey(arrayargument[i])
            }
		}
		this.actieveposten=function(){
			var posten=this.posten.values,post,lijst=[],lijst2=[]
			// eerst posten sorteren
			var postid = this.getpostenlijst()
			with(new Html()){
				for(var i=0;i<postid.length;i++){
	                post=posten[postid[i]]
					if(post.visible==true){
						lijst[lijst.length]=[postid[i],post.omschrijving]
						lijst2[lijst2.length]=tr(td(a(post.omschrijving,
						"class=post","href=javascript:bestekpostactie('"+postid[i]+"')")))
					}
	            }
			this.postenhtml=table(lijst2.join("\n"))
			}
			
			return lijst
		}
		this.postenhtml=""
		// zonder force wordt tekst overschreven
		// mét force wordt postselectie helemaal leeggemaakt: vooral handig bij meerdere opties
		// wil je voorkoment dat teksten worden overschreven: zet ze niet in bestek
		// het filter is een lijst met posten die ingelezen mogen worden uit dit bestek
		this.browser=null
		this.inlezen=function(bestand,id,force,filter){
			this.inleesarg=arguments;_xmlsrv = this
			if (document.implementation && document.implementation.createDocument){
				this.browser="ff"
				this.xml = document.implementation.createDocument("", "", null)
				this.xml.onload = function(){_xmlsrv.inlezenload()}
			}
			else if (window.ActiveXObject){
				this.browser="ie"
				this.xml=new ActiveXObject("Microsoft.XMLDOM")
				this.xml.onreadystatechange=function(){
					if(_xmlsrv&&_xmlsrv.xml.readyState==4){
						_xmlsrv.inlezenload()
					}
				}
		 	}
			else{return}
			this.xml.async=false
			this.xml.load(bestand)
		}
		
		this.inlezenload=function(){
			// zoek cdataveld
			var cdata=function(node){
				for(var z=0;z<node.childNodes.length;z++){
					if(node.childNodes[z].nodeType==4){
						return node.childNodes[z].nodeValue ; break
					}
				}
				return ""
			}
			var opties,optieobject,optienode,postid,postnode,postobject
			var eigenschappen,invoernodes,invoernode,invoerid,invoermasker,invoerobject
			var schraptekstnodes,schraptekstnode,schraptekstid,schraptekstnr,schraptekstobject
			var s_optienodes,s_optienode,s_optienr,s_optievalue,node_opsomming, inleesmatch
			// argumenten zijn via een omweg opgehaald 
			// omdat onreadystatechange in explorer een event is
			var xmldoc	= this.inleesarg[0]
			var id		= this.inleesarg[1]
			var force	= this.inleesarg[2]
			var filter	= this.inleesarg[3]
			// vind nu de selectie : ofwel het bestek met juiste id 
			var xml 	= this.xml
			var besteknode = null
			// omdat er alleen op het hoogste nivo bestek-nodes staan voldoet deze methode.
			var bestekken = xml.getElementsByTagName("bestek")
			
			// zoek hieruit de node met juiste id: het bestek dat we nodig hebben
			for(var i=0;i<bestekken.length;i++){
				if(bestekken[i].getAttribute("id")==id){
					besteknode=bestekken[i];break
				}
			}
			// bouw expressie voor het filter
			// dit filter laadt alleen de posten die aangegeven zijn
			// nog niet duidelijk is het of dit wel nodig is...
			if(filter){
				filter=(typeof filter=="string")?filter:filter.join("|")
				if(filter){var efilter=eval("/"+filter+"/")}
			}
			var tekstnode,subnode,optieteller=-1
			/*nu onderliggende posten selecteren: 
			de posten liggen direct onder de node 'bestek'*/
			r1:for(var i=0;i<besteknode.childNodes.length;i++){
				postnode=besteknode.childNodes[i]
				if(postnode.nodeName!="post"){continue r1}
				
				
				postid = postnode.getAttribute("id")
				
				
				postomschrijving = postnode.getAttribute("omschrijving")
				
				if(filter&&postid.match(efilter)==null){continue r1}
				// overschrijven van een post als deze al eerder is ingelezen
				if(force&&this.posten.getvalue(postid)){
					this.posten.deletekey(postid)
				}
				postobject=this.post(postid)
				postobject.omschrijving=postomschrijving||""
				
				optieteller=-1
				
				//var opties=postnode.selectNodes("optie")
				/*direct onder de node 'post' kunnen één of meerdere optie-nodes staan*/
				r2:for(var j=0;j<postnode.childNodes.length;j++){
					optienode=postnode.childNodes[j]
					if(optienode.nodeName!="optie"){continue r2}
					optieteller++
					// optieteller is hier nodig omdat
					// anders de veronderstelde index niet klopt
					optieobject=postobject.optie(optieteller)
					//alert(optieteller)
					/* 
					alle onderliggende nodes zijn:
						eigenschap
						invoer
						schraptekst
						tekst met daaronder cdata-node
						opsomming met daaronder cdata-node
					*/
					tekstnode=null,subnode=null,eigenschappen=[]
					r3:for(var k=0;k<optienode.childNodes.length;k++){
						subnode=optienode.childNodes[k]
						switch(subnode.nodeName){
							case "tekst":
								optieobject.text=this.vervangtekens(this.trim(cdata(subnode)))
								.replace(/\n	/g,"\n    ").replace(/	/g," ")
							break
							case "eigenschap":
								optieobject.eigenschappen[optieobject.eigenschappen.length]=
								subnode.getAttribute("value")
							break
							case "invoer":
								invoerid=subnode.getAttribute("id")
								invoervlag=subnode.getAttribute("vlag")
								invoerobject=optieobject.invoerwaarde(invoerid)
								invoerobject.vlag=invoervlag
							break
							case "schraptekst":
								schraptekstid=subnode.getAttribute("id")
								schraptekstnr=subnode.getAttribute("nr")
								schraptekstobject=optieobject.schraptekst(schraptekstid)
								schraptekstobject.setnr(schraptekstnr)
								// schraptekstobject is klaar, nu opties invoeren voor schraptekst
								r4:for(var m=0;m<subnode.childNodes.length;m++){
									s_optienode=subnode.childNodes[m]
									if(s_optienode.nodeName!="optie"){continue r4}
									s_optienr=s_optienode.getAttribute("nr")
									s_optievalue=s_optienode.getAttribute("value")
									s_optievalue=s_optievalue?("__"+s_optievalue):"handinvoer"
									schraptekstobject.schrapopties.setvalue(s_optievalue,s_optienr)
								}
							break
							case "opsomming":
								optieobject.opsomming=this.vervangtekens(this.trim(cdata(subnode)))
							break
							case "omschrijving":
								optieobject.omschrijving = subnode.getAttribute("value")
							break
						}
					}//r3
						
						//str="";for(var q in optieobject){
						//str += ">>"+ q + "<< "+ optieobject[q] + "\n"}
						//alert(str)
				}//r2
			}
		}
		
		
		
		
		
		this.inlezen2=function(xmldoc,id,force,filter){
		
			var xml=new ActiveXObject("microsoft.xmldom")
			//this.main.path(xmldoc)
			xml.async=false;xml.load(xmldoc)
			//alert(this.main.path(xmldoc))
			var selectie=xml.selectSingleNode("bestekken/bestek[@id='"+id+"']")
			if(!selectie){alert("fout: sytaxfout in xml-document");return}
			if(filter){
			filter=(typeof filter=="string")?filter:filter.join("|")
			if(filter){var efilter=eval("/"+filter+"/")}
			}
			
			var posten=selectie.selectNodes("post")
			var opties,optieobject,optienode,postid,postnode,postobject
			var eigenschappen,invoernodes,invoernode,invoerid,invoermasker,invoerobject
			var schraptekstnodes,schraptekstnode,schraptekstid,schraptekstnr,schraptekstobject
			var s_optienodes,s_optienode,s_optienr,s_optievalue,node_opsomming, inleesmatch
			rl:for(var i=0;i<posten.length;i++){
				postnode=posten[i]
				postid = postnode.getAttribute("id")
				postomschrijving = postnode.getAttribute("omschrijving")
				if(filter){
					if(postid.match(efilter)==null){
						continue rl
					}
				}
				if(force&&this.posten.getvalue(postid)){// overschrijven
					this.posten.deletekey(postid)
				}
				postobject=this.post(postid)
				postobject.omschrijving=postomschrijving||""
				var opties=postnode.selectNodes("optie")
				for(var j=0;j<opties.length;j++){
					optienode=opties[j]
					optieobject=postobject.optie(j)
					postobject.optie(j).text = this.vervangtekens(
					this.trim(optienode.selectSingleNode("tekst").text))
						postobject.optie(j).text
						.replace(/\n	/g,"\n    ").replace(/	/g," ")
					
					
					/* 
					nu weten we wat optie.text is 
					- in deze tekst staat basisregel... 
						615131a.S00.101.B552320.999.c99.000 HR-WASEMKAP
					of: 303311a.S00.101.B412320.114.f01.106
					of: 303311 .S00.101.B412320.114.f01.106
					of: 610033 .S03.102.A223102.001.a02.102

					inleesmatch = postobject.optie(j).text
					.match(/(\d{6})([a-z ])\.S\d{2}\.\d{3}\.((([A-Z])\d{6})\.\d{3}\.([a-z])\d{2})\.(\d{3})( [^\n]+|\n)/g)
					if(inleesmatch)alert(inleesmatch.join("\n -"))
					
					deze selectie moet leiden tot een onderverdeling van deze post (optie) in het object 'onderdeel'
					een onderdeel kan het volgende zijn: 
					 een stabu-post
					 een bouwdeel
					
					*/

					node_opsomming = optienode.selectSingleNode("opsomming")
					if(node_opsomming){
						postobject.optie(j).opsomming=this.vervangtekens(node_opsomming.text)
					}
					eigenschappen=optienode.selectNodes("eigenschap")
					for(var k=0;k<eigenschappen.length;k++){
						optieobject.eigenschappen[optieobject.eigenschappen.length]=
						eigenschappen[k].getAttribute("value")
                    }
					invoernodes=optienode.selectNodes("invoer")
					for(var l=0;l<invoernodes.length;l++){
                        invoernode=invoernodes[l]
						invoerid=invoernode.getAttribute("id")
						invoervlag=invoernode.getAttribute("vlag")
						invoerobject=optieobject.invoerwaarde(invoerid)
						invoerobject.vlag=invoervlag
                    }
					schraptekstnodes=optienode.selectNodes("schraptekst")
					for(var m=0;m<schraptekstnodes.length;m++){
                        schraptekstnode=schraptekstnodes[m]
						schraptekstid=schraptekstnode.getAttribute("id")
						schraptekstnr=schraptekstnode.getAttribute("nr")
						schraptekstobject=optieobject.schraptekst(schraptekstid)
						schraptekstobject.setnr(schraptekstnr)
						// schraptekstobject is klaar, nu opties invoeren voor schraptekst
						s_optienodes=schraptekstnode.selectNodes("optie")
						for(var n=0;n<s_optienodes.length;n++){
							s_optienode=s_optienodes[n]
							s_optienr=s_optienode.getAttribute("nr")
							s_optievalue=s_optienode.getAttribute("value")
							s_optievalue=s_optievalue?("__"+s_optievalue):"handinvoer"
							schraptekstobject.schrapopties.setvalue(s_optievalue,s_optienr)
                   		}
                    }
					
					nodeomschrijving=optienode.selectSingleNode("omschrijving")
					if(nodeomschrijving){
					optieobject.omschrijving = nodeomschrijving.getAttribute("value")
					}
					else{optieobject.omschrijving = ""}
                }
            } 
		}
		/*#########################BEGIN POSTCLASS####################################*/
		var PostClass=function(bestek,id,sindex){
			this.bestek=bestek||null 		// parentobject
			this.visible=true				// post wel of niet tonen in bestek
			this.id=id||null				// id van bestekpost: 303612a.101
			this.selectedindex=sindex||null	// welke van de opties is standaard of op enig moment geselecteerd
			this.opties=new keys()			// de verschillende options worden in deze array ingelezen
			this.optie=function(id){
				var r,t=this.opties
				if((r=t.getvalue(id))==null){
					r=t.setvalue(id,new OptieClass(this))
				};return r
			}
			this.getindex=function(){
				return this.selectedindex
			}
			this.getoptieslijst=function(){
				var lijst =[]
				for( var i in this.opties.values){
					lijst[lijst.length]=this.opties.values[i]
				}
				return lijst
			}
			this.geteigenschappenlijst=function(){
				var lijst =[]
				for( var i in this.opties.values){
					lijst[lijst.length]=this.opties.values[i].eigenschappen[0]
				}
				return lijst
			}
			// test voor welke optie de meeste argumenten tellen
			// eerst de opties doorlopen:
			// kies dan een ingevoerd argument (testwaarde)
			// doorloop vervolgens alle eigenschappen van die optie
			// zit de eigenschap erbij: gevonden
			// zit je aan het einde van alle eigenschappen-van-optie en niets gevonden? 
			// ga dan naar volgende optie
			// een andere belangrijke eigenschap is dat bij selectie van een andere optie binnen
			// een post de geselecteerde waarden van die post worden leeggemaakt.
			this.selecteer=function(){
				this.selectie=new keys()// maak selecteerwaarden leeg 
				var opties=this.opties.values,eigenschappen,index=0
				var eigenschap,testwaarde,gevonden
				opt:for(var i in opties){
					eigenschappen=opties[i].eigenschappen
	               	for(var j=0;j<arguments.length;j++){
						testwaarde=arguments[j];gevonden=false
	                    for(var k=0;k<eigenschappen.length;k++){
	                    	eigenschap=eigenschappen[k]
							if(eigenschap==testwaarde){gevonden=true}
							if(k==(eigenschappen.length-1)&&gevonden==false){continue opt}
	            		}
						if(j==(arguments.length-1)){this.selectedindex=i}
	                }
	            }
			}
			this.s=this.selecteer
			this.regelafbreker=function(invoer){// 10 extra
				var expr = /(.){0,53} /g
				var expr2 = /(.){0,53} |.+$/g // deze expressie neemt ook laatste stukje mee.
				var tekenaantal=this.bestek.stabu_tekstafbreek
				var inspring=this.bestek.stabu_tekstinspring
				if(invoer.substr(0,4)!=inspring){return invoer}
				if(invoer.length<=tekenaantal){return invoer}
				invoer=this.bestek.trim(invoer)
				var lijst=invoer.match(expr2)
				if(lijst)
				if(!lijst){return invoer}
				else{return inspring+lijst.join("\n"+inspring)}
				return invoer
			}
			this.formatteerinvoer=function(invoer,type){
				var lijst,uitvoer="",a,b
				var tekenaantal=this.bestek.stabu_tekstafbreek
				var inspring=this.bestek.stabu_tekstinspring
					switch(type){
		            	case "schraptekst" :
		            	break
		            	case "handinvoer" :
							if(invoer.length<(inspring.length+tekenaantal)){return invoer}
		            	break
						case "blok" :
						a=invoer.split(/\n/g)
						for(var i=0;i<a.length;i++){
	                        uitvoer+=this.regelafbreker(a[i])+"\n"
	                    }
						return uitvoer
						break
		            }
					
					invoer=invoer.replace(/^\s+/,"").replace(/\s+$/,"")
					invoer+= " "
					lijst=invoer.match(/(.){0,53} /g)
					if(lijst){uitvoer=lijst.join("\n"+inspring)}
					else{uitvoer=invoer}
					if(uitvoer.length!=(uitvoer.lastIndexOf(".")+1)){
						uitvoer=uitvoer.replace(/ *$/,".")
					}
					uitvoer=uitvoer.replace(/(\.){2}$/,".")
					return inspring+uitvoer
			}
			/*lees opsomming uit van één bestekpost*/
			this.getopsomming=function(){
				var invoerobject, id, selecteerwaarde, vlag, blok, blokweg,waarde
				var optie=this.opties.getvalue(this.selectedindex)
				if(!optie){return "geen mogelijkheden beschikbaar voor bestekspost ...."}
				var opsomming = optie.opsomming
				if(!opsomming){return ""}
				var invoerwaarden=optie.invoerwaarden.values
				var selecteerkey,selecteerwaarde,invoerwaarde
				for(var k in this.selectie.values){
						selecteerkey = k
						selecteerwaarde = this.selectie.values[k].value
						invoerwaarde = this.selectie.values[k].invoerwaarde||null
						vlag="\\$"+selecteerkey+"\\$"
						//blok	= opsomming.match(eval("/(\\[([^\\n\\]]+\\n)+)*[^\\n]+"+vlag+"[^\\n]*\\]/g"))
						//blokweg	= opsomming.match(eval("/(\\[([^\\n\\]]+\\n)+)*[^\\n]+"+vlag+"[^\\n]*\\]\\n/g"))
						blok = opsomming.match(eval("/\\[[^\$]*"+vlag+"[^\\]]*\\]/g"))
						blokweg = opsomming.match(eval("/\\[[^\$]*"+vlag+"[^\\]]*\\]\\n/g"))
						waarde = selecteerwaarde
						if(invoerwaarde){waarde  = selecteerwaarde+" "+invoerwaarde}
						if(selecteerwaarde){// vervang mbv vlag ingevulde waarde bij opsomming
							/*
							volgende validatie is hier nodig:
								is de waarde geselecteerd aan een schraptekst 
								en is er voor deze schraptekst geen optie binnen het bereik?
							*/
							if(schraptekstobject=optie.schrapteksten.getvalue(selecteerkey)){
								if(
									schraptekstobject.schrapopties.getvalue("__"+selecteerwaarde)||
									schraptekstobject.schrapopties.getvalue("handinvoer")
								){
								// er is een mogeljkheid om deze waarde in te vullen
								}
								else{// geen waarde : ruim tekst-regel op...
									if(blokweg){// ruim tekstblokken op...
										for(var j=0;j<blokweg.length;j++){
											x = opsomming.split(blokweg[j]).join("")
											opsomming = x
										}
									}
									opsomming=opsomming.replace(eval("/([^\\$\\n]+"+vlag+"[^\\n]*)+\\n?/g"),"")
								}
							}
							if(blok){
								for(var j=0;j<blok.length;j++){
									x = opsomming.split(blok[j]).join(blok[j].substr(1,blok[j].length-2))
									opsomming = x
								}
							}// vul nu waarde in
							opsomming=opsomming.replace(eval("/"+vlag+"/g"),""+waarde)
						}
						else{// geen waarde : ruim tekst-regel op...
							if(blokweg){// ruim tekstblokken op...
								for(var j=0;j<blokweg.length;j++){
									x = opsomming.split(blokweg[j]).join("")
									opsomming = x
								}
							}
							opsomming=opsomming.replace(eval("/([^\\$\\n]+"+vlag+"[^\\n]*)+\\n?/g"),"")
						}
					}
					/*enkele algemene opruimhandelingen*/
					opsomming = opsomming
					.replace(/(\[([^\n\]]+\n)+)*[^\n]+\$[^\$]+\$[^\n]*\]\n/g,"")
					.replace(/[^\$\n]+\$[^\$]+\$[^\n]*\n?/g,"")
				return opsomming
			}
			this.postgettext=function(){
				var optie = this.opties.getvalue(this.selectedindex)
				var invoerwaarden,invoerobject,text,id,selecteerwaarde,vervangwaarde,vlag
				var selecteerkey,schraptekstobject,schraptekstoptienr,schraptekstgroepen=[]
				var schraptekstregel,schrapteksthandinvoer,schraptekstgroep
				var vasteteksten,vastetekst,vastetekstregelbasisnr,vastetekstsorteernr,beginregel
				var vastetekstregelnr,vastetekstbody,temp,invoerwaarde
				if(optie){// optie is de geselecteerde bestektekst 
					invoerwaarden=optie.invoerwaarden.values
					text=optie.text
					//alert(text)
					/*
					hier worden waarden ingevuld 
					<invoer id="achterwandpaneel" vlag="$achterwandpaneel$" value="- achterwandpaneel (bxh) (mm): 600 x 690."/>
					*/
					for(var i in invoerwaarden){
						invoerobject=invoerwaarden[i]
						id=invoerobject.id
						selecteerwaarde=this.getvalue(id)
						vlag=invoerobject.vlag.replace(/\$/g,"\\$")
						/* 
						verwijder vlag volledig als deze alleen staat op een regel (1)
						geen \s gebruiken \n valt namelijk onder \s
						LET WEL OP DAT BIJ DEZE STAP DE INSPRING NOG NIET VARIABEL IS
						*/
						if(selecteerwaarde==null){
							vervangwaarde="....."
							if(text.match(eval("/\\n    [ ]*"+vlag+" *\\n/"))){
								text=text.replace(eval("/\\n    [ ]*"+vlag+" */"),"")/*(1)*/
							}else{text=text.replace(eval("/"+vlag+"/"),vervangwaarde)}
						}
						else{vervangwaarde=selecteerwaarde
							//alert(text)
							
							text=text.replace(eval("/"+vlag+"/"),vervangwaarde)
							//alert(text)
						}
						//alert(id+"\n"+selecteerwaarde+"\n"+vlag)
					}
					/*
					de invoerwaarden zijn nu ingevuld. 
					wat is er precies geselecteerd? schrapteksten of posten 
					bij een schraptekst wordt een selecteerwaarde gebruikt om de juiste s01 te kiezen
					de invoerwaarde is de data die in een invoerveld ingevuld wordt
					*/
					for(var j in this.selectie.values){
						selecteerkey = j
						selecteerwaarde = this.selectie.values[j].value
						invoerwaarde = this.selectie.values[j].invoerwaarde||null
						//alert(j+"\n"+selecteerwaarde+"\n"+invoerwaarde)
						
						/*voor deze optie: schraptekst die dezelfde naam heeft als de selecteerkey*/
						if(schraptekstobject=optie.schrapteksten.getvalue(selecteerkey)){
							/*
							test of er een key voorkomt bij schraptekstobject die overeenkomt met: __+ selecteerwaarde
							juiste node wordt gekozen en eventueel een waarde wordt ingevuld
							*/
							if(schraptekstobject.schrapopties.getvalue("__"+selecteerwaarde)){
								schraptekstobject.schrapoptienr=
								schraptekstobject.schrapopties.getvalue("__"+selecteerwaarde)
								schraptekstobject.handinvoerwaarde=invoerwaarde?("`'"+invoerwaarde):""
							}
							/*
							indien de te kiezen node niet wordt gevonden is er nog de mogelijkheid 
							om de gegevens in de vrije optie van de schraptekst in te vullen
							*/
							else if(schraptekstobject.schrapopties.getvalue("handinvoer")){// laatste node wordt gekozen 
								schraptekstobject.schrapoptienr=
								schraptekstobject.schrapopties.getvalue("handinvoer")
								schraptekstobject.handinvoerwaarde="`'"+(selecteerwaarde||"")
							}
							/*
							als dat ook niet mogelijk is, is het niet mogelijk om deze schraptekst toe te voegen
							*/
							else{
								schraptekstobject.schrapoptienr=null
								schraptekstobject.handinvoerwaarde=null
							}
						}
					}//einde for
					/*voor deze post/optie: op dit punt zijn voor alle schrapteksten 
					waardes ingevoerd en is bekend of de schraptekst wel/niet meedoet
					de volgende stap is om de schrapteksten in te delen per regelbasisnummer
					dan ze te sorteren S01, S02 etc
					en per regelbasisnummer een tekstblok op te bouwen
					*/
					for(var k in optie.schrapteksten.values){
						schraptekstobject=optie.schrapteksten.values[k]
						if(schraptekstobject.schrapoptienr==null){continue}
						if(!schraptekstgroepen[schraptekstobject.regelbasisnr]){// indelen in groepen
							schraptekstgroepen[schraptekstobject.regelbasisnr]=[]
						}
						/*belangrijk: 
						indien er al schapteksten zijn aangebracht in het document 
						kunnen deze niet in de sortering worden meegenomen
						zodra dit nodig is: schraptekstgroep uitlezen en in sortering toevoegen
						hiervoor geldt het volgende mechanisme:
						indien er binnen een basisregel in de tekst al waarden zijn gedefinieerd,
						kunnen deze NIET door de schrapteksten worden overschreven
						Indien wel/niet overschrijven een optie moet worden, 
						moet dat als argument worden ingebouwd bij gettext() ...
						*/
						if(!isNaN(schraptekstobject.sorteernr)){
							// bouw nu de tekst op voor één schraptekst
							schraptekstregel=schraptekstobject.nr+"-"+schraptekstobject.schrapoptienr
							if(schraptekstobject.handinvoerwaarde){
								if(schraptekstobject.handinvoerwaarde){
									schraptekstregel+="\n"+this.formatteerinvoer(schraptekstobject.handinvoerwaarde,"schraptekst")
								}
							}
							schraptekstgroepen[schraptekstobject.regelbasisnr][schraptekstobject.sorteernr]=
							schraptekstregel
						}
					}
					// wat nu? 
					/*
					vaste teksten zijn: een regel met daarachter alle informatie
					303311a.S00.101.B412320.114.f04.106-I01-S05
					    bla blabla blabla blabla blabla bla
					    bla blabla blabla blabla blabla bla
					*/
					
					var regels=text.split("\n")
					//alert(regels.join("\n"))
					var temp = []
					for(var p=0;p<regels.length;p++){
						// wat is een stukje ingevoerde tekst dat te lang is afbreken en opnieuw opmaken?
						// deze afbreekfunctie is helaas nog niet ideaal...
						// geen codering en groter als 60 tekens
						if(regels[p].length>60&&!regels[p].match(/^\d{6}.\./)){
							regels[p]=regels[p].match(/(.){0,53} |.+$/g)//.join("\n")
							.join("\n"+this.bestek.stabu_tekstinspring)
						}
						if(!regels[p].match(/^\d{6}.\.|^\s{4}/)){
							regels[p]=this.bestek.stabu_tekstinspring+regels[p]
						}
					}
					
					//alert(temp.join("\n"))
					text=regels.join("\n")
					
					//alert(text.match(/\n\d{6}|\s{4}.+/g))
					// de tekst is hier klaar behalve schrapteksten, deze moeten worden ingevoegd
					vasteteksten=text.match(/\d{6}.\.\w{3}\.\d{3}\.\w{7}\.\d{3}\.\w{3}\.\d{3}-\w{3}-\w{3} *[\n]+( {4}.+\n)*/g)
					
	
					if(vasteteksten){
						for(var l=0;l<vasteteksten.length;l++){
		                    vastetekst=vasteteksten[l]
	
							vastetekstregelbasisnr=vastetekst.match(/\d{6}.\.\w{3}\.\d{3}\.\w{7}\.\d{3}\.\w{3}\.\d{3}/)
							vastetekstregelbasisnr=vastetekstregelbasisnr?vastetekstregelbasisnr[0]:null
							vastetekstsorteernr=vastetekst.match(/\d{6}.\.\w{3}\.\d{3}\.\w{7}\.\d{3}\.\w{3}\.\d{3}-\w(\d{2})-\w{3}/)
							vastetekstsorteernr=vastetekstsorteernr?(vastetekstsorteernr[1]-0):null
							
							// inlezen sorteren en wegschrijven alleen nodig als er schrapteksten zijn....
							// verwijder alle vaste tekstregels uit de tekst en plaats bij het begin een vlag
							if(schraptekstgroepen[vastetekstregelbasisnr]){
								// verwijder vaste tekstregel 
								text=text.substr(0,(text.indexOf(vastetekst)))+
								text.substr(text.indexOf(vastetekst)+(vastetekst.length),text.length)
								temp=vastetekst.split("\n")
								if(temp.length>1&&temp[1]){// LET OP BIJ MAAR 1 REGEL
									vastetekstregelnr=temp[0];temp[0]=""
									for(var n=0;n<temp.length;n++){
										temp[n]=this.formatteerinvoer(temp[n],"handinvoer")
			                        }
									temp=temp.join("\n")
									vastetekst=vasteteksten[l]=vastetekstregelnr+temp
								}
								// overschrijf schraptekst met de vaste regel
								schraptekstgroepen[vastetekstregelbasisnr][vastetekstsorteernr]=vastetekst
							}
		                }
					}// einde if vasteteksten
					for(var m in schraptekstgroepen){
						schraptekstgroep=schraptekstgroepen[m]
						beginregel=text.match(eval("/"+m+" *\\n?(?: {4}.+\\n)*/"))
						if(beginregel){beginregel=beginregel[0]}
						text=text.replace(
							eval("/"+m+" *\\n?(?: {4}.+\\n)*/"),
							beginregel+
							schraptekstgroep.join("\n").replace(/\n+/g,"\n")+"\n"
						).replace(/\n *\n/,"\n")
					}
					text=text.replace(/\`\'/g,"")
					
					
				//	alert(text.match(/\d{6}.\.\w{3}\.\d{3}\.\w{7}\.\d{3}\.\w{3}\.\d{3}-\w{3}-\w{3} *[\n]+( {4}.+\n)*/g))
					
					
					return text
				}// if optie
			}// postgettext
			
			
			this.enable=function(a){
				if(a==true){this.visible=true}
				if(a==false){this.visible=false}
			}
			this.selectie=new keys()	
			this.setvalue=function(id,value,invoerwaarde){
				this.selectie.setvalue(id,
				new SelectieClass(value,invoerwaarde),true)
				return value
			}
			this.getvalue=function(id){
				if(this.selectie.getvalue(id)){
					return this.selectie.getvalue(id).value
				}
				else{return null}
			}
			/*private*/
			var SelectieClass=function(value,invoerwaarde){
				this.value=value||null
				this.invoerwaarde=invoerwaarde||null
			}	
			var OptieClass=function(post){
				this.post=post
				this.text=""
				this.eigenschappen=[]
				this.omschrijving=""
				this.invoerwaarden=new keys()
				this.invoerwaarde=function(id){
					var r,t=this.invoerwaarden
					if((r=t.getvalue(id))==null){
						r=t.setvalue(id,new InvoerClass(this,id))
					};return r
				}
				this.schrapteksten=new keys()
				this.schraptekst=function(id){
					var r,t=this.schrapteksten
					if((r=t.getvalue(id))==null){
						r=t.setvalue(id,new SchraptekstClass(this,id))
					};return r
				}
				this.isschraptekst=function(){
					this.schrapteksten.getvalue(id)
				}
			}
			var InvoerClass=function(optie,id){
				this.optie=optie
				this.id=id
				this.vlag=""
			}
			var SchraptekstClass=function(optie,id){
				this.optie=optie
				this.id=id
				this.nr=""
				this.regelbasisnr=""
				this.sorteernr=null
				this.schrapoptienr=null // dit is de geselecteerde waarde 
				this.handinvoerwaarde=null
				
				/*
				omdat opties van een schraptekst altijd maar 1 key en optioneel een waarde hebben
				volstaat het om hiervoor een key-valuepaar te gebruiken. Vanuit het opbouwen van het bestek wordt om 
				de waarde gevraagd (niet het S-nummer) waarde wordt dus de key. Bij ontbreken van deze waarde wordt 
				een handinvoer-key aangemaakt. Deze handinvoer-key wordt tijdens inlezen van document aangemaakt 
				indien dit toegestaan is.
				*/
				
				this.schrapopties=new keys()
				this.setnr=function(nr){
					this.nr=nr
					var lijst=this.nr.match(/^([a-zA-Z0-9]+\.)+[a-zA-Z0-9]+/)
					if(lijst){this.regelbasisnr=lijst[0]}
					lijst=this.nr.match(/[a-zA-Z0-9\.]+-[a-zA-Z](\d{2})/)
					if(lijst){this.sorteernr=lijst[1]-0}
					//alert("this.nr: "+this.nr+"\n"+"this.regelbasisnr: "+this.regelbasisnr+"\n"+"this.sorteernr: "+this.sorteernr)
				}
			}
		}
		/*#########################EINDE POSTCLASS####################################*/
	}

	


	// post--opties--optie--schrapteksten--schraptekst--opties--optie
	/*
	maak ik voor bestek een nieuw object? 
	lijkt me van wel
	wat moet het kunnen?
	>> gegevens inlezen (maakt niet uit waarvandaan)
	>> naar volgende pagina gaan als aan bepaalde criteria is voldaan
	>> een keuze maken uit het juiste bestek
	>> besturingselementen opbouwen en aanpassen
			gegevens opbouwen in besturingselementen mbt keuzemogelijkheden
			uitzonderingen verwerken
			indien een bepaalde waarde (lees aantal criteria) voldoet een actie uitvoeren
			zo'n actie kan zijn: tonen of niet tonen van een besturingselement
			sub-selectie van keuzes maken dwz: de comboboxen krijgen dan een andere inhoud
			vensters openenen met daarin een subselectie, die dan weer weggeschreven wordt naar hoofdpagina
			al deze gegevens in één object bewaren
			een keuze-verloop in de selectie aangeven 
			bij een bepaalde keuze naar een bepaalde bestekpagina gaan
			randwaarden voor invoer
			eerst een keuze maken en vervolgens een keuze waarbij de invoer afhankelijke is van de voorgaande keuze
			is een waarde vereist?
			als een bepaalde waarde wordt gekozen, dan heeft dat geen gevolgen voor andere waarden
			sommige gegevens kunnen een bestek aansturen maar maken zelf geen deel uit van de selectie: bijvoorbeeld
			een systeemkeuze uit een productselectie kiest wel welk bestek er wordt gebruikt maar niet de gegevens daarin
			moet er bij een bepaalde event en invoerwaarde een actie worden ondernomen?
		>> 
	Hoe ziet een bestek eruit
	
	Algemene waarden opslaan:
	-> een soort bak waar alle gegevens in staan
	-> of noem het huidige selectie
	-> deze selectie kan je ook weer leegmaken
	-> 	vraag: moeten er ook meerdere bestekken geselecteerd worden? 
		dit kan ook gebeuren op het moment dat daarnaar wordt gevraagd. 
		
	<selectie>
	<bestekken>
		<bestek>
			<post>
			<waarden>
			maximale waarde
			minimale waarde
			invoertype
			invoerveldtype (bijvoorbeeld optielijst of combobox)
			
			per keuze:
				omschrijving
				afbeelding
				eenheid
				melding dmv alert
	Het is wel zo dat de gegevens ergens vandaan moeten komen.
	ook zou het handig zijn om de bestekselectie te coderen.
	dwz: paneelboven1 = "30"  (3e keuze)
	
	
	*/
	
