<template>
  <div class="container">
    <vue-datepicker
      class="date"
      v-model="date"
      valueType="format"
    ></vue-datepicker>
    <vue-timepicker
      class="time"
      :format="timeFormat"
      v-model="time"
    ></vue-timepicker>
    <check-icon class="confirm icon" @click="onWriteActiveImage" />
  </div>
</template>

<script>
import VueTimepicker from 'vue2-timepicker'
import 'vue2-timepicker/dist/VueTimepicker.css'
import VueDatepicker from 'vue2-datepicker'
import 'vue2-datepicker/index.css'
import DatasetService from '@/services/DatasetService'
import CheckIcon from 'icons/Check'

export default {
  name: 'TimeShift',
  components: {
    VueTimepicker,
    VueDatepicker,
    CheckIcon
  },
  props: {
    cameraID: {
      type: String,
      required: true
    },
    imageName: {
      type: String,
      required: true
    }
  },
  data() {
    return {
      timeFormat: 'HH:mm:ss',
      time: {
        HH: '00',
        mm: '00',
        ss: '00'
      },
      date: '2000-01-01'
    }
  },
  computed: {
    imageDateTime() {
      return this.$store.getters.imageDateTime(this.cameraID, this.imageName)
    }
  },
  methods: {
    toString(value) {
      if (value < 10) return '0' + value.toString()
      return value.toString()
    },
    dateToString(date) {
      return (
        this.toString(date.getFullYear()) +
        '-' +
        this.toString(date.getMonth() + 1) +
        '-' +
        this.toString(date.getDate())
      )
    },
    timeToString(date) {
      return (
        this.toString(date.getHours()) +
        ':' +
        this.toString(date.getMinutes()) +
        ':' +
        this.toString(date.getSeconds())
      )
    },
    timeDateToString(date) {
      return this.dateToString(date) + 'T' + this.timeToString(date)
    },
    onReadActiveImage() {
      const timeAndDate = this.imageDateTime
      if (timeAndDate.length == 0) return
      const date = new Date(timeAndDate)
      this.time.HH = this.toString(date.getHours())
      this.time.mm = this.toString(date.getMinutes())
      this.time.ss = this.toString(date.getSeconds())
      this.date = this.dateToString(date)
    },
    onWriteActiveImage() {
      const oldTimeDate = new Date(this.imageDateTime)
      if (oldTimeDate.length == 0) return
      const newTimeDate = new Date(
        this.date + 'T' + this.time.HH + ':' + this.time.mm + ':' + this.time.ss
      )
      const dt = newTimeDate.getTime() - oldTimeDate.getTime()
      DatasetService.multipostBegin()
      if (dt != 0) {
        this.shiftDateTimeOfCameraImages(this.cameraID, dt)
        this.updateTimeSpan()
      }
      const [imageOrder, imageLookup] = this.buildChronologicalOrderOfImages()
      this.updateReciprocalImages(this.cameraID, imageOrder, imageLookup)
      DatasetService.multipostEnd()
    },
    shiftDateTimeOfCameraImages(camID, dt) {
      for (const [imageName, imageProps] of Object.entries(
        this.$store.getters.chartData(camID)
      )) {
        const newImageDateTimeString = this.timeDateToString(
          new Date(Date.parse(imageProps.dateTime) + dt)
        )
        this.$store.dispatch('setImageDateTime', {
          cameraID: camID,
          imageName,
          dateTimeString: newImageDateTimeString
        })
      }
    },
    updateTimeSpan() {
      var minTimestamp
      var maxTimestamp
      for (const camID of this.$store.getters.cameraIDs) {
        for (const [imageName, imageProps] of Object.entries(
          this.$store.getters.chartData(camID)
        )) {
          const timestamp = Date.parse(imageProps.dateTime)
          if (typeof minTimestamp == 'undefined' || timestamp < minTimestamp)
            minTimestamp = timestamp
          if (typeof maxTimestamp == 'undefined' || maxTimestamp < timestamp)
            maxTimestamp = timestamp
        }
      }
      const minDateTime = this.timeDateToString(new Date(minTimestamp))
      const maxDateTime = this.timeDateToString(new Date(maxTimestamp))
      this.$store.dispatch('setTimeSpan', { minDateTime, maxDateTime })
    },
    updateReciprocalImages(shiftedCameraID, imageOrder, imageLookup) {
      for (const cameraID of this.$store.getters.cameraIDs) {
        for (const [imageName, imageProps] of Object.entries(
          this.$store.getters.chartData(cameraID)
        )) {
          for (const [recipCameraID, recipImageName] of Object.entries(
            imageProps.reciprocalImageName
          )) {
            if (
              cameraID == shiftedCameraID ||
              recipCameraID == shiftedCameraID
            ) {
              const closestRecipImageName = this.findClosestImageName(
                imageProps.dateTime,
                imageLookup[recipCameraID][recipImageName],
                this.$store.getters.chartData(recipCameraID),
                imageOrder[recipCameraID]
              )
              if (closestRecipImageName != recipImageName)
                this.$store.dispatch('setReciprocalImage', {
                  cameraID,
                  imageName,
                  recipCameraID,
                  closestRecipImageName
                })
            }
          }
        }
      }
    },
    findClosestImageName(
      refImageDateTimeString,
      imageIdx,
      imageInfos,
      imageOrder
    ) {
      const referenceDateTime = Date.parse(refImageDateTimeString)
      let bestIdx = imageIdx
      let bestDist = Math.abs(
        Date.parse(imageInfos[imageOrder[bestIdx]].dateTime) - referenceDateTime
      )
      while (bestIdx > 0) {
        const dist = Math.abs(
          Date.parse(imageInfos[imageOrder[bestIdx - 1]].dateTime) -
            referenceDateTime
        )
        if (dist >= bestDist) break
        bestIdx -= 1
        bestDist = dist
      }
      if (bestIdx == imageIdx)
        while (bestIdx + 1 < imageOrder.length) {
          const dist = Math.abs(
            Date.parse(imageInfos[imageOrder[bestIdx + 1]].dateTime) -
              referenceDateTime
          )
          if (dist >= bestDist) break
          bestIdx += 1
          bestDist = dist
        }
      return imageOrder[bestIdx]
    },
    buildChronologicalOrderOfImages() {
      const imageOrder = {}
      const imageLookup = {}
      for (const cameraID of this.$store.getters.cameraIDs) {
        const chronology = this.$store.getters.getCameraImagesChronology(
          cameraID
        )
        imageOrder[cameraID] = chronology.order
        imageLookup[cameraID] = chronology.lookup
      }
      return [imageOrder, imageLookup]
    }
  },
  watch: {
    cameraID() {
      this.onReadActiveImage()
    },
    imageName() {
      this.onReadActiveImage()
    }
  },
  mounted() {
    this.onReadActiveImage()
  }
}
</script>

<style lang="scss" scoped>
.container {
  display: grid;
  grid-template-rows: auto auto;
  grid-template-columns: auto 30px;
  grid-template-areas:
    'date .'
    'time confirm';
}

.date {
  grid-area: date;
  width: auto;
}

.time {
  grid-area: time;
}

.confirm {
  grid-area: confirm;
  align-self: center;
  justify-self: center;
}
</style>
