<template>
  <div class="gamma-analysis">
    <a-spin :spinning="isLoading">
      <!-- 二级交互栏 -->
      <div class="spectrum-analysis-sub-operators">
        <pop-over-with-icon placement="bottomLeft">
          Detailed-Information
          <detailed-infomation slot="content" :data="detailedInfomation" />
        </pop-over-with-icon>
        <pop-over-with-icon placement="bottomLeft">
          QC Flags
          <qc-flags slot="content" :data="qcFlags" />
        </pop-over-with-icon>
        <pop-over-with-icon>
          Graph Assistance
          <graph-assistance slot="content" @change="handleGraphAssistanceChange" @reset="handleReset" />
        </pop-over-with-icon>
        <pop-over-with-icon>
          Nuclide Library
          <nuclear-library slot="content" />
        </pop-over-with-icon>
        <div class="peak-info">
          <button-with-switch-icon @change="handlePeakInfoChange">
            Peak Information
          </button-with-switch-icon>
        </div>
      </div>
      <!-- 二级交互栏结束 -->
      <!-- 主体部分 -->
      <div class="gamma-analysis-main">
        <div class="gamma-analysis-chart">
          <custom-chart
            ref="chartRef"
            :option="option"
            @zr:click="handleChartClick"
            @zr:mousedown="handleMouseDown"
            @zr:mouseup="handleMouseUp"
            @brushEnd="handleBrushEnd"
            style="height: 100%"
          />

          <div class="gamma-analysis-thumbnail">
            <custom-chart
              ref="thumbnailChartRef"
              :option="thumbnailOption"
              @zr:click="handleThumbnailChartClick"
              style="height: 100%"
            />
          </div>
        </div>
      </div>
      <!-- 主体部分结束 -->
    </a-spin>
  </div>
</template>

<script>
import CustomChart from '@/components/CustomChart/index.vue'
import PopOverWithIcon from './components/SubOperators/PopOverWithIcon.vue'
import DetailedInfomation from './components/SubOperators/DetailedInfomation.vue'
import QcFlags from './components/SubOperators/QcFlags.vue'
import GraphAssistance from './components/SubOperators/GraphAssistance.vue'
import NuclearLibrary from './components/SubOperators/NuclearLibrary.vue'
import ButtonWithSwitchIcon from './components/SubOperators/ButtonWithSwitchIcon.vue'
import { getAction } from '@/api/manage'
import Response from './response.json'
import { getXAxisAndYAxisByPosition } from '@/utils/chartHelper'

// 初始配置
const initialOption = {
  grid: {
    top: 40,
    left: 60,
    right: 50,
    containLabel: true
  },
  title: {
    text: '',
    left: 'center',
    bottom: 10,
    textStyle: {
      color: '#8FD4F8',
      rich: {
        a: {
          padding: [0, 20, 0, 0],
          fontSize: 16
        }
      }
    }
  },
  tooltip: {
    trigger: 'axis',
    axisPointer: {
      lineStyle: {
        color: '#099D24',
        width: 2
      }
    },
    formatter: params => {
      const [channel] = params[0].value
      return `<div class="channel">Channel: ${channel}</div>
              <div class="energy">Energy: ${(0).toFixed(2)}</div>`
    },
    className: 'figure-chart-option-tooltip'
  },
  xAxis: {
    name: 'Channel',
    nameTextStyle: {
      color: '#8FD4F8',
      fontSize: 16,
      align: 'right',
      verticalAlign: 'top',
      padding: [30, 0, 0, 0]
    },
    axisLine: {
      lineStyle: {
        color: '#ade6ee'
      }
    },
    splitLine: {
      show: false
    },
    axisLabel: {
      textStyle: {
        color: '#ade6ee'
      }
    },
    min: 0,
    max: 'dataMax',
    animation: false
  },
  yAxis: {
    name: 'Counts',
    nameTextStyle: {
      color: '#8FD4F8',
      fontSize: 16
    },
    axisLine: {
      show: true,
      lineStyle: {
        color: '#ade6ee'
      }
    },
    splitLine: {
      show: true,
      lineStyle: {
        color: 'rgba(173, 230, 238, .2)'
      }
    },
    axisLabel: {
      textStyle: {
        color: '#ade6ee'
      }
    },
    min: 0,
    max: 'dataMax',
    animation: false
  },
  series: [],
  brush: {}
}

