<template>
  <div class="annotated-image" v-on="events">
    <img alt="media" ref="image" draggable="false"
         :src="mediaUrl" :srcset="mediaUrlSet" :sizes="mediaUrlSizes"/>

    <div style="position: absolute; top: 0.5rem; left: 0.5rem">{{ data }}</div>

    <annotation-box v-if="current"
                    :image="image"
                    :position="current"
                    :immutable="true"/>

    <annotation-box v-for="(result, index) in predictions"
                    type="server"
                    :key="index"
                    :image="image"
                    :position="result"
                    :socket="socket"
                    :immutable="false"
                    :box-url="mediaUrl + '/' + result.id"/>
  </div>
</template>

<script>
import AnnotationBox from "@/components/media/annotation-box";

export default {
  name: "annotated-image",
  components: {AnnotationBox},
  props: ['project', 'data', 'socket'],
  mounted: function () {
    window.addEventListener("resize", this.resizeEvent);

    if (this.$refs.image.complete)
      this.resizeEvent();
    else
      this.$refs.image.addEventListener('load', this.resizeEvent);
  },
  destroyed() {
    window.removeEventListener("resize", this.resizeEvent);
  },
  watch: {
    data: function () {
      this.current = false;
      this.resizeEvent();
    }
  },
  data: function () {
    return {
      sizes: [600, 800, 1200, 1600, 2000, 3000],
      image: {
        left: 0,
        top: 0,
        width: 0,
        height: 0
      },
      start: false,
      current: false
    }
  },
  computed: {
    mediaUrl: function () {
      return this.socket.media(this.project.id, this.data.id);
    },
    mediaUrlSet: function () {
      return this.sizes.map(e => this.mediaUrl + '/' + e + ' ' + e + 'w').join(',');
    },
    mediaUrlSizes: function () {
      return this.sizes.map(e => '(max-width: ' + e + 'px) ' + e + 'px').join(',');
    },
    predictions: function () {
      return Object.keys(this.data.predictionResults).map(k => this.data.predictionResults[k]);
    },
    events: function () {
      return {
        'touchstart': this.press,
        'touchmove': this.track,
        'touchend': this.release,
        'mousedown': this.press,
        'mousemove': this.track,
        'mouseup': this.release,
        'dragstart': e => e.stopPropagation()
      }
    }
  },
  methods: {
    resizeEvent: function () {
      const element = this.$refs.image.getBoundingClientRect();
      const parent = this.$refs.image.parentElement.getBoundingClientRect();

      this.image.left = element.x - parent.x;
      this.image.top = element.y - parent.y;
      this.image.width = element.width;
      this.image.height = element.height;
    },
    get: function (event) {
      if ('clientX' in event)
        return event;
      if ('touches' in event && event.touches.length > 0)
        return event.touches[0];
      if ('changedTouches' in event && event.changedTouches.length > 0)
        return event.changedTouches[0];
    },
    getX: function (event) {
      const bcr = this.$refs.image.getBoundingClientRect();
      return (this.get(event).clientX - bcr.left) / bcr.width;
    },
    getY: function (event) {
      const bcr = this.$refs.image.getBoundingClientRect();
      return (this.get(event).clientY - bcr.top) / bcr.height;
    },
    buildRectangle: function (x1, y1, x2, y2) {
      const lx = Math.max(Math.min(x1, x2), 0);
      const hx = Math.min(Math.max(x1, x2), 1);
      const ly = Math.max(Math.min(y1, y2), 0);
      const hy = Math.min(Math.max(y1, y2), 1);

      return {
        x: lx,
        y: ly,
        w: hx - lx,
        h: hy - ly
      }
    },
    press: function (event) {
      this.start = {
        x: this.getX(event),
        y: this.getY(event)
      };
    },
    track: function (event) {
      if (this.start) {
        const x = this.getX(event);
        const y = this.getY(event);

        this.current = this.buildRectangle(this.start.x, this.start.y, x, y);
      }
    },
    release: function () {
      if (this.start) {
        this.socket.post(this.mediaUrl, this.current);
        this.start = false;
        this.current = false;
      }
    }
  }
}
</script>

<style scoped>
img {
  max-width: 100%;
  max-height: 100%;
}
</style>