<template>
  <el-row :gutter="20">
    <el-col :span="12" class="place">
      <el-row class="small-title">
        <h2>版面分析</h2>
      </el-row>
      <el-row style="color: gray; font-size: small;">
        <p>目前支持检测图片与表格</p>
      </el-row>
      <el-row style="color: gray; font-size: small;">
        <h4>支持jpg, png, bmp, pdf等文件格式</h4>
      </el-row>
      <div class="common-layout">
        <el-container>
          <el-input type="file" v-model="fileName" @change="uploadImg"></el-input>
          <el-button type="primary" @click="predict" :loading="loading">Predict</el-button>
        </el-container>
      </div>
      <div v-show="is_pdf">
        <el-row>
          <el-button-group>
            <el-button type="primary" :icon="ArrowLeft" @click="prePage">上一页</el-button>
            <el-button type="primary" @click="nextPage">
              下一页<el-icon class="el-icon--right">
                <ArrowRight />
              </el-icon>
            </el-button>
          </el-button-group>
          <div class="page-tool-item">{{ state.pageNum }}/{{ state.numPages }}</div>
          <el-container>
            <el-input type="number" v-model="pdf_page"></el-input>
            <el-button type="primary" @click="SetPdfPage" plain>页面跳转</el-button>
          </el-container>
        </el-row>
      </div>
      <el-row>
        <!-- 用于展示图片 -->
        <img id="show-img" class="show-area" />
      </el-row>
      <canvas id="canvas"></canvas>
      <canvas id="img_canvas" style="display: none;"></canvas>
    </el-col>
    <el-col :span="12" class="place">
      <el-row class="small-title">
        <h2 style="margin-right: 0;">识别结果展示</h2>
        <el-button type="danger" @click="submitBug" disabled>提交bug</el-button>
      </el-row>
      <div>
        <h2>图片</h2>
        <el-scrollbar height="auto">
          <ul>
            <li v-for="(item, index) in figureArr" :key="index" @click="figureHandleClick(index, item, figure_rects)"
              :style="index == figureSelectedItem ? 'color: blue' : ''">
              {{ item }}
            </li>
          </ul>
        </el-scrollbar>
        <h2>表格</h2>
        <el-scrollbar height="auto">
          <ul>
            <li v-for="(item, index) in tableArr" :key="index" @click="tableHandleClick(index, item, table_rects)"
              :style="index == tableSelectedItem ? 'color: blue' : ''">
              {{ item }}
            </li>
          </ul>
        </el-scrollbar>
      </div>
      <el-row>
        <section> 耗时：{{ predictTime }} ms.</section>
      </el-row>
    </el-col>
  </el-row>
</template>

<script lang="ts" setup>
import { Detection, SubmitBug } from '../../../../api/api'
import { fabric } from 'fabric';
import { reactive, ref } from 'vue'
import { onMounted } from "vue";
import { createLoadingTask } from "vue3-pdfjs/esm"; // 获得总页数
import {
  ArrowLeft,
  ArrowRight,
} from '@element-plus/icons-vue'

import { storeToRefs } from 'pinia'
import { useServerIpStore } from '../../../../store/ServerIp';
import { useServerPortStore } from '../../../../store/ServerPort';

const si = useServerIpStore();
const { server_ip } = storeToRefs(si);
const sp = useServerPortStore();
const { server_port } = storeToRefs(sp);

const api = "/v1/detection/layout_parser";

let loadingTask: any;
const is_pdf = ref(false);
const pdf_page = ref(1);
const pdf_img: any = ref("")

const state = reactive({
  source: "", //预览pdf文件地址
  pageNum: 1, //当前页面
  numPages: 0, // 总页数
});

function dataURLtoBlob(dataURL: any) {
  var arr = dataURL.split(','),
    mime = arr[0].match(/:(.*?);/)[1],
    bstr = atob(arr[1]),
    n = bstr.length,
    u8arr = new Uint8Array(n);
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }
  return new Blob([u8arr], { type: mime });
}