// 缩略图配置
const thumbnailOption = {
  grid: {
    top: 0,
    left: 5,
    right: 5,
    bottom: 0
  },
  xAxis: {
    type: 'category',
    axisLine: {
      show: false
    },
    splitLine: {
      show: false
    },
    axisLabel: {
      show: false
    },
    min: 0,
    max: 'dataMax'
  },
  yAxis: {
    axisLine: {
      show: false
    },
    splitLine: {
      show: false
    },
    axisLabel: {
      show: false
    }
  },
  series: []
}

export default {
  props: {
    sample: {
      type: Object
    }
  },
  components: {
    CustomChart,
    PopOverWithIcon,
    DetailedInfomation,
    QcFlags,
    GraphAssistance,
    NuclearLibrary,
    ButtonWithSwitchIcon
  },
  data() {
    return {
      isLoading: false,
      option: initialOption,
      thumbnailOption,

      detailedInfomation: [],
      qcFlags: [],
      graphAssistance: {},

      channelPeakGroup: [],
      energyPeakGroup: []
    }
  },
  created() {
    this.option.title.text = '{a|Channel:0} {a|Energy:0} {a|Counts:0} {a|Detectability:0}'
  },
  methods: {
    async getSampleDetail() {
      const { dbName, sampleId } = this.sample
      try {
        this.isLoading = true
        this.option.series = []

        // const { success, result, message } = await getAction('/gamma/gammaByDB', {
        //   dbName,
        //   sampleId
        // })
        const { success, result, message } = Response
        if (success) {
          this.isLoading = false

          const {
            dead_time,
            live_time,
            real_time,
            start_time,

            DetailedInformation,
            QCFlag,

            allData,

            shadowChannelChart,
            shadowEnergyChart,

            shapeChannelData,
            shapeEnergyData
          } = result


          this.detailedInfomation = DetailedInformation
          this.qcFlags = QCFlag

          const channelPeakGroup = allData.filter(item => item.name == 'Peak' && item.group == 'channel')
          const energyPeakGroup = allData.filter(item => item.name == 'Peak' && item.group == 'energy')

          const channelBaseLine = allData.find(item => item.name == 'BaseLine' && item.group == 'channel')
          const energyBaseLine = allData.find(item => item.name == 'BaseLine' && item.group == 'energy')

          const channelLcLine = allData.find(item => item.name == 'Lc' && item.group == 'channel')
          const energyLcLine = allData.find(item => item.name == 'Lc' && item.group == 'energy')

          const channelScacLine = allData.find(item => item.name == 'Scac' && item.group == 'channel')
          const energyScacLine = allData.find(item => item.name == 'Scac' && item.group == 'energy')

          // 保存Peak Line
          this.channelPeakGroup = channelPeakGroup
          this.energyPeakGroup = energyPeakGroup

          // 保存 Spectrum Line
          this.shadowChannelChart = shadowChannelChart
          this.shadowEnergyChart = shadowEnergyChart

          // 保存基线
          this.channelBaseLine = channelBaseLine
          this.energyBaseLine = energyBaseLine

          // 保存Lc
          this.channelLcLine = channelLcLine
          this.energyLcLine = energyLcLine

          // 保存Scac
          this.channelScacLine = channelScacLine
          this.energyScacLine = energyScacLine

          // 保存 基线控制点
          this.shapeChannelData = shapeChannelData
          this.shapeEnergyData = shapeEnergyData

          this.option.yAxis.max = Math.ceil(Math.max(...shadowChannelChart.pointlist.map(item => item.y)) * 1.1)

          // 推入Spectrum Line
          this.option.series.push({
            name: 'Spectrum',
            type: 'line',
            data: shadowChannelChart.pointlist.map(({ x, y }) => [x, y]),
            itemStyle: {
              color: `rgb(${shadowChannelChart.color})`
            },
            lineStyle: {
              width: 1
            },
            symbol: 'none',
            symbolSize: 1,
            emphasis: {
              disabled: true
            },
            markLine: {
              silent: true,
              symbol: 'none',
              label: {
                show: false
              },
              lineStyle: {
                color: 'red',
                width: 2
              },
              data: [{ xAxis: -1 }]
            },
            zlevel: 0
          })

          // 右上角缩略图推入Spectrum Line
          this.thumbnailOption.series.push({
            name: 'Spectrum',
            type: 'line',
            data: shadowChannelChart.pointlist.map(({ x, y }) => [x, y]),
            itemStyle: {
              color: `rgb(${shadowChannelChart.color})`
            },
            lineStyle: {
              width: 1
            },
            symbol: 'none',
            symbolSize: 1,
            emphasis: {
              disabled: true
            },
            silent: true,
            markLine: {
              silent: true,
              symbol: 'none',
              label: {
                show: false
              },
              lineStyle: {
                type: 'solid',
                color: '#1397a3',
                width: 2
              },
              data: []
            },
            zlevel: 0
          })

          // 推入Scac
          this.option.series.push({
            name: 'Scac',
            type: 'line',
            data: [].map(({ x, y }) => [x, y]),
            itemStyle: {
              color: `rgb(${shadowChannelChart.color})`
            },
            lineStyle: {
              width: 1
            },
            symbol: 'none',
            emphasis: {
              disabled: true
            }
          })

          // 推入基线
          this.option.series.push({
            name: 'BaseLine',
            type: 'line',
            data: channelBaseLine.pointlist.map(({ x, y }) => [x, y]),
            itemStyle: {
              color: `rgb(${channelBaseLine.color})`
            },
            lineStyle: {
              width: 1
            },
            symbol: 'none',
            emphasis: {
              disabled: true
            }
          })

          // 推入LC线
          this.option.series.push({
            name: 'LcLine',
            type: 'line',
            data: channelLcLine.pointlist.map(({ x, y }) => [x, y]),
            itemStyle: {
              color: `rgb(${channelLcLine.color})`
            },
            lineStyle: {
              width: 1
            },
            symbol: 'none',
            emphasis: {
              disabled: true
            }
          })

          // 推入Scac线
          this.option.series.push({
            name: 'ScacLine',
            type: 'line',
            data: channelScacLine.pointlist.map(({ x, y }) => [x, y]),
            itemStyle: {
              color: `rgb(${channelScacLine.color})`
            },
            lineStyle: {
              width: 1
            },
            symbol: 'none',
            emphasis: {
              disabled: true
            }
          })

          // 推入基线控制点
          this.option.series.push({
            name: 'BaseLine_Ctrl_Point',
            type: 'scatter',
            data: shapeChannelData.map(({ size, color, point: { x, y } }) => {
              return {
                value: [x, y],
                itemStyle: {
                  color: 'transparent',
                  borderColor: color,
                  borderWidth: size / 2
                }
              }
            }),
            emphasis: {
              disabled: true
            },
            z: 3,
            animation: false
          })

          // 推入Peak Line
          channelPeakGroup.forEach((item, index) => {
            this.option.series.push({
              name: `Peak_${index}`,
              type: 'line',
              data: item.pointlist.map(({ x, y }) => [x, y]),
              itemStyle: {
                color: `rgb(${item.color})`
              },
              lineStyle: {
                width: 1
              },
              symbol: 'none',
              animation: false
            })
          })
        } else {
          this.$message.error(message)
        }
      } catch (error) {
        console.error(error)
      }
    },

    // Graph Assistance 操作
    handleGraphAssistanceChange({ type, label, value }) {
      // 类型变化
      if (type == 'labelChange') {
        switch (label) {
          case 'Linear':
            break
          case 'Log10':
            break
          case 'Channel':
          case 'Energy':
            this.option.xAxis.name = label
            this.graphAssistance.type = type
            break
          case 'Lines':
            this.option.series[0].type = 'line'
            this.option.series[0].symbol = 'none'
            break
          case 'Scatter':
            this.option.series[0].type = 'scatter'
            this.option.series[0].symbol = 'circle'
            break
        }
      }
      // 值变化
      else if (type == 'valueChange') {
        this.graphAssistance[label] = value

        switch (label) {
          case 'Cursor':
            // 显示红色竖线
            if (value) {
              this.option.series[0].markLine.lineStyle.width = 2
            } else {
              this.option.series[0].markLine.lineStyle.width = 0
            }
            break
          case 'Baseline':
            const baseLineSeries = this.findSeriesByName('BaseLine')
            if (value) {
              if (this.graphAssistance.type == 'Energy') {
                baseLineSeries.data = this.energyBaseLine.pointlist.map(({ x, y }) => [x, y])
              } else {
                baseLineSeries.data = this.channelBaseLine.pointlist.map(({ x, y }) => [x, y])
              }
            } else {
              baseLineSeries.data = []
            }
            break
          case 'Lc':
            const lcLineSeries = this.findSeriesByName('LcLine')
            if (value) {
              if (this.graphAssistance.type == 'Energy') {
                lcLineSeries.data = this.energyLcLine.pointlist.map(({ x, y }) => [x, y])
              } else {
                lcLineSeries.data = this.channelLcLine.pointlist.map(({ x, y }) => [x, y])
              }
            } else {
              lcLineSeries.data = []
            }
            break
          case 'SCAC':
            const scacLineSeries = this.findSeriesByName('ScacLine')
            if (value) {
              if (this.graphAssistance.type == 'Energy') {
                scacLineSeries.data = this.energyScacLine.pointlist.map(({ x, y }) => [x, y])
              } else {
                scacLineSeries.data = this.channelScacLine.pointlist.map(({ x, y }) => [x, y])
              }
            } else {
              scacLineSeries.data = []
            }
            break
        }
      }
    },

    // 点击图表，设置红线
    handleChartClick(param) {
      const { offsetX, offsetY } = param
      const point = getXAxisAndYAxisByPosition(this.$refs.chartRef.getChartInstance(), offsetX, offsetY)
      if (point) {
        const xAxis = parseInt(point[0].toFixed())
        this.option.series[0].markLine.data[0].xAxis = xAxis
      }
    },

    resize() {
      this.$refs.chartRef.resize()
      this.$refs.thumbnailChartRef.resize()
    },

    // peak info 点击左右方向
    handlePeakInfoChange(direction) {
      this.moveMarkLine(direction)
    },

    /**
     * 向某一个方向移动标记线
     * @param { 'left'| 'right' } direction
     */
    moveMarkLine(direction) {
      const prevAxis = this.option.series[0].markLine.data[0].xAxis

      // 获取每一段 Channel 中的最大值
      const maxXAxises = this.channelPeakGroup.map(item => {
        const allY = item.pointlist.map(item => item.y)
        const max = item.pointlist.find(point => point.y == Math.max(...allY))
        return max.x
      })
      if (direction == 'right') {
        // 找到第一个比prevAxis大的xAxis
        const find = maxXAxises.find(xAxis => xAxis > prevAxis)
        if (find) {
          this.option.series[0].markLine.data[0].xAxis = find
        }
      } else if (direction == 'left') {
        // 找到第一个比prevAxis小的xAxis
        const find = maxXAxises.reverse().find(xAxis => xAxis < prevAxis)
        if (find) {
          this.option.series[0].markLine.data[0].xAxis = find
        }
      }
    },

    // 鼠标按下时开启可刷选状态
    handleMouseDown() {
      const chart = this.$refs.chartRef.getChartInstance()
      chart.dispatchAction({
        type: 'takeGlobalCursor',
        // 如果想变为“可刷选状态”，必须设置。不设置则会关闭“可刷选状态”。
        key: 'brush',
        brushOption: {
          // 参见 brush 组件的 brushType。如果设置为 false 则关闭“可刷选状态”。
          brushType: 'rect'
        }
      })
    },

    handleMouseUp() {
      setTimeout(() => {
        const chart = this.$refs.chartRef.getChartInstance()
        this.clearBrush(chart)
      }, 0)
    },

    clearBrush(chart) {
      // 清理刷选的范围
      chart.dispatchAction({
        type: 'brush',
        areas: []
      })

      // 改为不可刷选状态
      chart.dispatchAction({
        type: 'takeGlobalCursor'
      })
    },

    // 刷选完毕时
    handleBrushEnd(param) {
      const chart = this.$refs.chartRef.getChartInstance()
      const areas = param.areas[0]
      if (areas) {
        const range = areas.range
        const [[minX, maxX], [minY, maxY]] = range

        const point1 = chart.convertFromPixel({ seriesIndex: 0 }, [minX, minY]).map(num => parseInt(num.toFixed()))
        const point2 = chart.convertFromPixel({ seriesIndex: 0 }, [maxX, maxY]).map(num => parseInt(num.toFixed()))

        const xAxisMax = chart.getModel().getComponent('xAxis').axis.scale._extent[1]
        const yAxisMax = chart.getModel().getComponent('yAxis').axis.scale._extent[1]

        let [x1, y2, x2, y1] = [...point1, ...point2] // 根据解析出的数据确定真实的范围

        const xAxisLimit = this.rangeNumber(0, xAxisMax)
        const yAxisLimit = this.rangeNumber(0, yAxisMax)

        x1 = xAxisLimit(x1)
        x2 = xAxisLimit(x2)

        y1 = yAxisLimit(y1)
        y2 = yAxisLimit(y2)
        
        this.option.xAxis.min = x1
        this.option.xAxis.max = x2
        this.option.yAxis.min = y1
        this.option.yAxis.max = y2

        this.setThumbnailChartRect(x1, y2, x2, y1)
      }

      this.clearBrush(chart)
    },

    // 在右上角缩略图中设置范围
    setThumbnailChartRect(x1, y2, x2, y1) {
      this.thumbnailChartRect = [x1, y2, x2, y1]

      const { markLine } = this.thumbnailOption.series[0]
      const pointList = [
        [
          [x1, y1],
          [x2, y1]
        ],
        [
          [x2, y1],
          [x2, y2]
        ],
        [
          [x2, y2],
          [x1, y2]
        ],
        [
          [x1, y2],
          [x1, y1]
        ]
      ]
      const lines = pointList.map(point => {
        return this.generateLineDataByTwoPoints(point[0], point[1])
      })
      markLine.data = lines
    },

    // 缩略图点击
    handleThumbnailChartClick(param) {
      const { offsetX, offsetY } = param
      const thumbnailChart = this.$refs.thumbnailChartRef.getChartInstance()

      const point = getXAxisAndYAxisByPosition(thumbnailChart, offsetX, offsetY)
      if (point && this.thumbnailChartRect && this.thumbnailChartRect.length) {
        const [x1, y2, x2, y1] = this.thumbnailChartRect
        const halfWidth = Math.ceil((x2 - x1) / 2)
        const halfHeight = Math.ceil((y2 - y1) / 2)

        let [xAxis, yAxis] = point

        xAxis = parseInt(xAxis)
        yAxis = parseInt(yAxis)

        const xAxisMax = thumbnailChart.getModel().getComponent('xAxis').axis.scale._extent[1]
        const yAxisMax = thumbnailChart.getModel().getComponent('yAxis').axis.scale._extent[1]

        const xAxisLimit = this.rangeNumber(halfWidth, xAxisMax - halfWidth)
        const yAxisLimit = this.rangeNumber(halfHeight, yAxisMax - halfHeight)

        xAxis = xAxisLimit(xAxis)
        yAxis = yAxisLimit(yAxis)

        this.setThumbnailChartRect(xAxis - halfWidth, yAxis + halfHeight, xAxis + halfWidth, yAxis - halfHeight)

        this.option.xAxis.min = xAxis - halfWidth
        this.option.xAxis.max = xAxis + halfWidth
        this.option.yAxis.min = yAxis - halfHeight
        this.option.yAxis.max = yAxis + halfHeight
      }
    },

    // 重置
    handleReset() {
      this.option.xAxis.min = 0
      this.option.xAxis.max = 'dataMax'
      this.option.yAxis.min = 0
      this.option.yAxis.max = Math.ceil(Math.max(...this.shadowChannelChart.pointlist.map(item => item.y)) * 1.1)

      this.thumbnailOption.series[0].markLine.data = []
      this.thumbnailChartRect = []
    },

    // 根据name查找series
    findSeriesByName(seriesName) {
      return this.option.series.find(item => item.name == seriesName)
    },

    /**
     * 根据两个点生成一个markLine直线
     */
    generateLineDataByTwoPoints(point1, point2) {
      return [
        {
          xAxis: point1[0],
          yAxis: point1[1]
        },
        {
          xAxis: point2[0],
          yAxis: point2[1]
        }
      ]
    },

    /**
     * 限定数字在一定范围
     * @param {Number} min
     * @param {Number} max
     */
     rangeNumber(min, max) {
      return num => {
        return num > max ? max : num < min ? min : num
      }
    },
  },
  watch: {
    sample: {
      handler() {
        this.getSampleDetail()
      },
      immediate: true
    }
  }
}
</script>

<style lang="less" scoped>
.gamma-analysis {
  height: 100%;

  .ant-spin-nested-loading {
    height: 100%;

    ::v-deep {
      .ant-spin-container {
        height: 100%;
      }
    }
  }

  &-main {
    height: calc(100% - 51px);
    display: flex;
    overflow: auto hidden;
    position: relative;
  }

  &-chart {
    width: 100%;
    height: 100%;
    position: relative;
  }

  &-thumbnail {
    position: absolute;
    top: 50px;
    right: 10px;
    width: 500px;
    height: 20%;
    background-color: #153e44;
  }
}
</style>
