
function Completator(){
  
  var debug=false;
  
  var self=this;
  
  var D=[];
  var E=[];
  
  
  
  
  
  function FormField(id,formula,rounding,precision,condition,internal){
    
    var self=this;
    
    this.computed=false;
    var value=0;
    
    if(id.substring(0,1)=="D"){
      if(getEl(id)){
        var element=getEl(id);
        
        if(!isUndefined(internal)){
          if(internal=="Y")setDN(element.parentNode);
        }
        
        var tag=element.tagName.toLowerCase();

        if(tag=="select"){
          element.originalOptions=[];
          for(var i=0;i<element.options.length;i++){
            element.originalOptions[i]=[element.options[i].text,element.options[i].value,element.options[i].selected];
          }
        }

      }else{
      
        var element=false;
        var tag=false;
        
      }
      
    }

    
    
    if(formula!=""){

      var mt=formula.match(/\{[DE]\d+\,\d\}/g);
      if(mt){
        var parts=[];
        for(var i=0;i<mt.length;i++){
          var pp=mt[i].match(/\{([DE])(\d+)\,(\d)\}/);
          parts.push([pp[1],pp[2],pp[3]]);
        }
      }
      
      var formula=formula.replace(/\{D(\d+)\,(\d)\}/g,"D[$1].getValue($2)").replace(/\{E(\d+)\,(\d)\}/g,"E[$1][$2].getValue()").replace(/=/g,"==").replace(/!/g,"||").replace(/\&/g,"&&").replace(/SQRT/gi,"Math.sqrt");
    
      if(element)element.style.border="1px solid #ec6500";
      
    }

    
   
    if(!isUndefined(condition)){
      if(condition!=""){
        var condition=condition.replace(/\{D(\d+)\,(\d)\}/g,"D[$1].getValue($2)").replace(/\{E(\d+)\,(\d)\}/g,"E[$1][$2].getValue()").replace(/=/g,"==").replace(/!/g,"||").replace(/\&/g,"&&");
      }
    }else var condition="";
    
    


    
    


    var disabledOptions=[];
    
    this.addDisabledOption=function(ind,cond){
      disabledOptions.push([ind,cond.replace(/\{D(\d+)\,(\d)\}/g,"D[$1].getValue($2)").replace(/\{E(\d+)\,(\d)\}/g,"E[$1][$2].getValue()").replace(/=/g,"==").replace(/!/g,"||").replace(/\&/g,"&&")]);
    };
    


    
    
    this.getFormula=function(){
      return formula;
    };

    
    

    
    this.getParts=function(){
      return isUndefined(parts)?false:parts;
    };

    
    

    
    this.getElement=function(){
      return element;
    };


    
    
    
    this.getElementValue=function(){
      return element.value;
    };


    
    
    
    this.getTagName=function(){
      return tag;
    };


    
    
    
    this.getCondition=function(){
      return condition;
    };

    
    

    
    


    
    
 
 
 
 
    
    
    this.compute=function(){

      if(tag=="select"){
  
        if(disabledOptions.length>0){

          element.options.length=0;
          for(var i=0;i<element.originalOptions.length;i++){
            element.options[element.options.length]=new Option(element.originalOptions[i][0],element.originalOptions[i][1],element.originalOptions[i][2],element.originalOptions[i][2]);
            element.options[element.options.length-1].originalIndex=i;
            if(browser.getIEversion()<7 && browser.getIEversion()>0){
              if(element.originalOptions[i][2])element.value=element.originalOptions[i][1];
            }
          }

          var opts=element.options;
          for(var i=0;i<disabledOptions.length;i++){
            var res=eval(disabledOptions[i][1]);
            var j=0;
            if(!res){
              if(opts[disabledOptions[i][0]-1]){       
                opts[disabledOptions[i][0]-1].disabled=true;
                opts[disabledOptions[i][0]-1].className="deleteme";
                
              }
            }
          }

          
          var todel=getElementsByClassName(element,"deleteme");
          for(var i=0;i<todel.length;i++)element.removeChild(todel[i]);

        }
        
      }


      
      if(self.computed)return false;
      
      

      if(formula=="" && element){

        if(element.type=="text"){
          if(element.value=="")element.value="0";
        }
       
        if(element.type=="checkbox"){
  
          if(element.checked)value=1; else value=0;
          self.computed=true;
          self.displayValue();
          return true; 
  
        } else if(element.value.trim()!="" && !isNaN(element.value)){
  
          if(element.tagName.toLowerCase()=="select"){
            for(var i=0;i<element.originalOptions.length;i++){
              if(element.options[element.selectedIndex].originalIndex==i)value=i+1;
            }
          } else value=element.value;

          self.computed=true;
          self.displayValue();
          return true; 
        } else return false;
      }
      
      
      if(self.computed)return false;

      
      if(formula!=""){

        if(parts)for(var i=0;i<parts.length;i++){

          if(parts[i][0]=="D"){
            if(!D[parts[i][1]].computed)return false;
          }
         
          if(parts[i][0]=="E")if(!E[parts[i][1]][parts[i][2]].computed)return false;
          
        }
        
        try{        
          value=eval(formula);
        }catch(e){
          alert("Chyba ve formuli\n"+formula+"\n\n"+e.message);
        }
        
        self.computed=true;
        self.displayValue();
        return true; 
    
      }
      
    };
    
    
    
    
    
    
    
    
    
    
    
    
    
    this.setStatus=function(){
      
      if(condition!=""){
        
        if(element){
          try{
            if(eval(condition)){ 
              element.disabled=false;
              element.style.background="#fff";
            }else{
              element.disabled=true;
              element.style.background="#ccc";
            }
          }catch(e){
            alert("Chyba v předpisu podmínky\n"+condition+"\n\n"+"("+e.message+")");
          }
        }
        
      }
    
    };
    



    
    
    
    
    
    
    
    
    
    
    
    
    this.getValue=function(idx){
    
      var format=function(value,rounding,precision){
        var fc=eval("Math."+rounding);
        var dc=Math.pow(10,precision);
        return fc(value*dc)/dc;
      };
      
      var val=value;
      
      if(element){
      
        if(tag=="select"){

          if(idx==0){
            for(var i=0;i<element.originalOptions.length;i++){
              if(element.originalOptions[i][2])return (i+1);
            }
          }

          if(idx==1)val=element.value;

        }

      }
      
      if(rounding=="")return val; else return format(val,rounding,precision);
      
    };
    
    
    
    
    
    
    
    
    
    
    
    this.getRealValue=function(){
      return value;
    };

    
    
    
    
    
    
    
    
    
    
    this.setValue=function(val){

      if(!isNaN(val) && val>0 || self.getElementValue()=="0" && tag!="select"){
        value=val;
        self.computed=true;
        self.displayValue();
      }
      

      if(element){

        if(tag=="select"){

          if(val>0){
            for(var i=0;i<element.options.length;i++){
              if(element.options[i].originalIndex==val-1){
                element.selectedIndex=i;
                break;
              }
            }
          }
          
          for(var i=0;i<element.originalOptions.length;i++){
            if(element.options[element.selectedIndex].originalIndex==i){
              element.originalOptions[i][2]=true;
              value=element.originalOptions[i][1];
            }else element.originalOptions[i][2]=false;
          }

          
        } else if(element.type=="checkbox"){

          if(val>0)element.checked=true; else element.checked=false;

        } else self.displayValue();

      }

    };
    
    
    
    
    
    
    
    
    
    
    this.displayValue=function(){
      
      if(element){

      
        if(element.tagName.toLowerCase()=="select"){
       
          element.options.length=0;
       
          for(var i=0;i<element.originalOptions.length;i++){
            element.options[element.options.length]=new Option(element.originalOptions[i][0],element.originalOptions[i][1],element.originalOptions[i][2],element.originalOptions[i][2]);
            element.options[element.options.length-1].originalIndex=i;
          }
       
          var opts=element.options;
       
          for(var i=0;i<disabledOptions.length;i++){
            var res=eval(disabledOptions[i][1]);
            if(!res){
              if(opts[disabledOptions[i][0]-1]){       
                opts[disabledOptions[i][0]-1].disabled=true;
                opts[disabledOptions[i][0]-1].className="deleteme";
              }
            }
          }
       
          var todel=getElementsByClassName(element,"deleteme");

          for(var i=0;i<todel.length;i++)element.removeChild(todel[i]);
        
        
        } else element.value=self.getValue();
    
    
      }
    
    };
    
    
    
    
    
    
    
  }
  
  
  
  
  
  
  
  
  this.registerField=function(idx,idy,formula,rounding,precision,condition,internal){
    if(idy==-1)D[idx]=new FormField("D"+idx,formula,rounding,precision,condition,internal); else {
      if(isUndefined(E[idx]))E[idx]=[];
      E[idx][idy]=new FormField("",formula,rounding,precision,condition);
    }
  };
  
  
  
  
  
  
  this.hideField=function(idx,idy,cond){
    D[idx].addDisabledOption(idy,cond);
  };
  
  
  
  
  
  
  
  this.setComputed=function(idx,idy){
    if(idy==-1)D[idx].computed=true; else E[idx][idy].computed=true;
  };
  
  
  
  
  
  
  
  




  this.compute=function(itm){


    var loop=function(){

      if(debug)getEl("debug").innerHTML+="<hr>"+x+"<hr>";

      var res=false;
      for(var i in D)if(!isFunction(D[i])){
        if(D[i]!=eval(itm)){
          if(D[i].compute()){
            if(debug)getEl("debug").innerHTML+="D["+i+"]<br>";
            res=true;
          }
        }
      }
      
      for(var i in E)if(!isFunction(E[i])){
        for(var j in E[i])if(!isFunction(E[i][j])){
          if(E[i][j]!=eval(itm)){
            if(E[i][j].compute()){
              if(debug)getEl("debug").innerHTML+="E["+i+"]["+j+"]<br>"
              res=true;
            }
          }
        }
      }

      
      if(!res){
      
        for(var i in D)if(!isFunction(D[i])){
          if(!D[i].computed && D[i].getValue()>0){
            D[i].computed=true;
            return true;
          }
        }

        for(var i in E)if(!isFunction(E[i])){
          for(var j in E[i])if(!isFunction(E[i][j])){
            if(!E[i][j].computed  && E[i][j].getValue()>0){
              E[i][j].computed=true;
              return true;
            }
          }
        }
      
      }

      return res;

    };

    
    var x=0;
    do{x++;}while(loop());  

    for(var i in D)if(!isFunction(D[i]))D[i].setStatus();
    for(var i in E)if(!isFunction(E[i]))for(var j in E[i])if(!isFunction(E[i][j]))E[i][j].setStatus();

  };
  
  
  
  
  

  
  this.setStatus=function(){
    for(var i in D)if(!isFunction(D[i]))D[i].setStatus();
    for(var i in E)if(!isFunction(E[i]))for(var j in E[i])if(!isFunction(E[i][j]))E[i][j].setStatus();
  
  };
  
 
 
 
 
 
  
  this.computeItem=function(ev){
    return eval(ev).compute();
  };
  
  
  
  
  
  
  this.setFieldValue=function(idx,idy,value){
    if(idy==-1)D[idx].setValue(value);
  };
  


  
  
  
  
  
  
  
  
  
  
  
  this.uncompute=function(){
   for(var i in D)if(!isFunction(D[i]))D[i].computed=false;
   for(var i in E)if(!isFunction(E[i]))for(var j in E[i])if(!isFunction(E[i][j]))E[i][j].computed=false;
  };
  
  
  
  





  

  this.exprt=function(){
  
    var out="";
  
    for(var i in D)if(!isFunction(D[i])){
      out+="D["+i+"]="+D[i].getValue(0)+";";
    }
    
    for(var i in E)if(!isFunction(E[i])){
      for(var j in E[i])if(!isFunction(E[i][j])){
        out+="E["+i+"]["+j+"]="+E[i][j].getValue(0)+";";
      }
    }

    return out;
    
  };
  
  

  
  
  
  


  this.list=function(){

    var out="";

    for(var i in D)if(!isFunction(D[i])){
      out+="D["+i+"]<br>";
      out+="formula: "+D[i].getFormula()+"<br>";
      out+="parts: "+D[i].getParts()+"<br>";
      out+="computed: "+D[i].computed+"<br>";
      out+="element: "+D[i].getElement()+"<br>";
      out+="tag: "+D[i].getTagName()+"<br>";
      out+="value': "+D[i].getValue()+"<br>";
      out+="value: "+D[i].getRealValue()+"<br>";
      out+="cond: "+D[i].getCondition()+"<br>";
      out+="<br>";
    }
    
    for(var i in E)if(!isFunction(E[i])){
      for(var j in E[i])if(!isFunction(E[i][j])){
        out+="E["+i+"]["+j+"]<br>";
        out+="formula: "+E[i][j].getFormula()+"<br>";
        out+="parts: "+E[i][j].getParts()+"<br>";
        out+="computed: "+E[i][j].computed+"<br>";
        out+="value': "+E[i][j].getValue()+"<br>";
        out+="value: "+E[i][j].getRealValue()+"<br>";
        out+="cond: "+E[i][j].getCondition()+"<br>";
        out+="<br>";
      }
    }
    
    return out;
  };
  
  



  

}



