import DatasetService from '@/services/DatasetService'

export default {
  stickIDs: state => {
    return Object.keys(state.sticks)
  },
  cameraIDs: state => {
    return Object.keys(state.cameras)
  },
  activeStick: state => {
    return state.activePoint.stickID
  },
  activeCamera: state => {
    return state.activePoint.cameraID
  },
  activeImageName: state => cameraID => {
    if (state.activePoint.imageNames) {
      return state.activePoint.imageNames[cameraID]
    }
    return null
  },
  // Return set of cameras that can see the given stick
  cameraByStick: state => stickID => {
    if (state.sticks[stickID] === undefined) {
      return []
    }
    return Object.keys(state.sticks[stickID].labels)
  },
  primaryCamera: state => stickID => {
    return state.sticks[stickID].primaryCamera
  },
  stickViewLabel: state => (stickID, cameraID) => {
    if (!stickID || !cameraID) {
      return null
    }
    return state.sticks[stickID].labels[cameraID]
  },
  stickLengthCm: state => stickID => {
    return state.sticks[stickID].lengthCm
  },
  maxStickLengthCm: (state, getters) => {
    let result = 0
    if (!getters.stickIDs) {
      return 0
    }
    for (const stickID of getters.stickIDs) {
      const length = getters.stickLengthCm(stickID)
      if (length > result) {
        result = length
      }
    }
    return result
  },
  stickStatusGUI: state => stickID => {
    return state.sticks[stickID].statusGUI
  },
  cameraStatusGUI: state => cameraID => {
    return state.cameras[cameraID].statusGUI
  },
  showDaysGradient: state => {
    return state.controls.showDaysGradient
  },
  showImageDialog: state => {
    return state.controls.showImageDialog
  },
  showFilters: state => {
    return state.controls.showFilters
  },
  showLegend: state => {
    return state.controls.showLegend
  },
  showHelpDialog: state => {
    return state.controls.showHelpDialog
  },
  timespanStart: state => {
    return state.timespan.start
  },
  timespanEnd: state => {
    return state.timespan.end
  },
  maxSnowHeight: state => {
    return state.maxSnowHeight
  },
  zoomState: state => {
    return state.zoomState
  },
  chartData: state => cameraID => {
    return state.data[cameraID]
  },
  sunImage: state => {
    return state.sunImage
  },
  sticksByImageName: state => (cameraID, imageName) => {
    return state.data[cameraID][imageName].sticks
  },
  imageURL: () => (cameraID, imageName) => {
    return DatasetService.getImageURL(cameraID, imageName)
  },
  imageDateTime: state => (cameraID, imageName) => {
    return state.data[cameraID][imageName].dateTime
  },
  sticksNotVisible: state => (cameraID, imageName) => {
    const info = state.data[cameraID][imageName]
    var result = []
    for (const key in info.sticks) {
      if (!info.sticks[key].visible) {
        result.push(key)
      }
    }
    return result
  },
  sticksVisible: state => (cameraID, imageName) => {
    const info = state.data[cameraID][imageName]
    var result = []
    for (const key in info.sticks) {
      if (info.sticks[key].visible) {
        result.push(key)
      }
    }
    return result
  },
  imageConditions: state => (cameraID, imageName) => {
    const info = state.data[cameraID][imageName]
    return {
      processedState: info.processedState,
      weatherConditions: info.weatherConditions,
      isDay: info.isDay
    }
  },
  snowHeight: state => (cameraID, stickID, imageName) => {
    return state.data[cameraID][imageName].sticks[stickID].snowHeight
  },
  stickVisible: state => (cameraID, stickID, imageName) => {
    return state.data[cameraID][imageName].sticks[stickID].visible
  },
  flagImageApprovedByUser: state => (cameraID, imageName) => {
    return state.data[cameraID][imageName].approvedByUser
  },
  flagImageDiscardedByUser: state => (cameraID, imageName) => {
    return state.data[cameraID][imageName].discardedByUser
  },
  flagImageUsedForTraining: state => (cameraID, imageName) => {
    return state.data[cameraID][imageName].usedForTraining
  },
  flagStickCorrectedByUser: state => (cameraID, imageName, stickID) => {
    return state.data[cameraID][imageName].sticks[stickID].correctedByUser
  },
  flagStickDiscardedByUser: state => (cameraID, imageName, stickID) => {
    return state.data[cameraID][imageName].sticks[stickID].discardedByUser
  },
  flagStickCreatedByUser: state => (cameraID, imageName, stickID) => {
    return state.data[cameraID][imageName].sticks[stickID].createdByUser
  },

  previousImageName: state => (cameraID, imageName) => {
    // Get closest previous image from the input image.
    // Useful when implementing keyboard navigation between images.
    var prevImage = null
    var prevDate = 0
    const originalDate = new Date(
      state.data[cameraID][imageName].dateTime
    ).getTime()
    for (const name in state.data[cameraID]) {
      const testDate = new Date(state.data[cameraID][name].dateTime).getTime()
      if (testDate < originalDate && testDate > prevDate) {
        prevDate = testDate
        prevImage = name
      }
    }
    return prevImage
  },
  nextImageName: state => (cameraID, imageName) => {
    // Get closest next image from the input image.
    // Useful when implementing keyboard navigation between images.
    var nextImage = null
    var nextDate = new Date().getTime()
    const originalDate = new Date(
      state.data[cameraID][imageName].dateTime
    ).getTime()
    for (const name in state.data[cameraID]) {
      const testDate = new Date(state.data[cameraID][name].dateTime).getTime()
      if (testDate > originalDate && testDate < nextDate) {
        nextDate = testDate
        nextImage = name
      }
    }
    return nextImage
  },
  closeImageNames: state => (cameraID, imageName, timeWindow) => {
    // Get close imageNames from the input imageName, including the input imageName.
    // The whole searched area is 2 * timeWindow, with the input imageName in the middle.

    timeWindow = 3600 * 1000 * timeWindow // converted from hours to milliseconds
    const camera = state.data[cameraID]
    const chronology = state.chronology[cameraID]
    const midTimestamp = new Date(camera[imageName].dateTime).getTime()

    let low = chronology.lookup[imageName]
    for (; low > 0; --low) {
      const currentImageName = chronology.order[low - 1]
      const currentImage = camera[currentImageName]
      const timestamp = new Date(currentImage.dateTime).getTime()
      const deltaTime = Math.abs(midTimestamp - timestamp)
      if (deltaTime > timeWindow) {
        break
      }
    }

    let high = chronology.lookup[imageName]
    for (; high + 1 < chronology.order.length; ++high) {
      const currentImageName = chronology.order[high + 1]
      const currentImage = camera[currentImageName]
      const timestamp = new Date(currentImage.dateTime).getTime()
      const deltaTime = Math.abs(midTimestamp - timestamp)
      if (deltaTime > timeWindow) {
        break
      }
    }

    let result = []

    for (let i = low; i <= high; ++i) {
      const currentImageName = chronology.order[i]
      result.push(currentImageName)
    }

    return result
  },

  pendingPostRequestsCount: state => {
    return state.server.numPendingPostRequests
  },
  hasUncommitedChanges: state => {
    return state.server.hasPendingChanges
  },
  filters: state => {
    return state.filters
  },
  isFilteredOut: state => (imageProps, stickID) => {
    const filters = state.filters
    if (
      filters.imageProcessed != 2 &&
      filters.imageProcessed != imageProps.processedState
    )
      return true

    if (filters.isDay != 2 && filters.isDay != (imageProps.isDay ? 1 : 0))
      return true
    if (
      filters.snowDetected != 2 &&
      filters.snowDetected != imageProps.weatherConditions
    )
      return true

    // Stick is not found.
    const stick = imageProps.sticks[stickID]
    if (
      filters.stickFound !== 2 &&
      filters.stickFound !== (stick.visible ? 1 : 0)
    ) {
      return true
    }

    if (
      filters.imageApproved != 2 &&
      filters.imageApproved != (imageProps.approvedByUser ? 1 : 0)
    )
      return true
    if (
      filters.imageDiscarded != 2 &&
      filters.imageDiscarded != (imageProps.discardedByUser ? 1 : 0)
    )
      return true
    if (
      filters.imageUsedForSvmTraining != 2 &&
      filters.imageUsedForSvmTraining != (imageProps.usedForTraining ? 1 : 0)
    )
      return true
    const sticksIDs =
      typeof stickID == 'undefined' ? Object.keys(imageProps.sticks) : [stickID]
    let hasPassingStick = false
    for (const id of sticksIDs) {
      const stick = imageProps.sticks[id]
      if (
        stick.snowHeight < filters.minSnowHeight ||
        filters.maxSnowHeight < stick.snowHeight
      )
        continue
      if (
        filters.imageSticksEdited != 2 &&
        filters.imageSticksEdited != (stick.correctedByUser ? 1 : 0) &&
        filters.imageSticksEdited != (stick.discardedByUser ? 1 : 0) &&
        filters.imageSticksEdited != (stick.createdByUser ? 1 : 0)
      ) {
        continue
      }
      hasPassingStick = true
      break
    }
    if (!hasPassingStick) return true

    return false
  },
  getCameraImagesChronology: state => cameraID => {
    return state.chronology[cameraID]
  },
  getSnowHeightAverageTimeWindow: state => {
    // In hours
    return state.snowHeightAverageTimeWindow
  },
  getSnowHightAverage: state => (cameraID, imageName, stickID) => {
    // In hours
    return state.data[cameraID][imageName].sticks[stickID].snowHeightAverage
  },

  // --- Stick statistics ---
  statsManuallyEdited: state => (cameraID, stickID) => {
    let result = 0
    if (!state.chronology[cameraID]) {
      return result
    }
    for (const imageName of state.chronology[cameraID].order) {
      const stick = state.data[cameraID][imageName].sticks[stickID]
      const image = state.data[cameraID][imageName]
      if (stick.correctedByUser || image.approvedByUser) {
        result += 1
      }
    }
    return result
  },
  statsDiscarded: state => (cameraID, stickID) => {
    let result = 0
    if (!state.chronology[cameraID]) {
      return result
    }
    for (const imageName of state.chronology[cameraID].order) {
      const stick = state.data[cameraID][imageName].sticks[stickID]
      const image = state.data[cameraID][imageName]
      if (image.discardedByUser || stick.discardedByUser) {
        result += 1
      }
    }
    return result
  },
  statsNotFound: state => (cameraID, stickID) => {
    let result = 0
    if (!state.chronology[cameraID]) {
      return result
    }
    for (const imageName of state.chronology[cameraID].order) {
      const stick = state.data[cameraID][imageName].sticks[stickID]
      const image = state.data[cameraID][imageName]
      if (
        !stick.visible &&
        image.weatherConditions !== 0 &&
        !image.approvedByUser &&
        !stick.correctedByUser
      ) {
        result += 1
      }
    }
    return result
  },
  statsNoSnow: state => cameraID => {
    let result = 0
    if (!state.chronology[cameraID]) {
      return result
    }
    for (const imageName of state.chronology[cameraID].order) {
      const image = state.data[cameraID][imageName]
      if (image.weatherConditions === 0 && !image.approvedByUser) {
        result += 1
      }
    }
    return result
  },
  statsAllPoints: state => cameraID => {
    if (!state.chronology[cameraID]) {
      return 0
    }
    return state.chronology[cameraID].order.length
  }
  // ---
}
