<template>
  <div>
    <el-dialog v-el-drag-dialog :visible.sync="showMobile" title="" :close-on-click-modal="false" :close-on-press-escape="false" :custom-class="mobileStyle" @close="close">
      <div slot="title" class="cfff fs14">
        <span class="ml20">{{ mobileName }}</span>
        <el-dropdown placement="bottom" class="fr mr100 oln" trigger="hover" @command="handleCommand" @visible-change="handleVisble">
          <span class="fs14 cfff">{{ bitRateText }}<i :class="caretIcon" /></span>
          <el-dropdown-menu slot="dropdown" class="mobile-dropdown-menu">
            <el-dropdown-item :class="bitRateStyle('1638400')" command="1638400">自动</el-dropdown-item>
            <el-dropdown-item :class="bitRateStyle('491520')" command="491520">极速</el-dropdown-item>
            <el-dropdown-item :class="bitRateStyle('1392640')" command="1392640">标清</el-dropdown-item>
            <el-dropdown-item :class="bitRateStyle('2785280')" command="2785280">高清</el-dropdown-item>
          </el-dropdown-menu>
        </el-dropdown>
      </div>
      <div class="frns">
        <div class="mobile-audio">
          <video
            ref="player"
            width="372px"
            :controls="false"
            autoplay
            @play="ready"
            @error="error"
            @pause="pause"
            @mousedown="handleMouseDown"
            @mousemove="handleMouseMove"
            @mouseup="handleMouseUp"
            @mouseleave="handleMouseLeave"
          />
          <audio
            ref="audioPlayer"
            width="372px"
            controls
            autoplay
            poster="@/assets/equipment/loader-thumb.jpg"
          />
          <div v-if="isMask" class="mask">
            <i v-if="isLoading" class="el-icon-loading" />
            <img v-if="isError" class="w180h148" src="@/assets/equipment/guzhang_lixian_pic.png" alt="">
            <div class="c999 fs12 mt15">{{ maskText }}</div>
          </div>
        </div>
        <div class="mobile-sidebar">
          <i :class="volumeUpIcon" @click="handleRoutine(24)" />
          <i :class="volumeDownIcon" @click="handleRoutine(25)" />
          <el-popover placement="bottom-start" popper-class="nav-popover" width="109" trigger="hover">
            <div class="tac ptb10 c333 fs14">重启</div>
            <i slot="reference" :class="shutDownIcon" @click="reboot" />
          </el-popover>
          <el-popover placement="bottom-start" popper-class="nav-popover" width="109" trigger="hover">
            <div class="tac ptb10 c333 fs14">恢复出厂设置</div>
            <i slot="reference" :class="restartIcon" @click="recovery" />
          </el-popover>
        </div>
      </div>
      <div class="mobile-bottombar">
        <i :class="menuIcon" @click="handleRoutine(187)" />
        <i :class="homeIcon" @click="handleRoutine(3)" />
        <i :class="backIcon" @click="handleRoutine(4)" />
      </div>
    </el-dialog>
  </div>
</template>

<script>
import elDragDialog from '@/directive/el-drag-dialog'
import JMuxer from 'jmuxer'
import { getcardInfoBySn, rebootBatch, recovery, getcardStatus } from '@/api/mobile'
import { ExexuteMouseDown, ExexuteMouseMove, ExexuteMouseUp, ExexuteKeyDown, ExexutePixel, ExexuteCloseServer, CheckScreenDirection, RequestIFrame, ConfigChannel } from '@/utils/control'
import { keycodeMode } from '@/utils/config'

const VIDEO_WIDTH = 371
const VIDEO_HEIGHT = 660

