const loading = {
  show: () => {
    $("#loading").show();
  },
  hide: () => {
    $("#loading").hide();
  },
};

// Escape text for output in HTML
function escapeHtml(text) {
  return String(text)
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#039;")
    .replace(/\n/g, "<br/>");
}

function humanReadableConstName(name) {
  if (!name) {
    return "";
  }

  let nameLower = name.toLowerCase();
  let nameUpper = name.toUpperCase();
  let result = "";

  for (let i = 0; i < name.length; i++) {
    if (i == 0) {
      result = result.concat(nameUpper[i]);
    } else if (name[i] == nameUpper[i]) {
      result = result.concat(" ", nameUpper[i]);
    } else {
      result = result.concat(nameLower[i]);
    }
  }
  return result;
}

function formatDate(date) {
  date = new Date(date);
  return (
    date.getFullYear().toString() +
    (date.getMonth() + 1).toString().padStart(2, "0") +
    date.getDate().toString().padStart(2, "0")
  );
}

function timeStampNowText() {
  let timestamp = new Date();
  let textHour = String(timestamp.getHours());
  textHour = "0".repeat(2 - textHour.length).concat(textHour);
  let textMinute = String(timestamp.getMinutes());
  textMinute = "0".repeat(2 - textMinute.length).concat(textMinute);
  let textSecond = String(timestamp.getSeconds());
  textSecond = "0".repeat(2 - textSecond.length).concat(textSecond);
  //let textMSec = String(timestamp.getMilliseconds());
  //textMSec = '0'.repeat(3 - textMSec.length).concat(textMSec);
  //let textTimestamp = `[${textHour}:${textMinute}:${textSecond}.${textMSec}] `;
  return `${textHour}:${textMinute}:${textSecond}`;
}

// helper method logging data in an easier to read form. returns a string with each property
// located on a new line and indenting (a string usually with empty spaces) child objects.
// the first line is not indented so a recursive call can be used
function dumpValue(value, prefix, specialPrefix) {
  let string;

  if (!prefix) {
    prefix = "";
  }
  if (!specialPrefix) {
    specialPrefix = "";
  }

  if (Array.isArray(value)) {
    string = dumpValueArray(value, prefix, specialPrefix);
  } else if (value instanceof Map) {
    string = dumpValueMap(value, prefix, specialPrefix);
  } else if (value instanceof Set) {
    string = dumpValueSet(value, prefix, specialPrefix);
  } else if (value instanceof timapi.constants.EnumValue) {
    string = `constant(.${value.name})`;
  } else if (value instanceof Uint8Array) {
    string = dumpValueUint8Array(value, 8);
  } else if (typeof value === "object" && value !== null) {
    string = dumpValueObject(value, prefix, specialPrefix);
  } else {
    string = String(value).split("\n").join(`\n${specialPrefix}`);
  }

  return string;
}

function dumpValueArray(value, prefix, specialPrefix) {
  let string;

  if (value.length > 0) {
    let childSpecialPrefix = `${prefix}  `;
    let childPrefix = `${prefix}| `;
    let last = value.length - 1;
    string = `Array(${value.length} entries)`;

    for (let index in value) {
      if (index == last) {
        string = string.concat(
          `\n${prefix}+ ${dumpValue(
            value[index],
            `${prefix}  `,
            childSpecialPrefix
          )}`
        );
      } else {
        string = string.concat(
          `\n${prefix}+ ${dumpValue(
            value[index],
            childPrefix,
            childSpecialPrefix
          )}`
        );
      }
    }
  } else {
    string = "Array(0 entries)";
  }

  return string;
}

function dumpValueMap(value, prefix, specialPrefix) {
  let string;

  if (value.size > 0) {
    let childPrefix = `${prefix}| `;

    string = `Map(${value.size} entries)`;
    let propertyNames = Array.from(value.keys()).sort();
    let count = propertyNames.length;
    let last = value.size - 1;

    for (let index in propertyNames) {
      let propertyName = propertyNames[index];
      let propertyValue = value.get(propertyName);
      let childSpecialPrefix = prefix.concat(
        " ".repeat(propertyName.length + 5)
      );

      if (index == last) {
        string = string.concat(
          `\n${prefix}+ ${propertyName} = ${dumpValue(
            propertyValue,
            `${prefix}  `,
            childSpecialPrefix
          )}`
        );
      } else {
        string = string.concat(
          `\n${prefix}+ ${propertyName} = ${dumpValue(
            propertyValue,
            childPrefix,
            childSpecialPrefix
          )}`
        );
      }
    }
  } else {
    string = "Map(0 entries)";
  }

  return string;
}

function dumpValueSet(value, prefix, specialPrefix) {
  let string;

  if (value.size > 0) {
    let childSpecialPrefix = `${prefix}  `;
    let childPrefix = `${prefix}| `;
    let entries = Array.from(value.values());
    let last = entries.length - 1;
    string = `Set(${entries.length} entries)`;

    for (let index in entries) {
      if (index == last) {
        string = string.concat(
          `\n${prefix}+ ${dumpValue(
            entries[index],
            `${prefix}  `,
            childSpecialPrefix
          )}`
        );
      } else {
        string = string.concat(
          `\n${prefix}+ ${dumpValue(
            entries[index],
            childPrefix,
            childSpecialPrefix
          )}`
        );
      }
    }
  } else {
    string = "Set(0 entries)";
  }

  return string;
}

