React = require 'react'
require 'classlist-polyfill'
ReactDatepicker = React.createFactory(require 'react-datepicker')
SelectInput = React.createFactory(require './select_input_2')
moment = require 'moment'


{div, span, input} = React.DOM


DatePicker = React.createClass

  displayName: 'DatePicker'

  propTypes:
    placeholderText: React.PropTypes.oneOfType [
      React.PropTypes.string
      React.PropTypes.number
    ]
    dateFormat: React.PropTypes.string
    className: React.PropTypes.string
    minDate: React.PropTypes.object
    maxDate: React.PropTypes.object
    onChange: React.PropTypes.func.isRequired
    tabIndex: React.PropTypes.number
    selected: React.PropTypes.oneOfType [
      React.PropTypes.string
      React.PropTypes.object
    ]

  getDefaultProps: ->
    placeholderText: 'Select a date'
    dateFormat: 'MM/DD/YYYY'
    className: null
    includeTime: no # yes to include time selection
    returnDateString: null # pass a date format string to get that format from the getValue method

  getInitialState: ->
    {selected} = @props
    @getDateState selected
  
  getDateState: (selected = moment()) ->
    {
      selected: moment(selected.format('YYYYMMDD'), 'YYYYMMDD')
      inputDate: ''
      hours: selected.format('h')
      minutes: selected.format('mm')
      ampm: selected.format('a')
    }

  componentWillMount: ->
    {includeTime} = @props
    
    return unless includeTime
    
    @hoursOptions = [{
      label: '12'
      value: '12'
    }]

    @hoursOptions.push(
      label: hour
      value: hour
    ) for hour in [1..11]

    @minuteOptions = []
    for minute in [0..59]
      if minute < 10 then minute = "0#{minute}"
      @minuteOptions.push(
        label: minute
        value: minute
      )

    @ampmOptions = [
      {
        label: 'am'
        value: 'am'
      }
      {
        label: 'pm'
        value: 'pm'
      }
    ]

  componentWillReceiveProps: (nextProps) ->
    {selected} = @props
    
    if selected?.format('YYYYMMDDhmma') isnt nextProps.selected?.format('YYYYMMDDhmma')
      @setState(@getDateState(nextProps.selected))
    

  render: ->
    {placeholderText, className, dateFormat, minDate, maxDate, onChange, tabIndex, includeTime} = @props
    {selected, inputDate, hours, minutes, ampm} = @state

    if selected
      # Allow the value to be set from either a Moment object or a string
      switch typeof selected
        when 'string'
          value = moment(selected).format(dateFormat)
          selected = moment(selected, dateFormat)
        when 'object'
          value = selected.format(dateFormat)

    mainClass = 'datepicker-wrapper'
    mainClass += ' include-time' if includeTime
    mainClass += " #{className}" if className?

    div {
      className: mainClass
    }, [
      input {
        key: 'input'
        ref: 'input'
        type: 'text'
        placeholder: placeholderText
        value: inputDate or value
        onChange: @handleChange
        onKeyDown: @handleKeyDown
        onBlur: @handleBlur
        onFocus: @handleFocus
        tabIndex: tabIndex
      }
      ReactDatepicker {
        key: 'datepicker'
        ref: 'datepicker'
        selected: selected
        onChange: @handleDateChange
        dateFormat: dateFormat
        minDate: minDate
        maxDate: maxDate
      }
      div {
        key: 'time'
        className: 'time-wrapper'
      }, [
        SelectInput {
          key: 'hours'
          ref: 'hours'
          value: hours
          className: 'time-sel'
          options: @hoursOptions
          onChange: @handleChange
        }
        span {key: 'colon', className: 'colon'}, ':'
        SelectInput {
          key: 'minutes'
          ref: 'minutes'
          value: minutes
          className: 'time-sel'
          options: @minuteOptions
          onChange: @handleChange
        }
        SelectInput {
          key: 'ampm'
          ref: 'ampm'
          value: ampm
          className: 'time-sel ampm'
          options: @ampmOptions
          onChange: @handleChange
        }
      ] if includeTime
    ]

  hideCalendar: ->
    # Hide the datepicker popup
    @refs.datepicker.setOpen no

  handleFocus: ->
    # Show the datepicker popup
    @refs.datepicker.handleFocus()

  handleChange: (cb, blur) ->
    {includeTime, onChange} = @props
    
    setData =
      inputDate: @refs.input.value

    if includeTime
      setData.hours = @refs.hours.getValue()
      setData.minutes = @refs.minutes.getValue()
      setData.ampm = @refs.ampm.getValue()

    @setState setData, ->
      cb?(null, blur)
      onChange?()

  handleBlur: ->
    @handleChange(@handleKeyDown, true)

  handleKeyDown: (e, blur) ->
    {value} = @refs.input
    {minDate, maxDate, dateFormat} = @props
    inputDate = moment(value, dateFormat)
    unixInputDate = inputDate.unix()
    state = {}

    # Validate the value and enter key was pressed
    if inputDate.isValid() and (e?.key in ['Enter', 'Tab'] or not e?)
      # Check to make sure the date is in the valid range
      if minDate? and unixInputDate <= minDate.unix()
        inputAdjusted = true
        inputDate = minDate
      if maxDate? and unixInputDate >= maxDate.unix()
        inputAdjusted = true
        inputDate = maxDate

      if inputAdjusted then state.inputDate = inputDate.format(dateFormat)
      state.selected = inputDate

      @setState state
      , ->
        @props.onChange?()
        @hideCalendar() unless blur

  handleDateChange: (date) ->
    @setState
      selected: date
      inputDate: ''
    , -> 
      @props.onChange?()

  getValue: ->
    {returnDateString, includeTime} = @props
    {selected} = @state

    if includeTime
      {hours, minutes, ampm} = @state
      dateString = selected.format 'YYYYMMDD'
      dateString += "#{hours}:#{minutes}#{ampm}"
      selected = moment(dateString, 'YYYYMMDDh:mma')

    if returnDateString? then selected.format(returnDateString) else selected
    


module.exports = DatePicker