function getPdfImage(index: number) {
  console.log(index, state.pageNum)
  const showImg = document.getElementById("show-img") as HTMLImageElement;
  loadingTask.promise.then((pdf: any) => {
    state.numPages = pdf.numPages;
    pdf.getPage(index).then((page: any) => {
      const viewport = page.getViewport({ scale: 4.0 })
      img_canvas.value.height = viewport.height;
      img_canvas.value.width = viewport.width;
      canvas.value.height = viewport.height;
      canvas.value.width = viewport.width;
      const destWidth = 398;
      img_canvas.value.style.width = destWidth + 'px';

      img_canvas.value.style.height = destWidth * (viewport.height / viewport.width) + 'px';
      canvas.value.style.width = destWidth + 'px';

      canvas.value.style.height = destWidth * (viewport.height / viewport.width) + 'px';
      const ctx = img_canvas.value.getContext('2d');
      page.render({
        canvasContext: ctx,
        viewport,
      });
      img_canvas.value.toBlob(function (blob) {
        let data = img_canvas.value.toDataURL('images/png', 1.0)
        pdf_img.value = dataURLtoBlob(data)
        showImg.src = data;
        showImg.onload = () => {
          canvas.value.width = showImg.width;
          canvas.value.height = showImg.height;
          fa_canvas = new fabric.Canvas(canvas.value);
          figure_rects.splice(0)
          table_rects.splice(0)
          figureSelectedItem.value = -1;
          tableSelectedItem.value = -1;
        }
      });
    })
  });
}

function SetPdfPage() {
  if (pdf_page.value >= 1 && pdf_page.value <= state.numPages) {
    console.log(pdf_page.value)
    state.pageNum = Number(pdf_page.value);
    getPdfImage(state.pageNum);
  } else {
    console.log(pdf_page.value)
    alert('输入的pdf页面无效！')
  }
}

function prePage() {
  if (state.pageNum > 1) {
    state.pageNum -= 1;
    getPdfImage(state.pageNum);
  }
}

function nextPage() {
  if (state.pageNum < state.numPages) {
    state.pageNum += 1;
    getPdfImage(state.pageNum);
  }
}

// 构建 File 对象
function blobToFile(blob: any, fileName: any) {
  blob.lastModifiedDate = new Date();
  blob.name = fileName;
  return blob;
}

async function convertCanvasToFile(canvas: HTMLCanvasElement, fileName: any) {
  // 将 Canvas 转为 Blob 对象
  const blob = await new Promise(resolve => canvas.toBlob(blob => {
    resolve(blob);
  }, pdf_img.value.type, 1.0));
  // 手动构造 File 对象
  let file = null;
  try {
    file = new File([pdf_img.value], fileName, { type: pdf_img.value.type });
  } catch (e) {
    // Safari 浏览器不支持直接通过 new File() 创建文件对象，需要手动构造
    const rawFile = blobToFile(blob, fileName);
    file = Object.assign(rawFile, { lastModifiedDate: new Date(), name: fileName });
  }
  return file;
}

let loading = ref(false)
let show_predict = ref(false)
let predictTime = ref(0)
const fileName = ref(null);
const canvas = ref(null as unknown as HTMLCanvasElement);
const img_canvas = ref(null as unknown as HTMLCanvasElement);
let figureSelectedItem = ref(-1)
let tableSelectedItem = ref(-1)

let figureArr: any = ref([])
let tableArr: any = ref([])

let fa_canvas: any = null;
let bugId = ref("");
const json_result = ref("");

interface iRect {
  left: number,
  top: number,
  width: number,
  height: number
}

let figure_rects: any = []
let table_rects: any = []

onMounted(async () => {
  canvas.value = document.getElementById("canvas") as HTMLCanvasElement;
  img_canvas.value = document.getElementById("img_canvas") as HTMLCanvasElement;
});

const uploadImg = () => {
  /**
   * 这里由于操作是绑定在 el-input 上；因此需要在内部重新获取 input 再拿到 file
   */
  const reader = new FileReader();
  // 用于展示
  const showImg = document.getElementById("show-img") as HTMLImageElement;
  const inputElement = document
    .getElementsByClassName("el-input")[0]
    .getElementsByTagName("input")[0];

  try {
    const file = inputElement.files![0];
    reader.onload = () => {
      const post_ = file.name.substring(file.name.lastIndexOf("."), file.name.length).toLowerCase();
      fa_canvas ? fa_canvas.clear() : 0;
      if (post_ == ".pdf") {
        state.pageNum = 1;
        state.source = URL.createObjectURL(file);
        is_pdf.value = true
        loadingTask = createLoadingTask(state.source);
        getPdfImage(state.pageNum);
      } else
        if (post_ == ".jpg" || post_ == ".png" || post_ == ".bmp" || post_ == ".jpeg") {
          showImg.src = URL.createObjectURL(file);
          showImg.onload = () => {
            canvas.value.width = showImg.width;
            canvas.value.height = showImg.height;
            fa_canvas = new fabric.Canvas(canvas.value);
            figure_rects.splice(0)
            table_rects.splice(0)
            figureSelectedItem.value = -1;
            tableSelectedItem.value = -1;
          }
          is_pdf.value = false
        } else {
          alert('不支持的文件格式！')
          fileName.value = null
        }
    };
    reader.readAsDataURL(file);
  } catch (err) {
    console.error(err);
  }
  if (show_predict.value === true)
    show_predict.value = !show_predict.value;
};