function dumpValueUint8Array(binaryContent, num) {
  if (binaryContent == undefined) {
    return "undefined";
  }
  let s = "Uint8Array(";
  let i = 0;

  for (i = 0; i < binaryContent.length && (i < num || num === undefined); i++) {
    s += `0x${binaryContent[i].toString(16)},`;
  }
  if (i < binaryContent.length) {
    s += "...";
  } else {
    // remove last comma
    s = s.substring(0, s.length - 1);
  }
  s += ")";
  return s;
}

function dumpValueObject(value, prefix, specialPrefix) {
  let string;

  if (value.hasOwnProperty("code") && value.hasOwnProperty("exponent")) {
    string = `Currency(.${value.code})`;
  } else {
    let unfilteredPropertyNames = Object.getOwnPropertyNames(value).sort();
    let className = value.constructor.name ? value.constructor.name : "Object";

    // filter all hidden properties
    let propertyNames = [];
    for (let propertyName of unfilteredPropertyNames) {
      if (!propertyName.startsWith("_") && value[propertyName] !== undefined) {
        propertyNames.push(propertyName);
      }
    }

    if (propertyNames.length == 0) {
      string = `${className}(0 properties)`;
    } else {
      let childPrefix = `${prefix}| `;

      if (propertyNames.length == 1) {
        string = `${className}(1 property)`;
      } else {
        string = `${className}(${propertyNames.length} properties)`;
      }
      let last = propertyNames.length - 1;

      for (let index in propertyNames) {
        let propertyName = propertyNames[index];
        let propertyValue = value[propertyName];
        let childSpecialPrefix = prefix.concat(
          " ".repeat(propertyName.length + 5)
        );

        if (index == last) {
          string = string.concat(
            `\n${prefix}+ ${propertyName} = ${dumpValue(
              propertyValue,
              `${prefix}  `,
              childSpecialPrefix
            )}`
          );
        } else {
          string = string.concat(
            `\n${prefix}+ ${propertyName} = ${dumpValue(
              propertyValue,
              childPrefix,
              childSpecialPrefix
            )}`
          );
        }
      }
    }
  }

  return string;
}

function colorHexToRgb(hexValue) {
  let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hexValue);
  if (result) {
    return {
      r: parseInt(result[1], 16),
      g: parseInt(result[2], 16),
      b: parseInt(result[3], 16),
    };
  }
  return null;
}

function isValidInputMachineID(str) {
  if (str == null || str.length > 16) {
    return false;
  }
  //字母，数字或横线
  var $sz = "^[A-Za-z0-9]+$";
  var urlReg = new RegExp($sz);
  return urlReg.test(str);
}

function isValidInputAddress(str) {
  if (str == null || str.length < 4) {
    return false;
  }
  var domainRegExp =
    "^(?=^.{3,255}$)[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+$";
  var urlReg = new RegExp(domainRegExp);
  if (!urlReg.test(str)) {
    var ipRegExp =
      "^((([1-9]|([1-9]d)|(1dd)|(2([0-4]d|5[0-5])))).)((([0-9]|([1-9]d)|(1dd)|(2([0-4]d|5[0-5])))).){2}(([1-9]|([1-9]d)|(1dd)|(2([0-4]d|5[0-5]))))$";
    urlReg = new RegExp(ipRegExp);
    return urlReg.test(str);
  }
  return true;
}

function isValidInputPort(str) {
  if (str == null || str.length < 1) {
    return false;
  }

  const port = Number.parseInt(str);
  if (isNaN(port)) {
    return false;
  }

  return port >= 0 && port <= 65535;
}

function validate() {
  var errorMsg = "";
  var inputValue = $("#MachineID").val();
  if (inputValue == "") {
    errorMsg = "Pos Id cannot be blank.\r\n";
  } else if (isValidInputMachineID(inputValue) == false) {
    errorMsg = "Pos Id is invalid.Pos Id cannot include special characters\r\n";
  }

  inputValue = $("#EFTAddress").val();
  if (inputValue == "") {
    errorMsg += "EFTPOS ADDRESS cannot be blank.\r\n";
  } else if (isValidInputAddress(inputValue) == false) {
    errorMsg += "EFTPOS ADDRESS is invalid.\r\n";
  }

  inputValue = $("#EFTPort").val();
  if (inputValue == "") {
    errorMsg += "EFTPOS PORT cannot be blank.\r\n";
  } else if (isValidInputPort(inputValue) == false) {
    errorMsg += "EFTPOS PORT is invalid.\r\n";
  }

  updateDisplayContent(errorMsg);

  return errorMsg === "";
}

function updateDisplayContent(displayContent) {
  const tagDisplay = document.getElementById("display");
  tagDisplay.innerHTML = "";
  if (Array.isArray(displayContent)) {
    displayContent.forEach(function (each) {
      const tagDiv = document.createElement("div");
      tagDiv.innerHTML = escapeHtml(each);
      tagDisplay.appendChild(tagDiv);
    });
  } else {
    const tagDiv = document.createElement("div");
    tagDiv.innerHTML = escapeHtml(displayContent);
    tagDisplay.appendChild(tagDiv);
  }
}

function getLastSuccessTxn() {
    try {
        lastSuccessTxnStr = localStorage.getItem('lastSuccessTxn');
        if (lastSuccessTxnStr != null) {
            return JSON.parse(lastSuccessTxnStr)
        }
    } catch (e) {
        console.error('Fail to get the last success txn:', e.toString());
    }
    return null;
}

function setLastSuccessTxn(lastTxn) {
    try {
        if (lastTxn == null) {
            localStorage.removeItem('lastSuccessTxn');
            return;
        }
        localStorage.setItem('lastSuccessTxn', JSON.stringify(lastTxn));
    } catch (e) {
        console.error('Fail to store last success txn:', e.toString());
    }

}
