<template>
  <h1 class="text-center text-3xl title">ESP32程序批量烧录</h1>
  <div class="home">
    <div class="operatebox">
      <div class="flexbox">
        <div class="p-4 nop">
          <div class="textport">待烧录串口</div>
          <textarea disabled class="commsg resize-none border-2" :value="ports">
          </textarea>
        </div>
        <div class="p-4 nop">
          <div class="textport">文 件 路 径</div>
          <button
            class="seleanni px-4 border-2 rounded text-white"
            :class="loading ? 'bg-gray-500' : 'bg-blue-500'"
            :disabled="loading"
            @click="selectFile"
          >
            选　　　择
          </button>
        </div>
        <div class="p-4 truncate nop">
          <input
            disabled
            type="text"
            class="filebox border-2"
            :value="selectedFilePath"
          />
        </div>
      </div>
      <div class="col-span-2 nopd">
        <button
          class="anni px-4 border-2 rounded text-white"
          :class="loading ? 'bg-gray-500' : 'bg-blue-500'"
          :disabled="loading"
          @click="burn_start"
        >
          <svg
            v-if="loadings"
            class="svgbox animate-spin h-5 w-5"
            xmlns="http://www.w3.org/2000/svg"
            fill="none"
            viewBox="0 0 24 24"
          >
            <circle
              class="opacity-25"
              cx="12"
              cy="12"
              r="10"
              stroke="currentColor"
              stroke-width="4"
            ></circle>
            <path
              class="opacity-75"
              fill="currentColor"
              d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
            ></path>
          </svg>
          <div class="fontset" v-else>烧　　　录</div>
        </button>
      </div>
      <div class="tips">
        <h6 class="tipstitle">操　作　方　法</h6>
        <textarea disabled class="tipsmsg resize-none border-2">
        1. 待烧录或烧录失败的串口会自动显示。
        2. 点击按钮选择需要烧录的程序。
        3. 点击烧录按钮，等待烧录完成。

        **右侧为烧录输出**
        #若烧录失败可以通过烧录输出判断错误原因#
      </textarea
        >
      </div>
    </div>
    <div class="msgbox">
      <textarea
        ref="container"
        disabled
        class="textbox resize-none border-2 w-full"
        :value="msg"
      />
    </div>
  </div>
</template>

<script lang="ts" setup>
import { ref, inject, watch, onMounted } from "vue";

function alert(data) {
  loading.value = true;
  var a = document.createElement("div"),
    p = document.createElement("p"),
    btn = document.createElement("div"),
    textNode = document.createTextNode(data ? data : ""),
    btnText = document.createTextNode("确定");
  // 控制样式
  css(a, {
    "padding-top": "60px",
    position: "fixed",
    left: "0",
    right: "0",
    top: "40%",
    width: "300px",
    height: "180px",
    margin: "0 auto",
    "background-color": "#fff",
    border: "2px solid #ccc",
    "font-size": "100%",
    "text-align": "center",
    "z-index": "3",
  });
  css(btn, {
    margin: "10%",
    "margin-bottom": "5%",
    width: "80%",
    position: "absolute",
    bottom: "0",
    background: "#2222ff",
    opacity: "0.8",
    "border-radius": "24px",
    color: "#fff",
  });
  // 内部结构套入
  p.appendChild(textNode);
  btn.appendChild(btnText);
  a.appendChild(p);
  a.appendChild(btn);
  // 整体显示到页面内
  document.getElementsByTagName("body")[0].appendChild(a);

  // 确定绑定点击事件删除标签
  btn.onclick = function () {
    a.parentNode?.removeChild(a);
    loading.value = false;
  };
}
function css(targetObj, cssObj) {
  var str = targetObj.getAttribute("style") ? targetObj.getAttribute("style") : "";
  for (var i in cssObj) {
    str += i + ":" + cssObj[i] + ";";
  }
  targetObj.style.cssText = str;
}
window.alert = alert;

const IPCRENDERER_API_SUPPORTED = inject("IPCRENDERER_API_SUPPORTED", false);

const loading = ref(false);
const loadings = ref(false);
const msg = ref("烧录结果输出:\n");
const container = ref(null);
const selectedPort = ref("");
const ports = ref([]);
const errsum = ref(0);
const sucsum = ref(0);
const succom = ref([]);
const failedcom = ref([]);
const comlength = ref(0);

const setPorts = (value: Object[]) => {
  let compath = [];
  value.forEach((element) => {
    compath.push(element.path);
  });

  if (loading.value == false) {
    ports.value = compath;
  }
  comlength.value = ports.value.length;
};

const selectedFilePath = ref("");

const setSelectedFilePath = (value: string) => (selectedFilePath.value = value);

const selectFile = () => {
  if (!IPCRENDERER_API_SUPPORTED) {
    alert("The ipcRenderer API is not supported.");
    return;
  }

  ipcRenderer.send("SELECT_FILE");
};

const alert_msg = (value: string) => {
  if (!value) {
    return;
  }

  alert(value);
};

const errlog = (value: number) => {
  if (!value) {
    return;
  }

  errsum.value = value;
};

const suclog = (value: number) => {
  if (!value) {
    return;
  }

  sucsum.value = value;
};

const append_msg = (value: string) => {
  if (!value) {
    return;
  }

  msg.value += value + "\n";
};

const suc_result = (value: Array<string>) => {
  if (!value) {
    return;
  }

  succom.value.push(value);
};