type RectWithId = fabric.Rect & { id: number };

function CreateRect(canvas: any, i: number, left: number, top: number, width: number, height: number, highlight: boolean, label: number) {
  var rect = new fabric.Rect({
    left: left,
    top: top,
    width: width,
    height: height,
    fill: 'transparent',
    stroke: highlight ? 'blue' : 'green',
    strokeWidth: 2,
    opacity: 1.0,
    selectable: false,
    name: highlight ? 'high' : 'normal',
  }) as RectWithId;
  rect.set('id', i);
  canvas.add(rect);
}

const predict = async () => {
  if (fileName.value == undefined) {
    alert('请上传图片！')
    return;
  }

  fa_canvas.clear()
  figure_rects.splice(0)
  table_rects.splice(0)

  const img = document.getElementById("show-img") as HTMLImageElement;
  const inputElement = document
    .getElementsByClassName("el-input")[0]
    .getElementsByTagName("input")[0];
  const file = inputElement.files![0];

  loading.value = !loading.value
  var data = new FormData();

  if (is_pdf.value) {
    const file: any = convertCanvasToFile(img_canvas.value, "pdf.png").then(result => {
      data.append('image', result);
      Detection(api, data).then(res => {
        console.log(res.code)
        json_result.value = JSON.stringify(res.data, null, 4);
        console.log(res.data);
        figureArr.value.splice(0);
        tableArr.value.splice(0);
        let tmp_labels = res.data.labels;
        if (tmp_labels.length == 0) {
          alert("no result!");
        } else {
          let tmp_boxes = res.data.boxes;
          const h_radio = img.height / img.naturalHeight;
          const w_radio = img.width / img.naturalWidth;

          for (let i = 0; i < tmp_labels.length; i++) {
            let left = w_radio * tmp_boxes[i][0];
            let top = h_radio * tmp_boxes[i][1];
            let width = w_radio * (tmp_boxes[i][2] - tmp_boxes[i][0]);
            let height = h_radio * (tmp_boxes[i][3] - tmp_boxes[i][1]);
            const rect: iRect = { left, top, width, height };
            if (tmp_labels[i] == "Figure") {
              figureArr.value.push("图片");
              figure_rects.push(rect);
              CreateRect(fa_canvas, i, left, top, width, height, false, 1);
            } else if (tmp_labels[i] == "Table_0" || tmp_labels[i] == "Table_std") {
              tableArr.value.push("表格(" + tmp_labels[i] + ")");
              table_rects.push(rect);
              CreateRect(fa_canvas, i, left, top, width, height, false, 2);
            }
          }
          figureArr.value.reverse();
          tableArr.value.reverse();
          table_rects.reverse();
          for (let i = 0; i < figureArr.value.length; i++) {
            figureArr.value[i] = figureArr.value[i] + " -- " + String(i + 1);
          }
          for (let i = 0; i < tableArr.value.length; i++) {
            tableArr.value[i] = tableArr.value[i] + " -- " + String(i + 1);
          }
        }
        predictTime.value = res.data.cost;
        loading.value = !loading.value;
        bugId.value = res.response_id;
        if (show_predict.value === false)
          show_predict.value = !show_predict.value;
      }).catch(function (err) {
        loading.value = !loading.value;
        bugId.value = ""
        predictTime.value = 0
      });
    })
  } else {
    data.append('image', file);

    Detection(api, data).then(res => {
      console.log(res.code)
      json_result.value = JSON.stringify(res.data, null, 4);
      console.log(res.data);
      // rec_result.value = res.data.text.reduce((total: any, cur: any) => total + `<p>${cur}</p>`);
      figureArr.value.splice(0);
      tableArr.value.splice(0);
      let tmp_labels = res.data.labels;
      if (tmp_labels.length == 0) {
        alert("no result!");
      } else {
        let tmp_boxes = res.data.boxes;
        const h_radio = img.height / img.naturalHeight;
        const w_radio = img.width / img.naturalWidth;

        for (let i = 0; i < tmp_labels.length; i++) {
          let left = w_radio * tmp_boxes[i][0];
          let top = h_radio * tmp_boxes[i][1];
          let width = w_radio * (tmp_boxes[i][2] - tmp_boxes[i][0]);
          let height = h_radio * (tmp_boxes[i][3] - tmp_boxes[i][1]);
          const rect: iRect = { left, top, width, height };
          if (tmp_labels[i] == "Figure") {
            figureArr.value.push("图片");
            figure_rects.push(rect);
            CreateRect(fa_canvas, i, left, top, width, height, false, 1);
          } else if (tmp_labels[i] == "Table_0" || tmp_labels[i] == "Table_std") {
            tableArr.value.push("表格(" + tmp_labels[i] + ")");
            table_rects.push(rect);
            CreateRect(fa_canvas, i, left, top, width, height, false, 2);
          }
        }
        figureArr.value.reverse();
        tableArr.value.reverse();
        table_rects.reverse();
        for (let i = 0; i < figureArr.value.length; i++) {
          figureArr.value[i] = figureArr.value[i] + " -- " + String(i + 1);
        }
        for (let i = 0; i < tableArr.value.length; i++) {
          tableArr.value[i] = tableArr.value[i] + " -- " + String(i + 1);
        }
      }
      predictTime.value = res.data.cost;
      loading.value = !loading.value;
      bugId.value = res.response_id;
      if (show_predict.value === false)
        show_predict.value = !show_predict.value;
    }).catch(function (err) {
      loading.value = !loading.value;
      bugId.value = ""
      predictTime.value = 0
    });
  }
};