export default {
  name: 'DragDialogDemo',
  directives: { elDragDialog },
  props: {
    sn: {
      type: Array,
      default: () => {
        return []
      }
    },
    mobileName: {
      type: String,
      default: ''
    },
    mobileId: {
      type: Number,
      default: 0
    }
  },
  data() {
    return {
      showMobile: true,
      fpsCount: 0,
      timeCount: 0,
      isFeed: true,
      curTime: new Date().getTime(),
      requestTime: new Date().getTime(),
      jmuxer: null,
      audioMuxer: null,
      ip: '', // 设备ip
      port: '', // 设备端口号
      size: '', // 设备分辨率
      bitRate: '', // 设备清晰度
      path: 'ws://192.168.11.66:9101', // websocket地址
      socket: null, // websocket类
      isDrag: false,
      isLoading: true, // 加载中
      isMask: true, // 遮罩层
      maskText: '', // 加载文字
      isError: false, // 是否设备故障或者离线
      visble: false, // 下拉菜单是否展开
      isRotate: false, // 是否横屏
      isFlag: false
    }
  },
  computed: {
    bitRateStyle() {
      return (num) => {
        return this.bitRate === num ? 'pl20 bgcf3f6ff c515ff0 fs14' : 'pl20 c333 fs14'
      }
    },
    bitRateText() {
      /**
       * 极速 | 491520，60KB/S
       * 标清 | 1392640 ，170KB/S
       * 自动 | 1638400 ，200KB/S
       * 高清 | 2785280 ，340KB/S
       */
      const option = {
        '1638400': '自动',
        '491520': '极速',
        '1392640': '标清',
        '2785280': '高清'
      }
      return option[this.bitRate]
    },
    volumeUpIcon() {
      return this.isLoading || this.isError ? 'icon-volume-up disabled mt50' : 'icon-volume-up mt50'
    },
    volumeDownIcon() {
      return this.isLoading || this.isError ? 'icon-volume-down disabled mt40' : 'icon-volume-down mt40'
    },
    shutDownIcon() {
      return this.isLoading || this.isError ? 'icon-shutdown disabled mt226ormt90' : 'icon-shutdown mt226ormt90'
    },
    restartIcon() {
      return this.isLoading || this.isError ? 'icon-restart disabled mt40' : 'icon-restart mt40'
    },
    menuIcon() {
      return this.isLoading || this.isError ? 'icon-background disabled' : 'icon-background'
    },
    homeIcon() {
      return this.isLoading || this.isError ? 'icon-index disabled mlr64ormlr160' : 'icon-index mlr64ormlr160'
    },
    backIcon() {
      return this.isLoading || this.isError ? 'icon-back disabled' : 'icon-back'
    },
    caretIcon() {
      return this.visble ? 'el-icon-caret-top ml5' : 'el-icon-caret-bottom ml5'
    },
    mobileStyle() {
      return this.isRotate ? 'mobile-dialog rotate' : 'mobile-dialog'
    }
  },
  created() {
    this.getcardInfoBySn()
  },
  mounted() {
    document.addEventListener('visibilitychange', this.audioPlay)
    document.addEventListener('keydown', this.handleKeyDown)
    this.$nextTick(() => {
      this.jmuxer = new JMuxer({
        node: this.$refs.player,
        flushingTime: 15,
        fps: 30,
        mode: 'video',
        debug: false
      })
      this.audioMuxer = new JMuxer({
        node: this.$refs.audioPlayer,
        flushingTime: 1,
        clearBuffer: true,
        fps: 43, // 可以不选
        mode: 'audio',
        debug: false
      })
    })

    this.curTime = new Date().getTime()
  },
  destroyed() {
    document.removeEventListener('visibilitychange', this.audioPlay)
    document.removeEventListener('keydown', this.handleKeyDown)
    this.socket.send(ExexuteCloseServer(this.sn.join(','))) // 销毁监听
    this.socket.close()
  },
  methods: {
    handleVisble(flag) {
      this.visble = flag
    },
    // 设备恢复出厂设置
    recovery() {
      if (this.isLoading || this.isError) {
        this._message.warning('操作过于频繁，请稍后再试')
        return
      }
      this.$confirm('<div class="c666 fs18 mb10">确认要恢复出厂设置吗？</div><div class="c999 fs14">恢复出厂后将恢复到初始设置并清除所有数据，恢复出厂过程/n中设备将不可操作。</div>', '恢复出厂', {
        dangerouslyUseHTMLString: true,
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        customClass: 'cloud-phone-message-box', // 自定义消息样式类名
        confirmButtonClass: 'cloud-phone-confirm-btn', // 自定义确认按钮样式类名
        cancelButtonClass: 'cloud-phone-cancel-btn' // 自定义取消按钮样式类名
      }).then(() => {
        recovery({ sns: this.sn.join(',') }).then(res => {
          if (res.status === 0) {
            this.$alert('<div class="c666 fs18 mb10">恢复出厂设置指令已发送</div><div class="c999 fs14">若恢复出厂设置失败可重试</div>', '恢复出厂', {
              dangerouslyUseHTMLString: true,
              confirmButtonText: '确认',
              customClass: 'cloud-phone-message-box',
              confirmButtonClass: 'cloud-phone-confirm-btn', // 自定义确认按钮样式类名
              callback: action => {
                this.isMask = true
                this.isLoading = true
                this.maskText = '设备恢复出厂设置中...'
                this._send()
              }
            })
          } else {
            this._message.error('恢复出厂设置指令发送失败，请稍后再试')
          }
        })
      }).catch(() => {})
    },
    // 设备重启
    reboot() {
      if (this.isLoading || this.isError) {
        this._message.warning('操作过于频繁，请稍后再试')
        return
      }
      this.$confirm('<div class="c666 fs18 mb10">确认要重启设备吗？</div><div class="c999 fs14">重启后将完全关闭后台进程，重启过程中设备将不可操作。</div>', '重启', {
        dangerouslyUseHTMLString: true,
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        customClass: 'cloud-phone-message-box', // 自定义消息样式类名
        confirmButtonClass: 'cloud-phone-confirm-btn', // 自定义确认按钮样式类名
        cancelButtonClass: 'cloud-phone-cancel-btn' // 自定义取消按钮样式类名
      }).then(() => {
        rebootBatch({ sns: this.sn.join(',') }).then(res => {
          if (res.status === 0) {
            this.$alert('<div class="c666 fs18 mb10">重启指令已发送</div><div class="c999 fs14">若重启失败可重试</div>', '重启', {
              dangerouslyUseHTMLString: true,
              confirmButtonText: '确认',
              customClass: 'cloud-phone-message-box',
              confirmButtonClass: 'cloud-phone-confirm-btn', // 自定义确认按钮样式类名
              callback: action => {
                this.isMask = true
                this.isLoading = true
                this.maskText = '设备重启中...'
                this._send()
              }
            })
          } else {
            this._message.error('重启指令发送失败，请稍后再试')
          }
        })
      }).catch(() => {})
    },
    async _send() {
      const state = await this.getcardStatus()
      if (state === '1') {
        this.socket.send(ExexuteCloseServer(this.sn.join(','))) // 销毁监听
        this.socket.close()
        this.init()
        this.isLoading = false
        this.isMask = false
        this.maskText = ''
      } else {
        setTimeout(() => {
          this._send()
        }, 3000)
      }
    },
    async getcardStatus() {
      const res = await getcardStatus({ sns: this.sn.join(',') }).then(res => { return res })
      let state = '0'
      if (res.status === 0) {
        state = res.data[0].state
      }
      return state
    },
    // 设置像素
    handleCommand(command) {
      if (this.isLoading || this.isError) {
        return
      }
      this.bitRate = command
      const buffer = ExexutePixel(command, this.sn.join(','))
      this.socket.send(buffer)
    },
    // 音量加减、home键、back事件(keyCode的值分别表示为25减音量，24加音量，4为返回键，3为home键，187为切换菜单)
    handleRoutine(code) {
      if (this.isLoading || this.isError) {
        return
      }
      const buffer = ExexuteKeyDown(code, this.sn.join(','))
      this.socket.send(buffer)
    },
    // 鼠标点击事件
    handleMouseDown(event) {
      if (this.isLoading || this.isError) {
        return
      }
      if (event.button === 0) {
        var posX = this.isRotate ? event.offsetY / VIDEO_HEIGHT * 1920 * 1.0 : event.offsetX / VIDEO_WIDTH * 1080 * 1.0
        var posY = this.isRotate ? (VIDEO_WIDTH - event.offsetX) / VIDEO_WIDTH * 1080 * 1.0 : event.offsetY / VIDEO_HEIGHT * 1920 * 1.0
        var buffer = ExexuteMouseDown(posX.toString(), posY.toString(), this.sn.join(','))
        this.socket.send(buffer)
        this.isDrag = true
      }
    },
    // 鼠标移开事件
    handleMouseLeave(event) {
      if (this.isLoading || this.isError) {
        return
      }
      this.isDrag = false
      var posX = this.isRotate ? event.offsetY / VIDEO_HEIGHT * 1920 * 1.0 : event.offsetX / VIDEO_WIDTH * 1080 * 1.0
      var posY = this.isRotate ? (VIDEO_WIDTH - event.offsetX) / VIDEO_WIDTH * 1080 * 1.0 : event.offsetY / VIDEO_HEIGHT * 1920 * 1.0
      var buffer = ExexuteMouseUp(posX.toString(), posY.toString(), this.sn.join(','))
      this.socket.send(buffer)
    },
    // 鼠标移动事件
    handleMouseMove(event) {
      if (this.isLoading || this.isError) {
        return
      }
      if (this.isDrag && event.button === 0) {
        var posX = this.isRotate ? event.offsetY / VIDEO_HEIGHT * 1920 * 1.0 : event.offsetX / VIDEO_WIDTH * 1080 * 1.0
        var posY = this.isRotate ? (VIDEO_WIDTH - event.offsetX) / VIDEO_WIDTH * 1080 * 1.0 : event.offsetY / VIDEO_HEIGHT * 1920 * 1.0
        var buffer = ExexuteMouseMove(posX.toString(), posY.toString(), this.sn.join(','))
        this.socket.send(buffer)
      }
    },
    // 鼠标离开事件
    handleMouseUp(event) {
      if (this.isLoading || this.isError) {
        return
      }
      this.isDrag = false
      var posX = this.isRotate ? event.offsetY / VIDEO_HEIGHT * 1920 * 1.0 : event.offsetX / VIDEO_WIDTH * 1080 * 1.0
      var posY = this.isRotate ? (VIDEO_WIDTH - event.offsetX) / VIDEO_WIDTH * 1080 * 1.0 : event.offsetY / VIDEO_HEIGHT * 1920 * 1.0
      var buffer = ExexuteMouseUp(posX.toString(), posY.toString(), this.sn.join(','))
      this.socket.send(buffer)
    },
    // 键盘输入事件
    handleKeyDown(event) {
      if (this.isLoading || this.isError) {
        return
      }
      var buffer = ExexuteKeyDown(keycodeMode[event.keyCode] || event.keyCode, this.sn.join(','))
      this.socket.send(buffer)
    },
    // websocket初始化
    init() {
      this.socket = new WebSocket(this.path) // 实例化socket
      this.socket.binaryType = 'arraybuffer'
      this.socket.onopen = this.open // 监听socket连接
      this.socket.onerror = this.onerror // 监听socket错误信息
      this.socket.onmessage = this.getMessage // 监听socket消息
    },
    // websocket连接成功回调
    open() {
      this.isMask = false
      this.isError = false
      this.socket.send(ConfigChannel(this.sn))
      this.socket.onmessage = this.getMessage
    },
    // websocket连接失败回调
    onerror() {
      console.log('websocket连接失败')
      this.isLoading = false
      this.isError = true
      this.maskText = '设备故障或离线'
    },
    getMessage(event) {
      const data = this.parse(event.data) // 分离音视频数据
      const audioData = {
        audio: data.audio,
        video: null,
        duration: data.duration
      }
      // const videoData = {
      //   audio: null,
      //   video: data.video,
      //   duration: data.duration
      // }

      if (this.$refs.audioPlayer && this.$refs.audioPlayer.readyState === 2) {
        const playPromise = this.$refs.audioPlayer.play()
        if (playPromise !== undefined) {
          playPromise.then(() => {
            this.$refs.audioPlayer.play()
          }).catch(() => {})
        }
      }
      if (data.audio != null) { // 喂音频
        this.audioMuxer.feed(audioData)
      }
      if (data.video != null && this.isFeed) { // 喂视频
        this.jmuxer.feed(data)
      }
      if (data.video) {
        if (new Date().getTime() - this.curTime >= 1000) {
          this.fpsCount = 0
          this.curTime = new Date().getTime()
        } else {
          this.fpsCount++
        }
      }
    },
    // 弹窗关闭
    close() {
      this.$emit('closeDialog', 'showMobile')
    },
    // 根据sn获取设备获取清晰度、端口号和ip
    getcardInfoBySn() {
      var list = []
      list.push(this.mobileId)
      getcardInfoBySn({ mobileIdList: list }).then(res => {
        if (res.status === 0) {
          this.ip = res.data[0].ip
          this.port = res.data[0].port
          this.size = res.data[0].size
          this.bitRate = res.data[0].bitRate === '0' ? '1638400' : res.data.bitRate
          this.path = `ws://${res.data[0].ip}:${res.data[0].websocketPort.toString()}`
          //console.log(this.path)
          this.init()
        }
      })
    },
    pause() {
      this.isFeed = false
    },
    audioPlay() {
      if (document.visibilityState === 'visible') {
        this.isFlag = true
        this.socket.send(RequestIFrame(this.sn.join(',')))
      } else {
        this.isFlag = false
        this.isFeed = false
        this.$refs.player.pause()
      }
    },
    ready() {
      this.isLoading = false
    },
    error() {
      this.isMask = true
      this.isError = true
    },
    parse(data) {
      // var input = new Uint8Array(data)
      // var dv = new DataView(input.buffer)
      // var duration = dv.getUint16(0, true) // 获取duration
      // var audioLength = dv.getUint16(2, true)
      // var audio
      // var video

      // if (audioLength === 0) {
      //   video = input.subarray(4)
      // } else {
      //   audio = input.subarray(4, (audioLength + 4))
      //   video = input.subarray(audioLength + 4)
      // }

      // return {
      //   audio: audio,
      //   video: video,
      //   duration: duration
      // }
      var input = new Uint8Array(data)
      var duration
      var video
      var audio
      if (input[0] === 0 && input[1] === 0 && input[2] === 0 && input[3] === 1) {
        video = input
        duration = 24
        var nalType = input[4] & 0x1f
        if (nalType === 0x05 && this.isFlag) { // 策略， 找到sps、sps、或I帧，才继续渲染
          this.isFeed = true
        }
      } else if (input[0] === 0xff) {
        audio = input
        duration = 24
      } else if (input[23] === 0x0b) {
        this.$alert('<div class="c666 fs18 mb10">设备' + this.mobileName + '已在其它端受控</div>', '提示', {
          dangerouslyUseHTMLString: true,
          confirmButtonText: '确认',
          customClass: 'cloud-phone-message-box',
          confirmButtonClass: 'cloud-phone-confirm-btn', // 自定义确认按钮样式类名
          callback: action => {
            this.showMobile = false
          }
        })
      } else if (input[0] === 0x68 && input[23] === 0x05) {
        var state = CheckScreenDirection(input.slice(24, 24 + 8))
        if (state === 1) {
          this.isRotate = false
        } else {
          this.isRotate = true
        }
      }

      return {
        audio: audio,
        video: video,
        duration: duration
      }
    }
  }
}
</script>

