"use strict";

//version: 1.21

function UnlimitedElementsForm(){
  
  var t = this;
  
  //selectors
  var ueInputFieldSelector, ueNumberSelector, ueNumberErrorSelector, ueOptionFieldSelector, elementorElementSelector;
  
  //objects
  var g_objCalcInputs;
  
  //helpers
  var g_allowedSymbols, g_parents = [];
  
  /**
  * trace
  */
  function trace(str){
    console.log(str);
  }
  
  /**
  * show custom error
  */
  function showCustomError(objError, errorText, consoleErrorText){    
    objError.text(errorText);
    
    objError.show();
    
    var objErrorParent = objError.parents(".debug-wrapper");
    
    if(!objErrorParent.length)
      throw new Error(consoleErrorText);    
    
    objErrorParent.addClass("ue_error_true");
    
    throw new Error(consoleErrorText);     
  }
  
  /**
  * get formula names
  */
  function getFormulaNames(expr, objError){     
    var regex = /\[(.*?)\]/g;    
    var matches = expr.match(regex);       
    var names;    
    
    if(matches)      
      names = matches.map(match => match.substring(1, match.length - 1));     
    
    if(names == undefined)
      return(false);
    
    //check for space inside name
    names.forEach(function(name, index){      
      for (var i = 0; i < name.length; i++) {
        
        var currentChar = name[i];
        
        if(currentChar === " "){          
          var errorText = 'Unlimited Elements Form Error: Name option must not contain spaces inside. Found in name: '+name;
          var consoleErrorText = "Space character in name found";
          
          showCustomError(objError, errorText, consoleErrorText);          
        }        
      }      
    });
    
    //remove spacing in case they were not removed before
    expr = expr.replace(/\s+/g, "");
    
    var unmatches = expr.replace(regex, "").split(/[\[\]]/);
    
    //exclude allowed symbols and check if array is empty, if not - then in formula some fields written without square parentacess
    unmatches = unmatches[0].replace(g_allowedSymbols, "").split(/[\[\]]/);
    
    if(unmatches[0].length > 0){      
      var errorText = 'Unlimited Elements Form Error: Input Name should be surrounded by square parentheses inside Formula';
      var consoleErrorText = "Missing square parentheses inside Formula";
      
      showCustomError(objError, errorText, consoleErrorText);   
    }    
    return(names);    
  }
  
  /**
  * replace fields name with its values
  */
  function replaceNamesWithValues(expr, objError, objCalcInput){    
    var names = getFormulaNames(expr, objError);
    
    if(names == undefined || names == false)
      return(expr);
    
    names.forEach(function(name, index){      
      var objInpput = jQuery(ueInputFieldSelector+'[name="'+name+'"]');
      
      if(!objInpput.length){        
        var errorText = 'Unlimited Elements Form Error: couldn"t find Number Field Widget with name: '+name;
        var consoleErrorText = "Invalid Number Field Widget Name";
        
        showCustomError(objError, errorText, consoleErrorText);        
      }
      
      if(objInpput.length > 1){        
        var errorText = 'Unlimited Elements Form Error: Name option must be unique. Found '+objInpput.length+' Number Field Widgets with name: '+name;
        var consoleErrorText = "Invalid Number Field Widget Name";
        
        //check if not in stiky container
        var objParentSticky = objInpput.closest(".elementor-sticky");
        
        if(!objParentSticky || objParentSticky.length == 0)
          showCustomError(objError, errorText, consoleErrorText);        
      }
      
      //check if uppercase characters are in name
      for (var i = 0; i < name.length; i++) {        
        var currentChar = name[i];
        
        if (currentChar === currentChar.toUpperCase() && currentChar !== currentChar.toLowerCase()){          
          var errorText = 'Unlimited Elements Form Error: Name option must not contain Uppercase characters. Found in name: '+name;
          var consoleErrorText = "Uppercase in name found";
          
          showCustomError(objError, errorText, consoleErrorText);          
        }
        
        if(currentChar === " "){          
          var errorText = 'Unlimited Elements Form Error: Name option must not contain spaces inside. Found in name: '+name;
          var consoleErrorText = "Space character in name found";
          
          showCustomError(objError, errorText, consoleErrorText);          
        }        
      }
      
      var dataDateMode = objCalcInput.data("date-mode");   
      
      //set formula input to date type
      if(dataDateMode == true)
        objCalcInput.attr("type", "date");
      
      var inputType = objInpput.attr("type");      
      var inputValue;     
      
      if(inputType != "date"){        
        inputValue = objInpput.val();    
        
        //if input is empty then count it as 0
        if(inputValue.length == 0)
          inputValue = 0;
        
        //see if input value is round number, if so - make sure the number is unformatted
        var dataSeparateThousandsFormat =  objInpput.data("separate-thousands-format");
        
        if(dataSeparateThousandsFormat == "de-DE"){          
          inputValue = Number(inputValue.replace(/\./g, "").replace(/,/g, ""));          
        }else{       
          //make sure value is number type (usefull for separating thousand option)
          inputValue = Number(inputValue.toString().replace(/,/g, ''));          
        }      		
        
        //add parentheses if valus is less then 0
        if(inputValue < 0)
          inputValue = "("+inputValue+")";	        
      }else{        
        inputValue = new Date(objInpput.val()).getTime();         
      }
      
      expr = expr.replace(name, inputValue);
      expr = expr.replace('[', '');
      expr = expr.replace(']', '');      
    });
    
    return(expr);    
  }
  
  /*
  * validate the expression
  */
  function validateExpression(expr){      
    //allow Math.something (math js operation), numbers, float numbers, math operators, dots, comas    
    var matches = expr.match(g_allowedSymbols);    
    var result = "";
    
    if (matches) 
      result = matches.join('');    
    
    expr = result;
    
    return(expr);    
  }
  
  /**
  * get result from expression
  */
  function getResult(expr, objError, objCalcInput) {    
    //if space just erase it    
    expr = expr.replace(/\s+/g, "");  
    
    //replace inputs name with its values
    expr = replaceNamesWithValues(expr, objError, objCalcInput);
    
    var result;
    
    //returan closest value from lookup table if needed
    var dataLookupTableMode = objCalcInput.data("lookup-table");
    
    if(dataLookupTableMode == true){      
      result = getClosestValue(objCalcInput, objError);
      
      return(result);      
    }    
    
    var dataDateMode = objCalcInput.data("date-mode");
    
    if(dataDateMode == true){      
      result = new Date(eval(expr));
      
      return(result);
    }
    
    //validate espression
    expr = validateExpression(expr);
    
    var errorText = `Unlimited Elements Form Error: wrong math operation: ${expr}`;
    var consoleErrorText = `Invalid operation: ${expr}`;
    
    //catch math operation error
    try{      
      result = eval(expr);
      
      //hide error message after successful calculation
      objError.hide();      
    }
    
    catch{            
      showCustomError(objError, errorText, consoleErrorText);      
    }
    
    if(isNaN(result) == true){      
      showCustomError(objError, errorText, consoleErrorText);      
    }
    
    return result;    
  }
  
  /**
  * get number formated in fractional number
  */
  function getFractionalResult(result, objCalcInput){    
    var dataCharNum = objCalcInput.data("char-num");    
    //replace coma woth period if needed here		
    var dataPeriod = objCalcInput.data("dot-instead-coma");
    
    if(dataPeriod == true){      
      //change type of the field to "text" (this makes coma change to dot)
      objCalcInput.attr("type", "text");
      
      return(result.toFixed(dataCharNum));        
    } else{      
      return(result.toFixed(dataCharNum))      
    }		    
  }
  
  /**
  * format result number
  */
  function formatResultNumber(result, objCalcInput){    
    var dataDateMode = objCalcInput.data("date-mode");
    
    if(dataDateMode == true){
      result =  result.toISOString().split('T')[0] 
      
      return(result);
    }
    
    var dataFormat = objCalcInput.data("format");
    
    if(dataFormat == "round")
      return(Math.round(result))
    
    if(dataFormat == "floor")
      return(Math.floor(result))
    
    if(dataFormat == "ceil")
      return(Math.ceil(result))
    
    if(dataFormat == "fractional")
      return(getFractionalResult(result, objCalcInput));    
  }
  
  /**
  * add coma to separate thousands
  */
  function getValueWithSeparatedThousands(val, objCalcInput){    
    //input can be "text" or "number" type (some old versions of Text Field widget has calculation mode)    
    var dataSeparateThousands = objCalcInput.data("separate-thousands");
    
    //if no such attribute exit function
    if(!dataSeparateThousands)
      return(val)
    
    //if it set to false exit too
    if(dataSeparateThousands == false)
      return(val);
    
    var inputType = objCalcInput.attr("type");
    
    //if type is not "text" then make it "text"
    if(inputType != "text")
      objCalcInput.attr("type", "text");
    
    var dataSeparateThousandsFormat = objCalcInput.data("separate-thousands-format");
    
    if(!dataSeparateThousandsFormat)
      dataSeparateThousandsFormat = "en-US";
    
    val = val.toString().split(".");
    
    //different format available only for round numbers, if number isn't round then format only with coma
    if(val.length > 1 && dataSeparateThousandsFormat == "en-US")
      val = parseFloat(val[0]).toLocaleString(dataSeparateThousandsFormat) + '.' + val[1];
    else
    val = parseFloat(val[0]).toLocaleString(dataSeparateThousandsFormat)
    
    return(val);    
  }
  
  /**
  * init calc mode
  */
  function setResult(objCalcInput, objError){    
    //if data formula is empty
    var dataFormula = objCalcInput.data("formula");
    
    if(dataFormula == undefined)
      return(false);
    
    //get result with numbers instead of fields name
    var result = getResult(dataFormula, objError, objCalcInput);
    
    //format result
    result = formatResultNumber(result, objCalcInput);
    
    //separate thousands
    result = getValueWithSeparatedThousands(result, objCalcInput);
    
    //set result to input
    objCalcInput.val(result);
    
    //set readonly attr if needed
    var dataRemoveReadonlyCalcMode = objCalcInput.data("remove-readonly-for-calc-mode");
    var inputType = objCalcInput.attr("type");
    
    if(dataRemoveReadonlyCalcMode == false || inputType != "number")
      objCalcInput.attr('readonly', '');    
  }
  
  /**
  * input change controll
  */
  function onInputChange(objCalcInput){    
    objCalcInput.trigger("input_calc");    
  }
  
  /**
  * get parent object
  */
  function getParentInput(dataName){    
    dataName = dataName.replace('[', '');
    dataName = dataName.replace(']', '');
    
    var objInput = jQuery(ueInputFieldSelector+'[name="'+dataName+'"]');
    
    return(objInput);    
  }
  
  /**
  * assign parent for lookup table fields
  */
  function assignParentsForLookupTable(objParent, parentAttrName){
    var parentIdAttribute = objParent.attr("id");
    var objFormula = objParent.find("[data-formula]");
    
    var dataXField = objFormula.data("field-name-x");
    var dataYField = objFormula.data("field-name-y");
    
    var objXField = getParentInput(dataXField);
    var objYField = getParentInput(dataYField);
    
    objXField.attr(parentAttrName, parentIdAttribute);
    objYField.attr(parentAttrName, parentIdAttribute);    
  }
  
  /**
  * remove duplicated values from array
  */
  function removeDuplicatesFromArray(arr) {    
    var uniqueArray = [];
    
    jQuery.each(arr, function(index, value) {
      
      //check each inique value if it's not another array
      if (jQuery.inArray(value, uniqueArray) === -1){        
        var valueArray = value.split(",");
        var valueArrayNum = valueArray.length;
        
        uniqueArray.push(value);        
      }      
    });
    
    return uniqueArray;
  }
  
  /**
  * assign parent calc number field input to each input inside formula
  */
  function assignParentNumberField(objParent, objError){    
    var objFormula = objParent.find("[data-formula]");
    var expr = objFormula.data("formula");
    var parentIdAttribute = objParent.attr("id");
    var parentAttrName = "data-parent-formula-input";
    var dataLookup = objFormula.data("lookup-table");
    
    if(dataLookup == true){      
      assignParentsForLookupTable(objParent, parentAttrName);
      
      return(false);      
    }
    
    var names = getFormulaNames(expr, objError);
    
    if(names == undefined || names == false)
      return(false);
    
    for(let i=0;i<names.length;i++){      
      var objInpput = getParentInput(names[i]); 
      var parentAttr = objInpput.attr(parentAttrName);     
      
      g_parents.push(parentIdAttribute);
      
      g_parents = removeDuplicatesFromArray(g_parents);
      
      //find if any inputs in formula are x / y field for some lookup table - if exist then push to g_parents parentAttr var
      var objParentLookupTableInputByXField = jQuery('[data-field-name-x="'+names[i]+'"]');
      var objParentLookupTableInputByYField = jQuery('[data-field-name-y="'+names[i]+'"]');
      var isXFiledForLookupTable = objParentLookupTableInputByXField && objParentLookupTableInputByXField.length > 0;
      var isYFiledForLookupTable = objParentLookupTableInputByYField && objParentLookupTableInputByYField.length > 0;
      
      //for lookup tables (if already exist parent copy its name)
      if(parentAttr !== undefined && isXFiledForLookupTable == true || parentAttr !== undefined && isYFiledForLookupTable == true){        
        g_parents.push(parentAttr);
      }
      
      objInpput.attr(parentAttrName, g_parents);    
    }  
  }
  
  /**
  * Parse the CSV data into a two-dimensional array
  */
  function getLookupTable(csvData){    
    csvData = csvData.split('\n').map(function (row) {
      return row.split(',');
    });
    
    return(csvData);    
  }
  
  // Function to calculate the Euclidean distance between two points (width, height)
  function euclideanDistance(x1, y1, x2, y2) {    
    return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));    
  }
  
  /**
  * find closest value
  */
  function getClosestValue(objCalcInput, objError) {    
    var dataX = objCalcInput.data("field-name-x");
    var dataY = objCalcInput.data("field-name-y");    
    var objXField = getParentInput(dataX);
    var objYField = getParentInput(dataY);    
    var csvData = objCalcInput.data("csv");
    var xValue = objXField.val();
    var yValue = objYField.val();    
    //format csv table
    var lookupTable = getLookupTable(csvData);
    
    if(!xValue){      
      var errorText = 'Unlimited Elements Form Error: no x-value found.';
      var consoleErrorText = 'Unlimited Elements Form Error: no x-value found.';
      
      showCustomError(objError, errorText, consoleErrorText);      
    }
    
    if(!yValue){      
      var errorText = 'Unlimited Elements Form Error: no y-value found.';
      var consoleErrorText = 'Unlimited Elements Form Error: no y-value found.';
      
      showCustomError(objError, errorText, consoleErrorText);      
    }
    
    //hide error object in case of successful calculation
    objError.hide();
    
    var closestValue = null;
    var closestDistance = Infinity;
    
    for (var row = 1; row < lookupTable.length; row++) {      
      for (var col = 1; col < lookupTable[row].length; col++) {        
        var tableValue = lookupTable[row][col];
        var tableX = lookupTable[0][col];
        var tableY = lookupTable[row][0];
        var distance = euclideanDistance(xValue, yValue, tableX, tableY);
        
        if (distance < closestDistance) {          
          closestDistance = distance;
          closestValue = tableValue;          
        }        
      }      
    }
    
    return +closestValue;    
  }
  
  /**
  * get parent input calc
  */
  function getParentCalcInput(objInput){    
    var parentsArray = objInput.attr("data-parent-formula-input");    
    var objParentsArray = [];
    
    //make sure attr is an array
    if(parentsArray != undefined){      
      parentsArray = parentsArray.split(",");
      
      parentsArray.forEach(function(id, index){        
        var parentId = id;
        var objParentCalcInput = jQuery("#"+parentId).find("[data-calc-mode='true']");

        if(!objParentCalcInput || objParentCalcInput.length == 0)
          objParentCalcInput = jQuery("#"+parentId).find("[data-calc-mode='1']");
        
        objParentsArray.push(objParentCalcInput);        
      });
      
      return(objParentsArray);      
    }    
  }
  
  /**
  * show main input
  */
  function showField(objFieldWidget, classHidden, elementorHiddenClass){    
    objFieldWidget.removeClass(classHidden);
    
    var objParentElementorElement = objFieldWidget.closest(elementorElementSelector);
    
    objParentElementorElement.removeClass(elementorHiddenClass);    
  }
  
  /**
  * hide main input
  */
  function hideField(objFieldWidget, classHidden, elementorHiddenClass){    
    objFieldWidget.addClass(classHidden);
    
    //hide parent elementor-element container to avoid unnecessary gap
    var objParentElementorElement = objFieldWidget.closest(elementorElementSelector);
    
    objParentElementorElement.addClass(elementorHiddenClass);
  }
  
  /**
  * get condition
  */
  function getConditions(condition, objFieldValue, fieldValue){ 
    var visibilityCondition;
    switch (condition) {
      case "=":
      
      visibilityCondition = objFieldValue == fieldValue;
      
      break;
      case ">":
      
      visibilityCondition = objFieldValue > fieldValue;
      
      break;
      case ">=":
      
      visibilityCondition = objFieldValue >= fieldValue;
      
      break;
      case "<":
      
      visibilityCondition = objFieldValue < fieldValue;
      
      break;
      case "<=":
      
      visibilityCondition = objFieldValue <= fieldValue;
      
      break;
      case "!=":
      
      visibilityCondition = objFieldValue != fieldValue;
      
      break;      
    }
    
    return(visibilityCondition);    
  }
  
  /**
  * get operator
  */
  function getOperators(operator, visibilityOperator){    
    switch (operator){
      
      case "and":
      
      visibilityOperator = "&&";
      
      break;
      case "or":
      
      visibilityOperator = "||";
      
      break;      
    }   
    
    return(visibilityOperator);    
  }
  
  
  /**
  * get names
  */
  function getNames(arrNames, fieldName){    
    arrNames = [];
    arrNames.push(fieldName);
    
    return(arrNames);    
  }
  
  /**
  * equal condition and input names error
  */
  function equalConditionInputNameError(objField, arrNames, classError){    
    var inputName = objField.attr("name");    
    var isNamesEqual = arrNames.indexOf(inputName) != -1;
    
    if(isNamesEqual == true){
      var conditionStyles = 'color:red;font-size:12px;padding:5px;border:1px solid #CE5F5F;border-radius:5px;width:100%';
      var errorHtml = "<div class="+classError+" style='"+conditionStyles+"'>Unlimited Field Error: can't set condition. Condition Item Name equals Field Name: [ " + inputName + " ]. Please use different names.</div>";
      
      jQuery(errorHtml).insertBefore(objField.parent());      
    }    
  }
  
  /**
  * set visibility in editor
  */
  function setVisibilityInEditor(objFieldWidget, classError, classHidden){      
    var hiddenHtml = "<div class="+classError+">Unlimited Field is hidden due to Visibility Condition Options. <br> This message shows only in editor.</div>";
    var objError = objFieldWidget.find("."+classError);
    
    if(objFieldWidget.hasClass(classHidden) == true){      
      if(!objError || !objError.length)
        objFieldWidget.prepend(hiddenHtml);
      
    }else{      
      if(objError && objError.length)
        objError.remove();
    }    
  }
  
  /**
  * check if calculator input includes invisible inputs
  */
  function checkInvisibleInputsInFormula(){    
    //if no calc mode inpu found on page - do nothing
    if(!g_objCalcInputs.length)
      return(false);			
    
    //look after each calc mode input field on a page
    g_objCalcInputs.each(function(){      
      var objCalcInput = jQuery(this);
      
      //find main warapper of the widget
      var objCalcWidget = objCalcInput.parents(ueNumberSelector);		
      var objError = objCalcWidget.find(ueNumberErrorSelector);
      var formula = objCalcInput.data('formula');
      
      if(!formula)
        return(true);
      
      var names = getFormulaNames(formula, objError);
      
      if(names == undefined || names == false)
        return(false);
      
      names.forEach(function(name, index){        
        var objInpput = jQuery(ueInputFieldSelector+'[name="'+name+'"]');
        
        //check if field is hidden due to condition
        // if(objInpput.is(':visible') == false){
        
        //   var errorText = 'Unlimited Elements Form Error: Field is invisible on the page, but contains in formula: '+name+'.';
        //   var consoleErrorText = `Field is invisible on the page, but contains in formula: ${name}`;
        
        //   showCustomError(objError, errorText, consoleErrorText);
        
        // }
        
      });      
    });        
  }
  
  /**
  * recalculate parent inputs
  */
  function recalculateParentInputs(objParentCalkInputs){    
    if(objParentCalkInputs != undefined){
      
      objParentCalkInputs.forEach(function(parent, index){        
        onInputChange(parent);                  
      });
    }    
  }
  
  /**
  * create condition visual for Editor
  */
  function setConditionVisualInEditor(obj, operator, fieldName, condition, fieldValue, conditionsNum, conditions){
    var conditionClass = "ue-form-condition";
    var conditionStyles = 'color:#000;font-size:12px;padding:5px;border:1px solid grey;background-color:lightgrey;border-radius:5px;width:100%;margin-top:5px';
    var conditionHtml = `<div class="${conditionClass}" data-condition="['${operator}', '${fieldName}', '${condition}', '${fieldValue}']" style="${conditionStyles}">Visibility Condition: "${operator} ${fieldName} ${condition} ${fieldValue}"</div>`;
    var objCondition = obj.find(`[data-condition="['${operator}', '${fieldName}', '${condition}', '${fieldValue}']"]`);
    var objAllConditions = obj.find(`.${conditionClass}`);
    var visualConditionsNum = objAllConditions.length;
    
    if(!objCondition || !objCondition.length){      
      obj.append(conditionHtml);
      
      //remove unnecesary visual condition in editor (currently not doing anything)
      if(visualConditionsNum > conditionsNum){       
        
        objAllConditions.each(function(){
          var objCondition = jQuery(this);
          var dataCondition = objCondition.data("condition").replace(/'/g, '"');
          var currentConditionAttr = JSON.parse(dataCondition);
          var currentOperator = currentConditionAttr[0];
          var currentFieldName = currentConditionAttr[1];
          var currentCondition = currentConditionAttr[2];
          var currentFieldValue = currentConditionAttr[3];
          
          for(let i=0; i<conditionsNum; i++){
            
            var conditionArray = conditions[i];
            var operator = conditionArray.operator;
            var fieldName = conditionArray.field_name;
            var condition = conditionArray.condition;
            var fieldValue = parseFloat(conditionArray.field_value);
            
            if(operator == currentOperator && fieldName == currentFieldName && condition == currentCondition && fieldValue == currentFieldValue)
              return(true);
          }      
        });
      }
    }
  }
  
  /**
  * check if number 
  */
  function isNumber(value) {
    return !isNaN(value) && !isNaN(parseFloat(value));
  }
  
  /*
  * process the visibility array
  */
  t.setVisibility = function(conditionArray, widgetId){	      
    var objFieldWidget = jQuery("#"+widgetId);
    var classHidden = "ucform-has-conditions";
    var elementorHiddenClass = "elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-hidden-widescreen elementor-hidden-laptop";
    var classError = "ue-error";
    
    var conditions = conditionArray.visibility_conditions;
    
    if(!conditions || conditions.length == 0)
      return(false);
    
    var conditionsNum = conditions.length;
    var totalVisibilityCondition;
    
    //create val to contain all the names for errors catching purposes
    var arrNames;
    
    for(let i=0; i<conditionsNum; i++){      
      var conditionArray = conditions[i];
      var condition = conditionArray.condition;
      var fieldName = conditionArray.field_name;
      var fieldValue = conditionArray.field_value;

      if(isNumber(fieldValue) == true)
        fieldValue = parseFloat(fieldValue);

      var operator = conditionArray.operator;
      var id = conditionArray._id;
      
      var objField = jQuery(ueInputFieldSelector+'[name="'+fieldName+'"]');
      var isInEditor = objField.data("editor");
      
      var objFieldValue = objField.val();
      
      if(isNumber(objFieldValue) == true)
        objFieldValue = parseFloat(objFieldValue);
      
      //sets the condition: "==", ">", "<" ...
      var visibilityCondition = getConditions(condition, objFieldValue, fieldValue);
    
      //set the conditions: "&&", "||"
      var visibilityOperator = getOperators(operator, visibilityOperator);             
      
      //if only one item exist - ignore the condition ("&&", "||")
      if(i == 0)
        totalVisibilityCondition = visibilityCondition;
      
      if(i > 0)
        totalVisibilityCondition += visibilityOperator + visibilityCondition;      
      
      //show error if condition name equals input field name
      arrNames = getNames(arrNames, fieldName);
      
      var objInputField = objFieldWidget.find(ueInputFieldSelector);
      
      equalConditionInputNameError(objInputField, arrNames, classError);
      
      if(isInEditor == "yes")
        setConditionVisualInEditor(objFieldWidget, operator, fieldName, condition, fieldValue, conditionsNum, conditions);      
    }
    
    var isInEditor = objField.data("editor");
    
    if(eval(totalVisibilityCondition) == true){
      
      showField(objFieldWidget, classHidden, elementorHiddenClass);
      
      if(isInEditor == "yes"){
        // setVisibilityInEditor(objFieldWidget, classError, classHidden);
      }      
    }
    
    if(eval(totalVisibilityCondition) == false){            
      hideField(objFieldWidget, classHidden, elementorHiddenClass);
      
      if(isInEditor == "yes"){        
        // setVisibilityInEditor(objFieldWidget, classError, classHidden);
      }      
    }
    
    //check if in formula exists invisible field
    checkInvisibleInputsInFormula();    
  }
  
  /**
  * init the form
  */
  t.init = function(){    
    
    //if no calc mode inpu found on page - do nothing  
    if(!g_objCalcInputs.length)
      return(false);
    
    //look after each calc mode input field on a page
    g_objCalcInputs.each(function(){      
      var objCalcInput = jQuery(this);
      
      //find main warapper of the widget
      var objCalcWidget = objCalcInput.parents(ueNumberSelector);		
      var objError = objCalcWidget.find(ueNumberErrorSelector);
      
      //assign parent calc input number field widget for each ue field input that is inside formula of the number filed
      assignParentNumberField(objCalcWidget, objError);
      
      //set result in input
      setResult(objCalcInput, objError);    
      
      //set result on custom shange event
      objCalcInput.on('input_calc', function(){
        
        var objInput = jQuery(this); //triggered input        
        
        setResult(objInput, objError);
        
        var objParentCalkInputs = getParentCalcInput(objInput); //parent calc input with formula attr
        
        if(objParentCalkInputs != undefined){          
          objParentCalkInputs.forEach(function(parent, index){            
            var objParentError = parent.find(ueNumberErrorSelector);
            
            setResult(parent, objParentError);   
          });
        }        
      });      
    });
    
    //init events
    var objAllInputFields = jQuery(ueInputFieldSelector);
    
    //on input change trigger only parent calc number field, not all of them
    objAllInputFields.on('input', function(){      
      var objInput = jQuery(this); //triggered input
      var objParentCalkInputs = getParentCalcInput(objInput); //parent calc input with formula attr
      
      recalculateParentInputs(objParentCalkInputs); 
    });
    
    objAllInputFields.each(function(){      
      var objInput = jQuery(this); //triggered input
      var objParentCalkInputs = getParentCalcInput(objInput); //parent calc input with formula attr
      var dataCalcMode = objInput.data("calc-mode");
      
      if(dataCalcMode === false)
        return(true);
      
      recalculateParentInputs(objParentCalkInputs);      
    });
    
  }
  
  /**
  * init vars
  */
  function initVars(){    
    //selector
    ueInputFieldSelector = ".ue-input-field";
    ueNumberSelector = ".ue-number, .ue-content";
    ueNumberErrorSelector = ".ue-number-error";
    ueOptionFieldSelector = ".ue-option-field";
    elementorElementSelector = ".elementor-element";
    
    //objects
    g_objCalcInputs = jQuery(ueInputFieldSelector+'[data-calc-mode="true"], '+ueInputFieldSelector+'[data-calc-mode="1"]');
    
    //helpers
    g_allowedSymbols = /Math\.[a-zA-Z]+|\d+(?:\.\d+)?|[-+*/().,]+/g;
    
  }  
  initVars();  
}

var g_ucUnlimitedForms = new UnlimitedElementsForm();

setTimeout(function(){
g_ucUnlimitedForms.init();	
}, 2000);


jQuery( document ).on( 'elementor/popup/show', (event, id, objPopup) => {  
  var g_ucUnlimitedForms = new UnlimitedElementsForm();
  
  g_ucUnlimitedForms.init();  
});	

//template switcher script
jQuery(document).ready(function(){
  jQuery("body").on("uc_tsw_updated", function(){
    var g_ucUnlimitedForms = new UnlimitedElementsForm();
    
    g_ucUnlimitedForms.init();	
  });
});