import DateInput from './DateInput' import TimeInput from './TimeInput' import DateMenu from './DateMenu' import TimeMenu from './TimeMenu' import supportDom from '../decorators/supportDom' import { DEFAULT_TIMEZONE } from '../consts' import {

dateToTimestamp,
noop,
parse,
set,
timestampToDate,
toDate

} from '../utils'

@supportDom export default class Datepicker {

constructor(dom, timestamp, options = {}) {
  this.dom = dom
  this.options = options
  this.options.change = options.change || noop
  this.tz = options.tz || DEFAULT_TIMEZONE

  this.date = (timestamp === null) ? null : timestampToDate(timestamp)
  this.menuDate = (timestamp === null) ? toDate(new Date()) : toDate(this.date)
  this.focused = false
  this.nextDate = null
  this.backdropMode = options.backdropMode || 'auto'
  this.init()
}

init() {
  const { dom } = this
  this.dateInput = new DateInput(
    dom.querySelector('[data-date]'),
    this.date,
    this.options
  )
  this.dateMenu = new DateMenu({
    date: this.menuDate,
    options: Object.assign({}, this.options, { useSingleMenu: true })
  })

  const timeInput = dom.querySelector('[data-time]')
  if (timeInput) {
    this.timeInput = new TimeInput(
      timeInput,
      this.date,
      this.options
    )
    this.timeMenu = new TimeMenu()
  }
  this.addEvents()
}

clearInputStatus() {
  this.dateInput.clearStatus()
  this.timeInput && this.timeInput.clearStatus()
}

handleDateInputFocus() {
  this.focused = true
  this.clearInputStatus()
  this.dateInput.setActive(true)

  this.dateMenu.setDate({
    date: this.menuDate,
    startDate: this.date
  })

  this.dateMenu.show(this.dom)
  this.timeMenu && this.timeMenu.hide()
}

setTimestamp(timestamp) {
  return this.setDate(timestampToDate(timestamp))
}

setDate(date) {
  this.date = date
  this.dateInput.setDate(date)
  this.dateMenu.setDate({ startDate: date })
}

handleDateInputKeyUp(event) {
  const { date, dateInput } = this
  const { value } = event.target

  if ((! dateInput.required) && (value === '')) {
    this.date = null
    this.nextDate = null
    return
  }

  const res = parse(value, dateInput.datePattern, date || new Date())

  this.nextDate = null
  if (res.toString() === 'Invalid Date') {
    return dateInput.setDanger(true)
  }
  dateInput.setDanger(false)
  this.nextDate = res
}

clearBlurTimer() {
  if (this._blurTimer) {
    clearTimeout(this._blurTimer)
    this._blurTimer = null
  }
}

handleDateInputBlur() {
  const { nextDate, date, dateInput } = this

  if ((date === null) && (nextDate === null)) {
    dateInput.setDate(null)
    this.timeInput && this.timeInput.setDate(null)
    this._blurTimer = setTimeout(() => this.emitChange(), 50)
  }
  else if (nextDate) {
    this.date = nextDate
    this.menuDate = nextDate
    dateInput.setDate(nextDate)
    this.nextDate = null
    this.emitChange()
  }
  else {
    dateInput.setDate(date)
  }
}

handleTimeInputFocus() {
  const { timeInput } = this
  this.focused = true
  this.clearInputStatus()
  timeInput.setActive(true)
  this.dateMenu.hide()
  this.timeMenu.show({ src: this.dom, date: timeInput.date })
}

handleTimeInputKeyUp(event) {
  const { date, timeInput } = this
  const { value } = event.target

  if ((! timeInput.required) && (value === '')) {
    this.nextDate = null
    return
  }
  const res = parse(event.target.value, timeInput.timePattern, date)
  this.nextDate = null

  if (res.toString() === 'Invalid Date') {
    return timeInput.setDanger(true)
  }
  timeInput.setDanger(false)
  this.nextDate = res
}

handleTimeInputBlur() {
  const { nextDate, date, timeInput } = this

  if (nextDate) {
    this.date = nextDate
    timeInput.setDate(nextDate)
    this.nextDate = null
  }
  else if (date) {
    timeInput.setDate(date)
  }
}

addDateInputEvents() {
  this.dateInput.on('focus', () => this.handleDateInputFocus())
  this.dateInput.on('keyup', event => this.handleDateInputKeyUp(event))
  this.dateInput.on('blur', () => this.handleDateInputBlur())
}

addTimeInputEvents() {
  this.timeInput.on('focus', () => this.handleTimeInputFocus())
  this.timeInput.on('keyup', event => this.handleTimeInputKeyUp(event))
  this.timeInput.on('blur', () => this.handleTimeInputBlur())
}

emitChange() {
  const { date } = this
  this.options.change({
    date,
    timestamp: dateToTimestamp(date)
  })
}

hide() {
  const { timeMenu } = this
  this.focused = false
  this.clearInputStatus()
  this.dateMenu.hide()
  timeMenu && timeMenu.hide()
}

addEvents() {

  this.addDateInputEvents()

  this.dateMenu.on('td-click', (event, res) => {
    event.stopPropagation()
    event.preventDefault()

    this.clearBlurTimer()

    const { year, month, date } = res
    this.date = set(this.date || new Date(), { year, month, date })
    this.dateInput.setDate(this.date)
    this.dateMenu.setDate({ startDate: this.date })
    this.dateInput.setActive(false)
    this.dateMenu.hide()
    this.emitChange()
  })

  if (this.timeInput) {
    this.addTimeInputEvents()

    this.timeMenu.on('click', (event, res) => {
      if (this.date === null) {
        this.date = set(new Date(), { hours: res.hour, minutes: res.minute })
        this.dateInput.setDate(this.date)
      }
      else {
        this.date = set(this.date, { hours: res.hour, minutes: res.minute })
      }
      this.timeInput.setDate(this.date)
      this.timeMenu.hide()
      this.clearInputStatus()
      this.emitChange()
    })
  }

  this.addEvent(document, 'click', event => {
    const { dom, dateMenu, timeMenu } = this
    const { target } = event
    const dateMenuDom = dateMenu.dom
    const timeMenuDom = timeMenu ? timeMenu.dom : null

    if (this.focused) {
      this.focused = false
      return
    }
    if (this.backdropMode === 'manual') {
      return
    }
    if ((! dateMenu.isVisible) && (timeMenu && (! timeMenu.isVisible))) {
      return
    }
    if (dom.contains(target)) {
      return
    }
    if (dateMenuDom.contains(target)) {
      return
    }
    if (dateMenuDom === target) {
      return
    }
    if (timeMenuDom && timeMenuDom.contains(target)) {
      return
    }
    if (timeMenuDom && (timeMenuDom === target)) {
      return
    }
    this.hide()
  })
}

destroy() {
  this.dateInput.destroy()
  this.dateMenu.destroy()
  this.timeInput && this.timeInput.destroy()
  this.timeMenu && this.timeMenu.destroy()
}

}