<template>
  <div :class="[componentClass, isCameraOpen && 'c-cam-open']">
    <button v-if="!isCameraOpen" class="c-btn-cam-open" @click="openCamera"></button>
    <div v-if="isCameraOpen" class="c-cam-open">
      <div class="c-t-bar">
        <button class="c-btn-cam-close" @click="closeCamera"></button>
      </div>
      <div class="c-cam">
        <video v-show="!isPhotoTaken" ref="camera" autoplay playsinline></video>
        <canvas v-show="isPhotoTaken" id="photoTaken" ref="canvas" :width="canvasWidth" :height="canvasHeight"></canvas>
      </div>
      <div v-if="actionState !== 0" class="c-b-bar">
        <button v-if="!isPhotoTaken" type="button" class="c-btn-shoot" @click="takePhoto"></button>

        <button v-if="isPhotoTaken" class="c-btn-disc-photo" @click="discardPhoto"></button>
        <a
          v-if="isPhotoTaken"
          class="c-btn-download"
          ref="btnDownloadPhoto"
          @click="downloadPhoto"
          :download="fileName"
        >
          <div ref="canvasToDataURL"></div>
        </a>
        <button v-if="isPhotoTaken" class="c-btn-acc-photo" @click="acceptPhoto"></button>
      </div>
      <c-spinner v-else-if="actionState === 0" />
    </div>
  </div>
</template>

<script>
import cSpinner from './c-spinner'

const props = {
  fileName: {
    type: String,
    default: 'camera-capture.jpg'
  },
  actionIdent: {
    type: String
  },
  multiple: {
    type: Boolean,
    default: false
  }
}

import { mapGetters, mapActions } from 'vuex';
import base from './c-base'

export default {
  extends: base,
  data: function () {
    return {
      componentClass: 'c-camera',
      isCameraOpen: false,
      isPhotoTaken: false,
      streamTrack: null,
      streamMaxWidth: null,
      streamMaxHeight: null,
      canvasWidth: null,
      canvasHeight: null,
      videoWidth: 4000 //Higher value does nt work on ZEBRA mobile device
    }
  },
  props,
  components: {
    'c-spinner': cSpinner
  },
  computed: {
    ...mapGetters('csAppWindowsUtils', [
      'getDataSetActionState'
    ]),
    actionState: function () {
      return this.getDataSetActionState(this.dataSet, this.actionIdent, this.contextRow)
    }
  },

  beforeDestroy: function() {
    this.closeCamera()
  },
  methods: {
    ...mapActions('csAppWindowsUtils', ['addFile', 'deleteAllFiles', 'invokeAction']),
    async createCameraElement() {
      const constraints = {
        audio: false,
        video: {
          width: this.videoWidth
        }
      }

      try {
        let stream = await navigator.mediaDevices.getUserMedia(constraints)
        this.streamTrack = stream.getVideoTracks()[0]
        if(this.streamTrack != null) {
          let capabilities = this.streamTrack.getCapabilities()
          this.streamMaxWidth = capabilities.width.max
          this.streamMaxHeight = capabilities.height.max

          let settings = this.streamTrack.getSettings()
          let streamOrientation = settings.width < settings.height ? 'vertical' : 'horizontal'

          if(streamOrientation == 'vertical') {
            this.canvasWidth = this.streamMaxHeight
            this.canvasHeight = this.streamMaxWidth
          } else {
            this.canvasWidth = this.streamMaxWidth
            this.canvasHeight = this.streamMaxHeight
          }

          this.$refs.camera.srcObject = stream
        }
      } catch (error) {
        throw error
      }
    },
    stopCameraStream() {
      if(this.$refs.camera == null || this.$refs.camera.srcObject == null)
        return
      let tracks = this.$refs.camera.srcObject.getTracks()
      if(tracks != null) {
        tracks.forEach(track => {
          track.stop()
        })
      }
    },
    async openCamera() {
      this.isPhotoTaken = false
      this.isCameraOpen = true
      await this.createCameraElement()
    },
    closeCamera() {
      this.isCameraOpen = false
      this.isPhotoTaken = false
      this.stopCameraStream()
    },
    async takePhoto() {
      let constrs = this.streamTrack.getConstraints();
      constrs.width = this.streamMaxWidth
      constrs.height = this.streamMaxHeight
      this.streamTrack.applyConstraints(constrs)
      const context = this.$refs.canvas.getContext('2d')
      context.drawImage(this.$refs.camera, 0, 0, this.canvasWidth, this.canvasHeight)
      this.isPhotoTaken = true

      constrs.width = this.videoWidth
      constrs.height = null
      this.streamTrack.applyConstraints(constrs)
    },
    discardPhoto() {
      this.isPhotoTaken = false
    },
    async acceptPhoto() {
      if (!this.multiple) {
        await this.deleteAllFiles({dataSet: this.dataSet})
      }
      ////
      const canvas = this.$refs.canvas
      if (canvas != null) {
        canvas.toBlob(async (blob) => {
          let file = new File([blob], this.fileName, { type: 'image/jpeg' })
          this.addFile({
            dataSet: this.dataSet,
            file: file
          });
          ////
          if (this.actionIdent != null && this.actionIdent != '') {
            let payload = {
              appWindowIdent: this.appWindowIdent,
              dataSetIdent: this.dataSetIdent,
              actionIdent: this.actionIdent,
              row: this.contextRow,
              router: this.$router,
              window: window,
              layoutIdent: this.layoutIdent
            }
            this.showConfirmation = false
            this.confirmed = false
            await this.invokeAction(payload)
          }
          ////
          this.closeCamera()
        }, 'image/jpeg');
      }
    },
    downloadPhoto() {
      const btnDownloadPhoto = this.$refs.btnDownloadPhoto
      const canvas = this.$refs.canvas.toDataURL('image/jpeg').replace('image/jpeg', 'image/octet-stream')
      btnDownloadPhoto.setAttribute('href', canvas)
    }
  }
}
</script>