const failed_result = (value: Array<string>) => {
  if (!value) {
    return;
  }

  failedcom.value.push(value);
};

const scroll = () => {
  setTimeout(() => (container.value.scrollTop = container.value.scrollHeight), 5);
};

const burn = () => {
  selectedPort.value = ports.value.shift();
  const param = {
    selectedPort: selectedPort.value,
    selectedFilePath: selectedFilePath.value,
    errsum: errsum.value,
    sucsum: sucsum.value,
  };
  ipcRenderer.send("BURN", param);
  loading.value = true;
  loadings.value = true;
};

const burn_start = () => {
  if (ports.value.length == 0) {
    alert("未发现串口");
    return;
  }
  if (!selectedFilePath.value) {
    alert("请选择程序文件");
    return;
  }
  succom.value = [];
  failedcom.value = [];
  errsum.value = 0;
  sucsum.value = 0;
  msg.value = "烧录结果输出:\n";
  burn();
};

watch(msg, () => {
  scroll();
});

onMounted(() => {
  if (!IPCRENDERER_API_SUPPORTED) {
    alert("The ipcRenderer API is not supported.");
    return;
  }

  ipcRenderer.receive("SELECT_FILE", setSelectedFilePath);
  ipcRenderer.receive("LIST_PORTS", setPorts);
  ipcRenderer.receive("BURN_END", () => {
    if (ports.value.length == 0) {
      loadings.value = false;
      loading.value = false;
      if (errsum.value == 0) {
        alert("串口已全部烧录成功！");
        return;
      } else if (sucsum.value == 0) {
        alert("串口已全部烧录失败！");
        ports.value = failedcom.value;
        return;
      } else {
        alert(`烧录结束，成功：${sucsum.value}个，失败：${errsum.value}个`);
        ports.value = failedcom.value;
        return;
      }
    }
    burn();
  });
  ipcRenderer.receive("ALERT_MSG", alert_msg);
  ipcRenderer.receive("ERR_SUM", errlog);
  ipcRenderer.receive("SUC_SUM", suclog);
  ipcRenderer.receive("APPEND_MSG", append_msg);
  ipcRenderer.receive("FAILED_RESULT", failed_result);
  ipcRenderer.receive("SUC_RESULT", suc_result);
  // ipcRenderer.receive('CLEAN_MSG' , () => msg.value = '')
});
</script>

<style scoped>
.title {
  min-width: 220px;
  height: 14vh;
  line-height: 14vh;
}
.textport {
  width: 45%;
  font-size: clamp(0.8rem, 0.5rem + 1vw, 2rem);
  display: flex;
  align-items: center;
}
.anni {
  width: 40%;
  min-width: 60px;
  height: 80%;
  margin-top: 1%;
  border-radius: 48px;
  position: relative;
  z-index: 2;
}
.fontset {
  margin: auto;
  width: 100%;
  text-align: center;
  display: flex;
  font-size: clamp(0.8rem, 0.5rem + 1vw, 2rem);
  justify-content: space-around;
  align-items: center;
}
.seleanni {
  width: 45%;
  border-radius: 24px;
  height: 100%;
  font-size: clamp(0.8rem, 0.5rem + 1vw, 2rem);
}
.selebox {
  width: 45%;
  border-radius: 24px;
  height: 100%;
  box-shadow: inset 4px 4px 4px rgba(0, 0, 0, 0.3),
    inset -4px -4px 4px rgba(255, 255, 255, 0.7);
}
.filebox {
  min-width: 90px;
  width: 90%;
  background-color: #fff;
  height: 100%;
  border-radius: 24px;
  white-space: nowrap;
  overflow: hidden;
  box-shadow: inset 4px 4px 4px rgba(0, 0, 0, 0.3),
    inset -4px -4px 4px rgba(255, 255, 255, 0.7);
}
.flexbox {
  margin: 0;
  width: 100%;
  height: 40%;
  background-color: #eeffff;
  display: flex;
  justify-content: center;
  align-content: space-evenly;
  flex-wrap: wrap;
  overflow: hidden;
}
.svgbox {
  margin: auto;
}
.nop {
  padding: 0;
  padding-left: 10%;
  flex: 1;
  min-width: 100%;
  max-width: 200%;
  height: 16%;
  min-height: 28px;
  overflow: hidden;
  display: flex;
  justify-content: start;
}
.nopd {
  padding: 0;
  flex: 1;
  display: flex;
  width: 100%;
  height: 10%;
  justify-content: center;
  align-content: center;
}
.msgbox {
  padding: 0;
  width: 48%;
  height: 100%;
  overflow: hidden;
}
.textbox {
  height: 100%;
  background-color: #ffe;
}
.home {
  height: 80vh;
  display: flex;
  justify-content: center;
  margin: auto;
}
.operatebox {
  margin: 0;
  width: 48%;
  margin-right: 1%;
  height: 100%;
  background-color: #ccffff;
}
.tips {
  width: 100%;
  height: 50%;
  background-color: #99ffff;
  padding-left: 9%;
}
.tipstitle {
  width: 90%;
  min-width: 120px;
  min-height: 10%;
  text-align: center;
  padding-top: 1.5%;
  font-size: clamp(0.6rem, 0.5rem + 1vw, 1.2rem);
}
.tipsmsg {
  width: 90%;
  height: 80%;
  background-color: #efe;
}
.commsg {
  width: 45%;
  height: 100%;
  background-color: #efe;
}
</style>
