<template>
  <div
    ref="container"
    class="picture-player"
  >
    <div
      ref="picture-wrapper"
      class="picture-wrapper"
      oncontextmenu="return false;"
    >
      <div
        v-show="!isLoading"
        ref="picture-subwrapper"
        class="picture-subwrapper"
      >
        <div
          id="loupe"
          ref="loupe"
          class="loupe"
          :style="{
            background: 'url(' + pictureDlPath + ')'
          }"
        />
        <div v-show="isGif">
          <img
            ref="picture-gif"
            :src="pictureGifPath"
          >
        </div>
        <div v-show="!isGif">
          <img
            v-show="fullScreen"
            id="picture-big"
            ref="picture-big"
            :src="pictureDlPath"
          >
          <img
            v-show="!fullScreen"
            id="picture"
            ref="picture"
            :src="picturePath"
          >
        </div>
      </div>
      <spinner v-if="isLoading" />
    </div>
  </div>
</template>

<script>
import { fullScreenMixin } from '@/components/mixins/fullscreen'
import { domMixin } from '@/components/mixins/dom'
import Spinner from '@/components/widgets/Spinner'

export default {
  name: 'PictureViewer',

  components: {
    Spinner
  },
  mixins: [domMixin, fullScreenMixin],

  props: {
    big: {
      type: Boolean,
      default: false
    },
    defaultHeight: {
      type: Number,
      default: 0
    },
    fullScreen: {
      type: Boolean,
      default: false
    },
    isComparing: {
      type: Boolean,
      default: false
    },
    light: {
      type: Boolean,
      default: false
    },
    preview: {
      type: Object,
      default: () => {}
    }
  },

  data() {
    return {
      isLoading: true,
      picturePath: '',
      pictureDlPath: '',
      pictureGifPath: ''
    }
  },

  mounted() {
    this.container.style.height = this.defaultHeight + 'px'
    this.isLoading = true
    if (this.picture.complete) {
      this.isLoading = false
      this.onWindowResize()
    }
    this.picture.addEventListener('load', this.endLoading)
    this.pictureBig.addEventListener('load', this.endLoading)
    this.pictureGif.addEventListener('load', this.endLoading)
    window.addEventListener('resize', this.onWindowResize)
    this.setPicturePath()
  },

  beforeUnmount() {
    window.removeEventListener('resize', this.onWindowResize)
  },

  computed: {
    // Elements

    container() {
      return this.$refs.container
    },

    picture() {
      return this.$refs.picture
    },

    pictureBig() {
      return this.$refs['picture-big']
    },

    pictureGif() {
      return this.$refs['picture-gif']
    },

    pictureWrapper() {
      return this.$refs['picture-wrapper']
    },

    pictureSubWrapper() {
      return this.$refs['picture-subwrapper']
    },

    status() {
      return this.preview && this.preview.status ? this.preview.status : 'ready'
    },

    isAvailable() {
      return !['broken', 'processing'].includes(this.status)
    },

    // Utils

    extension() {
      return this.preview ? this.preview.extension : ''
    },

    isGif() {
      return this.extension === 'gif'
    },

    isMovie() {
      return this.extension === 'mp4'
    },

    isPicture() {
      return ['gif', 'png', 'jpg', 'jpeg'].includes(this.extension)
    },

    pictureOriginalPath() {
      if (this.preview && this.isAvailable && this.isPicture) {
        const previewId = this.preview.id
        return `${this.$store.state.login.server}/api/pictures/originals/preview-files/${previewId}.png`
      } else {
        return null
      }
    }
  },

  methods: {
    // Sizing
    getNaturalDimensions() {
      let picture = { naturalWidth: 0, naturalHeight: 0 }
      if (!this.fullScreen && this.picture.naturalWidth && !this.isGif) {
        picture = this.picture
      } else if (
        this.fullScreen &&
        this.pictureBig.naturalWidth &&
        !this.isGif
      ) {
        picture = this.pictureBig
      } else if (this.pictureGif.naturalWidth && this.isGif) {
        picture = this.pictureGif
      }
      return {
        height: picture.naturalHeight,
        width: picture.naturalWidth
      }
    },

    getDimensions() {
      let ratio = 1
      const dimensions = this.getNaturalDimensions()
      if (dimensions.width > 0) ratio = dimensions.height / dimensions.width
      let width = dimensions.width
      if (width > this.container.offsetWidth) {
        width = this.container.offsetWidth
      }
      let height = Math.floor(width * ratio)
      if (height > this.defaultHeight) {
        height = this.defaultHeight
      }
      width = Math.floor(height / ratio)
      return { width, height }
    },

    onWindowResize() {
      const now = new Date().getTime()
      this.lastCall = this.lastCall || 0
      if (now - this.lastCall > 600) {
        this.lastCall = now
        this.$nextTick(this.resetPicture)
        setTimeout(() => {
          this.resetPicture()
        }, 400)
      }
    },

    // Configuration

    endLoading() {
      this.isLoading = false
      this.$nextTick(this.resetPicture)
    },

    resetPicture() {
      const heightValue = this.defaultHeight + 'px'
      this.container.style.height = heightValue
      if (this.pictureWrapper) this.pictureWrapper.style.height = heightValue
      if (this.pictureSubWrapper) {
        this.pictureWrapper.style['max-height'] = heightValue
        this.pictureSubWrapper.style['max-height'] = heightValue
      }
      const dimensions = this.getDimensions()
      const width = dimensions.width
      const height = dimensions.height
      this.picture.style.width = width + 'px'
      this.picture.style.height = height + 'px'
      this.pictureBig.style.width = width + 'px'
      this.pictureBig.style.height = height + 'px'
      this.pictureGif.style.width = width + 'px'
      this.pictureGif.style.height = height + 'px'
      this.picture.width = width
      this.picture.height = height
      this.pictureBig.width = width
      this.pictureBig.height = height
      this.pictureGif.width = width
      this.pictureGif.height = height
      if (this.isPicture) this.$emit('size-changed', dimensions)
    },

    setPicturePath() {
      if (this.isGif && this.isAvailable && this.isPicture) {
        const previewId = this.preview.id
        this.pictureGifPath = `${this.$store.state.login.server}/api/pictures/originals/preview-files/${previewId}.gif`
      } else if (this.preview && this.isAvailable && this.isPicture) {
        const previewId = this.preview.id
        this.picturePath = `${this.$store.state.login.server}/api/pictures/previews/preview-files/${previewId}.png`
      }
      this.setPictureDlPath()
    },

    setPictureDlPath() {
      if (this.preview && this.isAvailable && this.isPicture) {
        const previewId = this.preview.id
        this.pictureDlPath = `${this.$store.state.login.server}/api/pictures/originals/preview-files/${previewId}/download`
      } else {
        this.pictureDlPath = null
      }
    },

    // Loupe

    showLoupe() {
      this.$refs.loupe.style.display = 'block'
    },

    hideLoupe() {
      this.$refs.loupe.style.display = 'none'
    },

    updateLoupePosition(event, canvasDimensions) {
      const w = canvasDimensions.width
      const h = canvasDimensions.height
      const maxWidth = parseInt(w.substring(0, w.length - 2))
      const maxHeight = parseInt(h.substring(0, h.length - 2))
      let x = Math.max(event.pointer.x - 150, 0)
      let y = Math.max(event.pointer.y - 150, 0)
      x = Math.min(x, maxWidth - 300)
      y = Math.min(y, maxHeight - 300)
      this.$refs.loupe.style.left = x + 'px'
      this.$refs.loupe.style.top = y + 'px'

      let zx = Math.max(event.pointer.x, 0)
      let zy = Math.max(event.pointer.y, 0)
      zx = Math.min(zx, maxWidth)
      zy = Math.min(zy, maxHeight)
      const naturalDimensions = this.getNaturalDimensions()
      const ratioW = naturalDimensions.width / maxWidth
      const bgX = Math.min(ratioW * zx - 150, naturalDimensions.width - 300)
      const bgY = Math.min(ratioW * zy - 150, naturalDimensions.height - 300)
      this.$refs.loupe.style['background-position'] = `-${bgX}px -${bgY}px`
    }
  },

  watch: {
    fullScreen() {
      if (this.fullScreen) {
        this.isLoading = true
        this.setPictureDlPath()
        if (this.pictureBig.complete) this.isLoading = false
      } else {
        this.setPicturePath()
      }
    },

    isLoading() {
      if (!this.isLoading) {
        setTimeout(this.resetPicture, 100)
      }
    },

    light() {
      this.onWindowResize()
    },

    isComparing() {
      setTimeout(() => {
        this.resetPicture()
      }, 20)
    },

    preview() {
      this.isLoading = true
      this.setPicturePath()
      this.setPictureDlPath()
      if (this.currentIndex > 1) {
        this.currentIndex = 1
      }
      if (this.fullScreen) {
        if (this.pictureBig.complete) {
          this.resetPicture()
          this.isLoading = false
        }
      } else {
        if (this.picture.complete) {
          this.isLoading = false
        }
        this.$nextTick(this.resetPicture)
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.loading-background {
  width: 100%;
  height: 100%;
  background: black;
  display: flex;
  background: black;
  align-items: center;
  justify-content: center;
}

.picture-player {
  display: flex;
  flex-direction: column;
  align-content: flex-end;
  border-radius: 5px;
  height: 100%;
}

.spinner {
  margin-top: 1em;
  margin-bottom: 1em;
}

.picture-wrapper {
  flex: 1;
  border-radius: 5px;
  display: flex;
  background: black;
  align-items: center;
  justify-content: center;
  text-align: center;
  width: 100%;
  z-index: 300;
  margin: auto;
}

.picture-subwrapper {
  position: relative;
}

.picture-player {
  width: 100%;
  text-align: center;
  background: #36393f;
}

.loupe {
  display: none;
  position: absolute;
  top: 0;
  left: 0;
  height: 300px;
  width: 300px;
  background: white;
  z-index: 3000;
  border-radius: 5px;
  box-shadow: 0 0 8px 4px rgba(0, 0, 0, 0.2);

  img {
    position: relative;
    width: 800px;
  }
}
</style>
