React = require 'react'
ReactDOM = require 'react-dom'
Spinner = React.createFactory(require './spinner')

InputMixin = require '../mixins/input_mixin'

{makeGuid, synthesizeMouseEvent} = require '../utils'
{ENTER} = require '../constants/keyboard'

{div, select, label, option} = React.DOM

###
Select Props

@props.value - REQUIRED - string
  The value of the input
  w/ out this props, the input will not work

@props.options - REQUIRED - array/collection
  An array of objects w/ a value and label property

or
@props.options - REQUIRED - array/collection
  An array of objects w/ any values
@props.selectText - STRING
  text for the default option
@props.labelField - String - REQUIRED w/ arbittrary option array (ie no label/value properties)
  The attribute name from the collection of objects to be used as the select label
@props.valueField - String - REQUIRED w/ arbittrary option array (ie no label/value properties)
  The attribute value from the collection of objects to be used as the select value
@props.returnFullObjects - BOOLEAN - default: no
  Get value will return a full object instead of just the value

@props.onChange - REQUIRED 
  method that will change the value of the input prop
  gets passed a single param that is the new value of the input
  w/ out this method, the input will not update

@props.className - OPTIONAL - string - default 'select-input'
  optional class to be added the select element itself

@props.id - OPTIONAL - string - default null
  optional id to be added the input element itself

@props.wrapperClass - OPTIONAL - string default null
  class to be added to the wrapper div

@props.wrapperLabel - OPTIONAL - default null
  text for wrapping label element

@props.loading - OPTIONAL - Boolean
  indicator to determine that the input is loading a value from the server

@props.tabIndex - OPTIONAL - int - default null
  tab index for the input

@props.onEnterKey/onBlur/onFocus
  optional handlers for various events

@props.disabled - OPTIONAL - Boolean - default no
  disabled state of the input

@props.validation - OPTIONAL - method
  a method that takes the value and returns an arry of validation objects
  always return an empty array for a valid value
  see the validation store for more documentation on validation objects

@props.isInPopover - OPTIONAL - default no
  set this to yes if the form is inside a popover or modal, forces the
  validation to display above the popover/modal layer
  Inconsequential if validation is not being used

@props.delayedActionOnChange - OPTIONAL - Object
  Takes action and interval parameters, will fire the action after the set interval everytime the data changes

@props.openOnMount - boolean -default no
  opens the drop down when it mounts
###

SelectInput2 = React.createClass
  
  displayName: 'SelectInput2'

  mixins: [InputMixin]

  contextTypes:
    clearValidationError: React.PropTypes.func
    addValidationError: React.PropTypes.func
    getValidationStatus: React.PropTypes.func
    toggleValidationError: React.PropTypes.func

  propTypes:
    onChange: React.PropTypes.func.isRequired
    options: React.PropTypes.array.isRequired

  getDefaultProps: -> 
    {
      type: 'text'
      className: 'select-menu'
      id: null
      wrapperClass: null
      wrapperLabel: null
      loading: no
      tabIndex: null
      onKeyDown: null
      onKeyPress: null
      onFocus: null
      onBlur: null
      onKeyUp: null
      onEnterKey: null
      onChange: null
      disabled: no
      validation: off
      isInPopover: no
      delayedActionOnChange: null
      openOnMount: no
      returnFullObjects: no
      valueField: null
      labelField: null
      selectText: null
    }

  render: ->
    {value, options, tabIndex, className, loading, onKeyDown, onKeyPress, onBlur, onFocus, 
    wrapperClass, wrapperLabel, id, disabled, validation, valueField, labelField, returnFullObjects, selectText} = @props
    {valueHasChanged} = @state
    {error, forceShowAllErrors} = @context.getValidationStatus(@inputId)
    {valueHasChanged} = @state
    isValid = not error?

    outerClass = 'field-wrap'
    outerClass += " #{wrapperClass}" if wrapperClass?
    outerClass += ' invalid shrink' if not isValid and (valueHasChanged or forceShowAllErrors)

    inputClass = 'loading-spinner'
    inputClass += " #{className}" if className?

    valueField = valueField or 'value'
    labelField = labelField or 'label' 

    optionEls = (option {
      key: "#{item[valueField]}_#{index}"
      value: item[valueField]
    }, item[labelField] for item, index in options)

    if selectText?
      optionEls.unshift option {
        key: "default"
        value: ''
      }, selectText

    # When returnFullObjects is on, then overwrite the value (which will be ab object), 
    # with it's 'valueField' attribute
    if returnFullObjects and value? then value = value[valueField]


    input = select {
      ref: 'input'
      key: 'selectMenu'
      onChange: @handleChange
      onKeyUp: @handleKeyUp
      value: value or ''
      className
      id
      tabIndex
      onFocus
      onBlur
      onKeyDown
      onKeyPress
      disabled
    }, optionEls

    # Add a wrapper label element if label prop is present
    if wrapperLabel
      input = label {
        key: 'textInputLabel'
      }, [wrapperLabel, input]

    div {
      className: "#{outerClass}"
    }, [
      input
      div({
        key: 'input-spinner'
        className: 'input-spinner'
      }, Spinner {length: 3}) if loading
      div {
        className: 'field-errors-show'
        key: 'textInputErrorsShow'
        ref: 'errorAnchor'
        onMouseOver: @handleErrorMouseOver
        onMouseOut: @handleErrorMouseOut
      }
    ]

  componentDidMount: ->
    if @props.openOnMount
      setTimeout =>
        synthesizeMouseEvent @refs.input, 'mousedown'
      , 15


 

module.exports = SelectInput2
