React = require 'react'
createClass = require 'create-react-class'
PropTypes = require 'prop-types'
Spinner = React.createFactory(require './spinner')

InputMixin = require '../mixins/input_mixin'

{div, button, label, input} = React.DOM

###&

@general
  TextInput2 is the updated version of TextInput. This component uses the validation store.

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

@props.onChange - REQUIRED - [Function]
  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 'text-input'
  optional class to be added the input element itself

@props.inputTextClass - OPTIONAL - [String] 
  optional class to be added the input element itself when using the gridInputForm

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

@props.placeholder - OPTIONAL - [String] - default null
  optional placeholder text for the input

@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.showClear - OPTIONAL - [Boolean]
  indicator to determine whether or not to show the clear "X" button 

@props.tabIndex - OPTIONAL - [Number] - default null
  tab index for the input

@props.maxLength - OPTIONAL - [Number] - default null
  max characters that can be entered in the input

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

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

@props.validation - OPTIONAL - [Function]
  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 - [Boolean] - 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.textTransform - OPTIONAL - [Function] 
  runs the value through a transform method that will change the input before returning via getValue()

@props.focusOnMount - OPTIONAL - [Boolean] 
  Focuses the input once mounted

@props.tabId - OPTIONAL - [String] 
  If this input is within a tab, this id will be used for validation errors in the store
&###


TextInput2 = createClass
  
  displayName: 'TextInput2'

  mixins: [InputMixin]

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

  propTypes:
    type: PropTypes.string
    className: PropTypes.string
    textTransform: PropTypes.func
    focusOnMount: PropTypes.bool
    delayedActionOnChange: PropTypes.object
    tabIndex: PropTypes.number
    maxLength: PropTypes.number
    disabled: PropTypes.bool
    onChange: PropTypes.func
    onInput: PropTypes.func
    onKeyDown: PropTypes.func
    onKeyUp: PropTypes.func
    onKeyPress: PropTypes.func
    style: PropTypes.object
    autoComplete: PropTypes.oneOfType [
      PropTypes.string
      PropTypes.bool
    ]
    placeholder: PropTypes.oneOfType [
      PropTypes.string
      PropTypes.number
    ]
    value: PropTypes.oneOfType([
      PropTypes.string
      PropTypes.number
    ]).isRequired
    id: PropTypes.oneOfType [
      PropTypes.string
      PropTypes.number
    ]
    tabId: PropTypes.oneOfType([
      PropTypes.string
      PropTypes.number
    ])

  getDefaultProps: -> 
    type: 'text'
    className: 'text-input'
    id: null
    placeholder: ''
    wrapperClass: null
    wrapperLabel: null
    loading: no
    showClear: no
    tabIndex: null
    maxLength: null
    onKeyDown: null
    onKeyPress: null
    onFocus: null
    onBlur: null
    onKeyUp: null
    onEnterKey: null
    onChange: null
    onInput: null
    disabled: no
    autoComplete: no
    validation: off
    isInPopover: no
    delayedActionOnChange: null
    spellCheck: false
    style: null
    focusOnMount: false

  render: ->
    {value, placeholder, tabIndex, className, inputTextClass, maxLength, loading, type, showClear, onInput, onKeyDown, onKeyPress, onBlur, onFocus, wrapperClass, wrapperLabel, id, disabled, validation, autoComplete, spellCheck, style, focusOnMount} = @props
    {error, forceShowAllErrors} = @context.getValidationStatus(@inputId)
    {valueHasChanged} = @state
    isValid = not error?

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

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

    errorButtonClass = 'field-errors-show'
    errorButtonClass += ' is-hidden' if loading

    # Autocomplete
    autoComplete = switch typeof autoComplete 
      when 'string' then autoComplete
      when 'boolean'
        if autoComplete then 'on' else 'off'

    textInput = input {
      key: 'textInput'
      ref: 'input'
      id: id
      className: inputClass
      type: type
      value: value
      placeholder: placeholder
      maxLength: maxLength
      disabled: disabled
      tabIndex: tabIndex
      onChange: @handleChange unless onInput?
      onInput: @handleChange if onInput?
      onKeyUp: @handleKeyUp
      onKeyDown: onKeyDown
      onKeyPress: onKeyPress
      onBlur: onBlur
      onFocus: onFocus
      autoComplete: autoComplete
      spellCheck: spellCheck
    }

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

    div {
      className: "#{outerClass}"
      style: style
    }, [
      textInput
      div({
          key: 'input-spinner'
          className: 'input-spinner'
        }, 
          Spinner {
            length: 3
          }
      ) if loading
      button {
        className: 'search-clear'
        title: 'Clear Search'
        key: 'searchClearBtn'
        onClick: @clear
        tabIndex: -1
      } if value?.length and showClear
      div {
        className: errorButtonClass
        key: 'textInputErrorsShow'
        ref: 'errorAnchor'
        onMouseOver: @handleErrorMouseOver
        onMouseOut: @handleErrorMouseOut
      }
    ]


module.exports = TextInput2