const submitBug = async () => {
  if (bugId.value == undefined || bugId.value == "") {
    alert('请先预测结果！')
    return;
  }

  SubmitBug(api, bugId.value).then(res => {
    console.log(res.code, res.data)
  }).catch(function (err) {
    console.log(err)
    // loading.value = !loading.value;
  });
};

async function figureHandleClick(index: any, item: any, rects: any) {
  figureSelectedItem.value = index;
  tableSelectedItem.value = -1;
  let objects = fa_canvas.getObjects();
  for (let i = 0; i < objects.length; i++) {
    if (objects[i].name === 'high') {
      // 找到名为 rectName 的矩形元素，执行删除操作等
      fa_canvas.remove(objects[i]);
      break;
    }
  }
  CreateRect(fa_canvas, index, rects[index].left, rects[index].top, rects[index].width, rects[index].height, true, 1);
}

async function tableHandleClick(index: any, item: any, rects: any) {
  tableSelectedItem.value = index;
  figureSelectedItem.value = -1;
  let objects = fa_canvas.getObjects();
  for (let i = 0; i < objects.length; i++) {
    if (objects[i].name === 'high') {
      // 找到名为 rectName 的矩形元素，执行删除操作等
      fa_canvas.remove(objects[i]);
      break;
    }
  }
  CreateRect(fa_canvas, index, rects[index].left, rects[index].top, rects[index].width, rects[index].height, true, 2);
}
</script>

<style scoped>
#canvas {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
  /* 设置Canvas的层级，使其显示在图像之上 */
  background-color: transparent;
}

#show-img {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
}

.demo-image__placeholder .block {
  padding: 30px 0;
  text-align: center;
  border-right: solid 1px var(--el-border-color);
  display: inline-block;
  width: 50%;
  box-sizing: border-box;
  vertical-align: top;
}

.demo-image__placeholder .demonstration {
  display: block;
  color: var(--el-text-color-secondary);
  font-size: 14px;
  margin-bottom: 20px;
}

.demo-image__placeholder .el-image {
  padding: 0 5px;
  max-width: 300px;
  max-height: 200px;
}

.demo-image__placeholder.image-slot {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
  background: var(--el-fill-color-light);
  color: var(--el-text-color-secondary);
  font-size: 14px;
}

.demo-image__placeholder .dot {
  animation: dot 2s infinite steps(3, start);
  overflow: hidden;
}

.place {
  margin-right: auto;
  margin-left: auto;
  border-right: solid 1px #ccc;
}

.show-area {
  width: 100%;
}

.small-title {
  justify-content: space-between;
  align-items: center;
}

.page-tool-item {
  padding: 8px 15px;
  padding-left: 10px;
  cursor: pointer;
}
</style>
