<template>
  <box
    title="全链路监测状态"
    @fullscreen="onFullscreen"
  >
    <div
      ref="box"
      v-loading="!loaded && loading"
      element-loading-background="transparent"
      class="l-flex__fill l-flex--row center jcenter"
    >
      <div
        v-if="loaded"
        class="c-device-dashboard-link-state"
        :class="{ fullscreen }"
        :style="scaleStyle"
      >
        <div
          v-for="item in items"
          :key="item.key"
          class="co"
          :class="item.className"
        >
          <div
            v-if="item.multiLines"
            class="ctext"
          >
            <div>{{ item.label[0] }}</div>
            <div>{{ item.label[1] }}</div>
          </div>
          <div
            v-else
            class="ctext"
          >
            {{ item.label }}
          </div>
          <device-player
            v-if="item.key === 'led'"
            :device="device"
            autoplay
          />
          <svg-icon
            v-else
            class="c-device-dashboard-link-state__img"
            :icon-class="item.icon"
          />
        </div>
        <div
          v-for="line in lines"
          :key="line.key"
          class="line"
          :class="line.className"
        >
          <svg
            v-if="line.linked"
            class="svg"
          >
            <polyline
              class="polyline"
              :points="line.points"
              style="fill: none; stroke: #0ab4ff; stroke-width: 1px"
              :style="{
                strokeDasharray: line.length + 'px',
                strokeDashoffset: line.length + 'px',
                animation: line.animation,
              }"
            />
            <ellipse
              v-if="line.type !== 'col'"
              :rx="fullscreen ? 4 : 2"
              cx="0"
              :ry="fullscreen ? 2 : 1"
              cy="0"
              fill="#0AB4FF"
            >
              <animateMotion
                dur="2s"
                repeatCount="indefinite"
                :path="line.path"
              />
            </ellipse>
            <ellipse
              v-else
              :ry="fullscreen ? 4 : 2"
              cy="0"
              :rx="fullscreen ? 2 : 1"
              cx="0"
              fill="#0AB4FF"
            >
              <animateMotion
                dur="2s"
                repeatCount="indefinite"
                :path="line.path"
              />
            </ellipse>
          </svg>
        </div>
      </div>
    </div>
  </box>
</template>

<script>
import { getBoundThirdPartyDevices } from '@/api/external'
import { ThirdPartyDevice } from '@/constant'
import Box from './Box'

const LinkItems = Object.freeze([
  {
    key: 'msr',
    label: '浪潮屏媒安播云平台'
  },
  {
    key: 'device',
    label: ['浪潮超高清', '媒体播控器'],
    multiLines: true
  },
  {
    key: 'led',
    label: 'LED大屏'
  },
  {
    key: ThirdPartyDevice.GATEWAY,
    alias: 'gateway',
    label: '浪潮物联网关',
    iconKey: 'gateway',
    canClick: true
  },
  {
    key: ThirdPartyDevice.TRAFFIC_CAMERA,
    alias: 'traffic_camera',
    label: '人流量监测摄像头',
    iconKey: 'camera',
    canClick: true
  },
  {
    key: ThirdPartyDevice.LED_CAMERA,
    alias: 'led_camera',
    label: 'LED屏监测摄像头',
    iconKey: 'camera',
    canClick: true
  },
  {
    key: ThirdPartyDevice.SENDING_CARD,
    alias: 'sending_card',
    label: '发送控制设备',
    iconKey: 'sending-card',
    canClick: true
  },
  {
    key: ThirdPartyDevice.RECEIVING_CARD,
    alias: 'receiving_card',
    label: '接收卡',
    iconKey: 'receiving-card',
    canClick: true
  }
])