<style lang="scss">
  .ml111 {margin-left: 111px;}.mt50{margin-top: 50px;}.mt40{margin-top: 40px;}
  .w180h148 {width: 180px;height: 148px;}.mr100{margin-right: 100px;}
  .mobile-dialog {
    width: 417px;
    height: 740px;
    background: #141414;
    box-shadow: 0px 0px 30px 0px rgba(0, 0, 0, 0.5);
    border-radius: 0;
    &.rotate {
      width: 705px;
      height: 452px;
      .el-dialog__body {
        padding: 0;
        .mt226ormt90{
          margin-top: 90px;
        }
        .mlr64ormlr160{
          margin-left: 160px;
          margin-right: 160px;
        }
        .mobile-audio {
          width: 660px;
          height: 372px;
          position: relative;
          video {
            transform:rotate(-90deg);
            position: absolute;
            top: -145px;
            left: 145px;
          }
          .mask {
            width: 100%;
            height: 100%;
            background-color: #fff;
            position: absolute;
            top: 0;
            left: 0;
            display: flex;
            align-items: center;
            justify-content: center;
            flex-direction: column;
          }
        }
        .mobile-sidebar {
          width: 45px;
          height: 372px;
          display: flex;
          flex-direction: column;
          align-items: center;
        }
        .mobile-bottombar {
          width: 100%;
          height: 40px;
          display: flex;
          align-items: center;
          justify-content: center;
        }
      }
    }
    .el-dialog__header {
      height: 40px;
      line-height: 40px;
      padding: 0;
      .el-dialog__headerbtn {
        top: 13px;
        right: 15px;
        font-size: 14px;
        .el-dialog__close {
          color: #fff;
          font-weight: 800;
        }
      }
    }
    .el-dialog__body {
      padding: 0;
      .mt226ormt90 {
        margin-top: 226px;
      }
      .mlr64ormlr160{
        margin-left: 64px;
        margin-right: 64px;
      }
      .mobile-audio {
        width: 371px;
        height: 660px;
        position: relative;
        .mask {
          width: 100%;
          height: 100%;
          background-color: #fff;
          position: absolute;
          top: 0;
          left: 0;
          display: flex;
          align-items: center;
          justify-content: center;
          flex-direction: column;
        }
      }
      .mobile-sidebar {
        width: 46px;
        height: 660px;
        display: flex;
        flex-direction: column;
        align-items: center;
      }
      .mobile-bottombar {
        width: 100%;
        height: 40px;
        display: flex;
        align-items: center;
        justify-content: center;
      }
    }
  }
  .mobile-dropdown-menu {
    width: 110px;
    padding: 5px 0;
    border: none;
    box-shadow: 0px 0px 30px 0px rgba(0, 0, 0, 0.3);
    .popper__arrow {
      border-width: 10px;
      border-bottom-color: #fff !important;
      top: -8px !important;
      left: 60px !important;
    }
    .el-dropdown-menu__item {
      height: 40px;
      line-height: 40px;
      &:hover {
        background-color: #F3F6FF;
        color: #333;
      }
    }
  }
  audio {
    display: none;
  }
</style>
