export const input_mask = function (
  actionP,
  valP,
  typeP,
  maskP,
  elemP,
  grid_objP,
  grid_row_idP,
  grid_col_idP,
  dsSessionP
) {
  // TEXT
  // ===================
  // 25 or AAA or aaa or Aaa or (AAA) XXX
  // X = Alpha numeric input
  // A = uppercase
  // a = lowercase
  // # = number digit
  // /T - auto tab
  // NUMERIC
  // ===================
  // 3 or 2.2
  //  ##.## - number mask
  // /T - auto tab
  // /A - auto fill
  // /+[custom char] - add + sign
  // /-[custom char] - add - sign (alow negative values)
  // /Z[custom char] - padding with zeros
  // /N[custom char] - null when zero
  // /C[custom char] - add custom character
  // /+[custom char]/-[custom char]/$/99.99/%/ZERO or Z[custom char]/NULL or N[custom char]/T
  // actionP :
  // init = initiate an input field
  // get = return masked val
  // val = return original val
  var nonCharPatt = /\W/;
  var wordPatt = /[A-Z,a-z]/;
  var digitPatt = /\d/;
  const get_properties = function (typeP, maskP) {
    var ret = {
      custom_pfx: false,
      customChar_pfx: "",
      positive_pfx: false,
      positiveChar_pfx: "+",
      negative_pfx: false,
      negativeChar_pfx: "-",
      size: 0,
      whole: 0,
      decimal: 0,
      zeros: false,
      zerosChar: "0",
      do_null: false,
      nullChar: "",
      autoTab: false,
      autoFill: false,
      negative_sfx: false,
      negativeChar_sfx: "",
      positive_sfx: false,
      positiveChar_sfx: "",
      custom_sfx: false,
      customChar_sfx: "",
      type: typeP,
      mask: "",
      maskPos: null,
      error: "",
    };
    var get_char = function (valP, defaultP) {
      var ret = defaultP;
      if (valP.length > 1) ret = valP.substr(1, valP.length);
      return ret;
    };
    var fill_mask = function (lenP, charP) {
      var s = "";
      for (var i = 0; i < lenP; i++) {
        s += charP;
      }
      return s;
    };
    var mask_Arr = maskP.split("/");
    // find mask pos

    _.forEach(mask_Arr, function (val, key) {
      if (typeP === "number") {
        if (/[0-9.#]/.test(val) && !/[TNCZ+-]/.test(val.substr(0, 1)))
          ret.maskPos = key;
      }
      if (typeP === "string") {
        if (/[0-9XAaUL#]/.test(val) && !/[T]/.test(val.substr(0, 1)))
          ret.maskPos = key;
      }
    });
    if (ret.maskPos === null) {
      ret.error = "SYS_MSG_0612 - missing mask definition";
      return ret;
    }
    // make mask
    var mask = mask_Arr[ret.maskPos];
    if (typeP === "number") {
      var whole = mask.split(".")[0];
      var decimal = mask.split(".")[1];
      if (whole && whole > 15) {
        ret.error = "SYS_MSG_0632 - Too big";
        return ret;
      }
      if (decimal && decimal > 5) {
        ret.error = "SYS_MSG_0632 - Too big";
        return ret;
      }
      if (
        /\D/.test(whole) // find non digit for whole
      )
        ret.mask = whole;
      else ret.mask = fill_mask(whole, "#");
      if (decimal && ret.mask) {
        if (
          /\D/.test(decimal) // find non digit for decimal
        )
          ret.mask += "." + decimal;
        else ret.mask += "." + fill_mask(decimal, "#");
      }
    }
    if (typeP === "string") {
      if (/\D/.test(mask)) {
        // find non digit
        // ret.mask = mask;
        if (/\d/.test(mask)) {
          // check if digit exist
          var patt = /[ULXAa#]/g;
          var str = "";
          var Arr = [];
          for (var i = 0; i <= mask.length; i++) {
            var val = mask.substr(i, 1);
            if (patt.test(val)) str += "@" + val;
            else str += val;
          }
          var s = str.split("@");
          for (var i = 1; i <= s.length - 1; i++) {
            Arr[i - 1] = fill_mask(s[i].substr(1), s[i].substr(0, 1));
          }
          ret.mask = Arr.join(""); // U1L10
        } else ret.mask = mask; // mixed UUUAAA
        //console.log(Arr.join(""))
      } else ret.mask = fill_mask(mask, "X"); // only digits eg. 25
    }
    if (!ret.mask) {
      ret.error = "SYS_MSG_0614 - wrong mask definition";
      return ret;
    }
    // get size
    var patt = /[#]/g;
    if (typeP === "number") {
      if (ret.mask.match(patt)) {
        ret.size = ret.mask.match(patt).join("").length;
        ret.whole = ret.mask.split(".")[0].match(patt).join("").length;
        if (ret.mask.split(".")[1])
          ret.decimal = ret.mask.split(".")[1].match(patt).join("").length;
      }
    }
    patt = /[X#AaUL]/g;
    if (typeP === "string") {
      if (ret.mask.match(patt)) ret.size = ret.mask.match(patt).join("").length;
    }
    if (!ret.size) {
      ret.error = "SYS_MSG_0616 - size parser";
      return ret;
    }
    for (let [key, val] of Object.entries(mask_Arr)) {
      if (!val) continue;
      if (val.trim() === "Z" || val.substr(0, 1) === "Z") {
        ret.zeros = true;
        ret.zerosChar = get_char(val, "0");
        if (typeP === "string")
          ret.error = "SYS_MSG_0618 - Illegal 'Z' in string mask";
        continue;
      } else {
        if (val.trim() === "N" || val.substr(0, 1) === "N") {
          ret.do_null = true;
          ret.nullChar = get_char(val, "");
          if (typeP === "string")
            ret.error = "SYS_MSG_0620 - Illegal 'N' in string mask";
          continue;
        } else {
          if (val.trim() === "+" || val.substr(0, 1) === "+") {
            if (key < ret.maskPos) {
              ret.positive_pfx = true;
              ret.positiveChar_pfx = get_char(val, "+");
            }
            if (key > ret.maskPos) {
              ret.positive_sfx = true;
              ret.positiveChar_sfx = get_char(val, "+");
            }
            if (typeP === "string" && val.trim() === "+")
              ret.error = "SYS_MSG_0622 - Illegal '+' in string mask";
            continue;
          } else {
            if (val.trim() === "-" || val.substr(0, 1) === "-") {
              if (key < ret.maskPos) {
                ret.negative_pfx = true;
                ret.negativeChar_pfx = get_char(val, "-");
              }
              if (key > ret.maskPos) {
                ret.negative_sfx = true;
                ret.negativeChar_sfx = get_char(val, "-");
              }
              if (typeP === "string" && val.trim() === "-")
                ret.error = "SYS_MSG_0624 - Illegal '-' in string mask";
              continue;
            } else {
              if (val.trim() === "C" || val.substr(0, 1) === "C") {
                if (key < ret.maskPos) {
                  ret.custom_pfx = true;
                  ret.customChar_pfx = get_char(val, "C");
                }
                if (key > ret.maskPos) {
                  ret.custom_sfx = true;
                  ret.customChar_sfx = get_char(val, "C");
                }
                if (typeP === "string" && val.trim() === "C")
                  ret.error = "SYS_MSG_0626 - Illegal 'C' in string mask";
                continue;
              } else {
                if (val.trim() === "T" || val.substr(0, 1) === "T") {
                  ret.autoTab = true;
                  continue;
                } else {
                  if (key !== ret.maskPos)
                    ret.error = "SYS_MSG_0628 - invalid /" + val + " switch";
                }
              }
            }
          }
        }
      }
    }
    return ret;
  };
  const run_mask = function (dataP, validateP, prev_val, mask) {
    //        if (!dataP && dataP !== "" && dataP !== "0")
    //            return;
    var str = "";
    var i = -1;
    var prop = get_properties(typeP, mask);
    if (prop.error) return prop.error;
    if (typeP === "number") {
      var fill_zeros = function (maskLenP, valLenP, charP) {
        var s = "";
        for (var i = 0; i < maskLenP - valLenP; i++) {
          if (charP) s += charP;
          else s += "0";
        }
        return s;
      };
      var str_pfx = prop.customChar_pfx;
      if (prop.positive_pfx && dataP > 0) str_pfx += prop.positiveChar_pfx;
      if (prop.negative_pfx && dataP < 0) str_pfx += prop.negativeChar_pfx;
      var str_sfx = "";
      if (prop.negative_sfx && dataP < 0) str_sfx += prop.negativeChar_sfx;
      if (prop.positive_sfx && dataP > 0) str_sfx += prop.positiveChar_sfx;
      str_sfx += prop.customChar_sfx;
      if (dataP && dataP !== "0") {
        var val_whole = Math.abs(dataP.toString().split(".")[0]).toString();
        var val_decimal = dataP.toString().split(".")[1];
        var whole_truncated = val_whole;
        if (val_whole.length > prop.whole)
          whole_truncated = val_whole.substr(
            val_whole.length - prop.whole,
            val_whole.length
          ); // truncate only when mask length  bigger then value
        if (prop.zeros)
          str +=
            fill_zeros(prop.whole, whole_truncated.length, prop.zerosChar) +
            whole_truncated;
        // do padding
        else str += whole_truncated; // truncate whole acording the mask
        if (prop.decimal) {
          if (val_decimal)
            str +=
              "." +
              val_decimal +
              fill_zeros(prop.decimal, val_decimal.length, prop.zerosChar);
          // fill zeroz for fraction
          else str += "." + fill_zeros(prop.decimal, 0, prop.zerosChar); // fill zeroz for fraction
        }
      } else {
        // no data exist
        if (prop.zeros) str = fill_zeros(prop.whole, 0);
        // do padding
        else str = "0";
        if (prop.decimal)
          str += "." + fill_zeros(prop.decimal, 0, prop.zerosChar); // fill zeroz for fraction
      }
      if (prop.do_null && (!dataP || dataP === "0")) str = prop.nullChar;
      else str = str_pfx + str + str_sfx;
      return str;
    }
    if (typeP === "string") {
      var err;

      for (var x = 0; x <= prop.mask.length; x++) {
        var val = prop.mask.substr(x, 1);
        if (!dataP) return;
        if (dataP.length > i) {
          if (nonCharPatt.test(val) && val !== "#") {
            str += val;
          } else {
            i++;
            //                    var s = dataP.substr(i, 1);
            var s = "";
            s = dataP.substr(i, 1);
            if (val === "X") {
              // X = mixed
              str += s;
            }
            if (val === "U") {
              // U = uppercase only
              if (wordPatt.test(s) || s === " ") str += s.toUpperCase();
            }
            if (val === "A") {
              // A = uppercase
              str += s.toUpperCase();
            }
            if (val === "a") {
              // a = lowercase
              str += s.toLowerCase();
            }
            if (val === "L") {
              // L = lowercase only
              if (wordPatt.test(s) || s === " ") str += s.toLowerCase();
            }
            if (val === "#") {
              // # = digit
              if (digitPatt.test(s)) str += s;
            }
          }
        }
      }
      //            });
      if (validateP && err) return prev_val;
      else return str;
    }
  };

  var run_value = function (dataP, mask) {
    if (!dataP) return;
    var str = "";
    if (typeP === "string") {
      if (mask)
        for (var i = 0; i <= dataP.length; i++) {
          var val = dataP.substr(i, 1);
          var s = mask.substr(i, 1);
          if (s === val && nonCharPatt.test(s) && s !== "#") str += "";
          // return; //true;
          else str += val;
        }
    }
    if (typeP === "number") {
      var patt = /[0-9-.]/g;
      var arr = dataP.toString().match(patt);
      if (arr && arr.length > 0) str = parseFloat(arr.join(""));
    }
    return str;
  };

  if (actionP === "init") {
    if (!elemP) return "SYS_MSG_0630 - Missing DOM Element";
    $(elemP).data({
      mask: maskP,
    });
    $(elemP).off("keypress.mask");
    $(elemP).on("keypress.mask", function (e) {
      var _this = this;
      setTimeout(function () {
        var prev_val = $(_this).data("prev_val");
        var mask = $(_this).data("mask");
        var prop = get_properties(typeP, mask);
        //                var is_autoTab = prop.autoTab;
        // return on non character key
        if (
          typeP === "number" &&
          !/[0-9-.+]/.test(String.fromCharCode(e.keyCode))
        ) {
          e.preventDefault();
          return false;
        }
        var val = $(_this).val();
        if (typeP === "string" && val) {
          var res = run_mask(run_value(val, mask), true, prev_val, mask);
          $(_this).val(res).data({
            prev_val: res,
          });
        }
        // if (grid_objP) {
        //   // auto skip for grid
        //   if (run_value(val, mask).toString().length >= prop.size)
        //     func.UI.grid.next_field(
        //       grid_objP,
        //       grid_row_idP,
        //       grid_col_idP,
        //       dsSessionP
        //     );
        // }
      }, 50);
    });
    $(elemP).off("blur.mask");
    $(elemP).on("blur.mask", function (e) {
      var prev_val = $(this).data("prev_val");
      var mask = $(this).data("mask");
      var val = $(this).val();
      // return on non character key
      if (typeP === "number" && !/[0-9-.+]/.test(val)) return;
      if (typeP === "number" && val) {
        var res = run_mask(run_value(val, mask), true, prev_val, mask);
        $(this).val(res).data({
          prev_val: res,
        });
        setTimeout(function () {
          if (grid_objP)
            grid_objP.cells(grid_row_idP, grid_col_idP).setValue(res);
        }, 50);
      }
    });
  }
  if (actionP === "get") return run_mask(valP, null, null, maskP);
  if (actionP === "val") return run_value(valP, maskP);
  if (actionP === "properties") {
    var prop = {};
    prop = get_properties(typeP, maskP);
    if (valP) prop.val_size = run_value(valP, maskP).toString().length;
    return prop;
  }
};