const LineFromeTo = {
  1: ['msr', 'device'],
  2: ['device', ThirdPartyDevice.SENDING_CARD],
  3: [ThirdPartyDevice.SENDING_CARD, ThirdPartyDevice.RECEIVING_CARD],
  4: ['msr', ThirdPartyDevice.GATEWAY, ThirdPartyDevice.LED_CAMERA, ThirdPartyDevice.TRAFFIC_CAMERA],
  5: ['msr', ThirdPartyDevice.TRAFFIC_CAMERA],
  6: ['msr', ThirdPartyDevice.LED_CAMERA],
  7: [ThirdPartyDevice.GATEWAY, 'led'],
  8: [ThirdPartyDevice.RECEIVING_CARD, 'led']
}

export default {
  name: 'LinkState',
  components: {
    Box
  },
  props: {
    device: {
      type: Object,
      required: true
    }
  },
  data () {
    return {
      fullscreen: false,
      scale: 1,
      loading: false,
      loaded: false,
      linkDeviceMap: null
    }
  },
  computed: {
    scaleStyle () {
      return this.fullscreen
        ? null
        : { transform: `scale(${this.scale})` }
    },
    online () {
      return this.device.activate === 2 && this.device.onlineStatus === 1
    },
    linkState () {
      const map = {
        msr: 1,
        device: this.online ? 1 : 0,
        led: this.online ? 1 : 0,
        [ThirdPartyDevice.GATEWAY]: -1,
        [ThirdPartyDevice.LED_CAMERA]: -1,
        [ThirdPartyDevice.TRAFFIC_CAMERA]: -1,
        [ThirdPartyDevice.SENDING_CARD]: -1,
        [ThirdPartyDevice.RECEIVING_CARD]: -1
      }
      if (this.linkDeviceMap) {
        for (const item of this.linkDeviceMap) {
          map[item.deviceType] = item.status
        }
      }
      return map
    },
    items () {
      const map = this.linkState
      return LinkItems.map(({ key, alias, label, iconKey, multiLines }) => {
        const status = map[key]
        return {
          key, label, status, multiLines,
          icon: status === -1
            ? 'link-unbound'
            : `link-${iconKey || key}-${status === 1 ? 'online' : 'offline'}`,
          className: alias || key
        }
      })
    },
    lines () {
      const map = this.fullscreen
        ? [
          null,
          {
            points: '0,4 150,4',
            path: 'M0,4 L150,4',
            length: 150,
            animation: this.getAnimation(150)
          },
          {
            points: '0,4 150,4',
            path: 'M0,4 L150,4',
            length: 150,
            animation: this.getAnimation(150)
          },
          {
            points: '0,4 150,4',
            path: 'M0,4 L150,4',
            length: 150,
            animation: this.getAnimation(150)
          },
          {
            points: '4,0 4,137',
            path: 'M4,0 L4,137',
            type: 'col',
            length: 137,
            animation: this.getAnimation(137)
          },
          {
            points: '0,50 350,50 350,0 400,0',
            path: 'M0,50 L350,50 L350 0 L400,0',
            type: 'polygon',
            length: 450,
            animation: this.getAnimation(450)
          },
          {
            points: '0,51 350,51 350,100 400,100',
            path: 'M0,51 L350,51 L350,100 L400,100',
            type: 'polygon',
            length: 449,
            animation: this.getAnimation(449)
          },
          {
            points: '0,4 494,4',
            path: 'M0,4 L494,4',
            length: 494,
            animation: this.getAnimation(494)
          },
          {
            points: '4,0 4,78',
            path: 'M4,0 L4,78',
            type: 'col',
            length: 78,
            animation: this.getAnimation(78)
          }
        ]
        : [
          null,
          {
            points: '0,4 22,4',
            path: 'M0,4 L22,4',
            length: 22,
            animation: this.getAnimation(22)
          },
          {
            points: '0,4 22,4',
            path: 'M0,4 L22,4',
            length: 22,
            animation: this.getAnimation(22)
          },
          {
            points: '0,4 22,4',
            path: 'M0,4 L22,4',
            length: 22,
            animation: this.getAnimation(22)
          },
          {
            points: '4,0 4,95',
            path: 'M4,0 L4,95',
            type: 'col',
            length: 95,
            animation: this.getAnimation(95)
          },
          {
            points: '0,18 80,18 80 0 105 0',
            path: 'M0,18 L80,18 L80 0 L105 0',
            type: 'polygon',
            length: 123,
            animation: this.getAnimation(123)
          },
          {
            points: '0,19 80,19 80 36 105 36',
            path: 'M0,19 L80,19 L80 36 L105 36',
            type: 'polygon',
            length: 122,
            animation: this.getAnimation(122)
          },
          {
            points: '0,4 119,4',
            path: 'M0,4 L119,4',
            length: 119,
            animation: this.getAnimation(119)
          },
          {
            points: '4,0 4,92',
            path: 'M4,0 L4,92',
            type: 'col',
            length: 92,
            animation: this.getAnimation(92)
          }
        ]
      const state = this.linkState
      return Object.keys(LineFromeTo).map(key => {
        const from = LineFromeTo[key][0]
        const to = LineFromeTo[key].slice(1)
        const linked = state[from] === 1 && to.some(key => state[key] === 1)
        return {
          ...map[key],
          linked,
          key: `line${key}`,
          className: [`l${key}`, linked ? '' : 'closed'].join(' ')
        }
      })
    }
  },
  created () {
    this.getBoundThirdPartyDevices()
    this.$timer = setInterval(this.getBoundThirdPartyDevices, 10000)
  },
  mounted () {
    this.onFullscreen(this.fullscreen)
    const width = this.$refs.box.clientWidth
    const height = this.$refs.box.clientHeight
    this.scale = Math.min(278 / width, 244 / height)
  },
  beforeDestroy () {
    clearInterval(this.$timer)
  },
  methods: {
    onFullscreen (fullscreen) {
      this.fullscreen = fullscreen
    },
    getAnimation (length, gap, dur = 2, mode = 'linear') {
      return `${dur}s linkLength${length} ${mode} infinite`
    },
    getBoundThirdPartyDevices () {
      if (this.loading) {
        return
      }
      this.loading = true
      getBoundThirdPartyDevices(this.device.id, true).then(({ data }) => {
        this.linkDeviceMap = data
        this.loaded = true
      }).finally(() => {
        this.loading = false
      })
    }
  }
}
</script>

<style lang="scss" scoped>
@mixin getPosition($left, $top, $width, $height) {
  left: $left;
  top: $top;
  width: $width;
  height: $height;
}

.c-device-dashboard-link-state {
  position: relative;
  width: 278px;
  height: 244px;
  transform-origin: center;

  &__img {
    width: 100%;
    height: 100%;
  }

  .co {
    position: absolute;
    background-position: center;
    background-size: cover;
    background-repeat: no-repeat;
    z-index: 1;
  }

  .line {
    position: absolute;
    background: #a1c9ff;

    &.closed {
      background: #d5d9e4;
    }
  }

  .svg {
    position: absolute;
    top: -4px;
    left: 0;
    width: 100%;
    height: 8px;
  }

  .col {
    .svg {
      position: absolute;
      top: 0;
      left: -4px;
      width: 8px;
      height: 100%;
    }
  }

  .polygon {
    .svg {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
    }
  }

  .ctext {
    display: flex;
    flex-direction: column;
    align-items: center;
    position: absolute;
    left: 0;
    bottom: -20px;
    width: 100%;
    height: 15px;
    color: #fff;
    font-size: 12px;
    line-height: 15px;
    text-align: center;
    white-space: nowrap;
    transform-origin: center top;
    transform: scale(0.8);
  }

  .msr {
    @include getPosition(0, 0, 92px, 92px);
  }

  .device {
    @include getPosition(108px, 32px, 44px, 48px);
  }

  .sending_card {
    @include getPosition(176px, 32px, 44px, 48px);
  }

  .receiving_card {
    @include getPosition(234px, 32px, 44px, 48px);
  }

  .traffic_camera {
    @include getPosition(141px, 107px, 40px, 40px);

    .ctext {
      left: 10px;
      bottom: -10px;
    }
  }

  .led_camera {
    @include getPosition(141px, 145px, 40px, 40px);

    .ctext {
      left: -20px;
      bottom: -10px;
    }
  }

  .gateway {
    @include getPosition(25px, 180px, 40px, 40px);
  }

  .led {
    @include getPosition(182px, 168px, 96px, 54px);
  }

  .l1 {
    @include getPosition(88px, 63px, 22px, 1px);
  }

  .l2 {
    @include getPosition(146px, 63px, 32px, 1px);
  }

  .l3 {
    @include getPosition(214px, 63px, 22px, 1px);
  }

  .l4 {
    @include getPosition(45px, 88px, 1px, 95px);
  }

  .l5 {
    @include getPosition(45px, 122px, 105px, 36px);
    clip-path: polygon(
      0 18px,
      80px 18px,
      80px 0,
      105px 0,
      105px 1px,
      81px 1px,
      81px 19px,
      0 19px
    );
  }

  .l6 {
    @include getPosition(45px, 122px, 105px, 36px);
    clip-path: polygon(
      0 19px,
      81px 19px,
      81px 35px,
      105px 35px,
      105px 36px,
      80px 36px,
      80px 20px,
      0 20px
    );
  }

  .l7 {
    @include getPosition(63px, 206px, 119px, 1px);
  }

  .l8 {
    @include getPosition(256px, 76px, 1px, 92px);
  }

  &.fullscreen {
    width: 1030px;
    height: 528px;

    .ctext {
      bottom: -30px;
      height: 25px;
      line-height: 25px;
      font-size: 18px;
      transform: none;
    }

    .msr {
      @include getPosition(0, 0, 250px, 250px);
    }

    .device {
      @include getPosition(389px, 118px, 90px, 90px);
    }

    .sending_card {
      @include getPosition(622px, 118px, 90px, 90px);
    }

    .receiving_card {
      @include getPosition(854px, 118px, 90px, 90px);
    }

    .traffic_camera {
      @include getPosition(511px, 213px, 90px, 90px);

      .ctext {
        bottom: -20px;
      }
    }

    .led_camera {
      @include getPosition(511px, 308px, 90px, 90px);

      .ctext {
        bottom: -12px;
      }
    }

    .gateway {
      @include getPosition(80px, 377px, 90px, 90px);
    }

    .led {
      @include getPosition(660px, 279px, 370px, 208px);
    }

    .l1 {
      @include getPosition(243px, 177px, 150px, 1px);
    }

    .l2 {
      @include getPosition(475px, 178px, 150px, 1px);
    }

    .l3 {
      @include getPosition(709px, 178px, 150px, 1px);
    }

    .l4 {
      @include getPosition(124px, 246px, 1px, 137px);
    }

    .l5 {
      @include getPosition(125px, 238px, 400px, 100px);
      clip-path: polygon(
        0 50px,
        350px 50px,
        350px 0,
        400px 0,
        400px 1px,
        351px 1px,
        351px 51px,
        0 51px
      );
    }

    .l6 {
      @include getPosition(125px, 238px, 400px, 100px);
      clip-path: polygon(
        0 51px,
        351px 51px,
        351px 99px,
        400px 99px,
        400px 100px,
        350px 100px,
        350px 52px,
        0 52px
      );
    }

    .l7 {
      @include getPosition(166px, 436px, 494px, 1px);
    }

    .l8 {
      @include getPosition(899px, 201px, 1px, 78px);
    }
  }
}
</style>

<style lang="scss">
$linkLengthArr: 22, 119, 92, 95, 122, 123, 150, 137, 450, 449, 494, 78;

@each $item in $linkLengthArr {
  @keyframes linkLength#{$item} {
    0% {
      stroke-dashoffset: $item + px;
    }
    100% {
      stroke-dashoffset: 0px;
    }
  }
}
</style>
