/**
 * Mixin for form.
 * @mixin ApFormMixin
 */

'use strict'

import React, {PropTypes as types} from 'react'
import ReactDOM from 'react-dom'
import defaults from 'defaults'
import stringcase from 'stringcase'

/** @lends ApFormMixin */
const ApFormMixin = {

  // --------------------
  // Custom
  // --------------------
  $apFormMixed: true,

  /**
   * Handle change of form input
   * @param {object} e - Input change event.
   */
  handleFormChange (e) {
    const s = this
    let { props } = s

    let { name, value } = e.target
    let values = Object.assign(
      {}, props.formValues, {
        [name]: value
      }
    )

    if (props.onFormChange) {
      e = e || {}
      e.target = e.target || ReactDOM.findDOMNode(s)
      e.form = values
      props.onFormChange(e)
    }
  },

  /**
   * Handle form submit.
   * @param {object} e - Submit event.
   */
  handleFormSubmit (e) {
    const s = this
    let { props } = s

    let values = props.formValues
    if (props.onFormSubmit) {
      e = e || {}
      e.target = e.target || ReactDOM.findDOMNode(s)
      e.form = values
      props.onFormSubmit(e)
    }
  },

  /**
   * Handle form cancel.
   * @param {object} e - Submit event.
   */
  handleFormCancel (e) {
    const s = this
    let { props } = s

    let values = props.formValues
    if (props.onFormCancel) {
      e = e || {}
      e.target = e.target || ReactDOM.findDOMNode(s)
      e.form = values
      props.onFormCancel(e)
    }
  },

  /**
   * Get a form value.
   * @param {string} name - Name of the value.
   * @returns {*} - Value
   */
  getFormValue (name) {
    const s = this
    let values = s.getFormValues()
    return values && values[ name ]
  },

  /**
   * Get form values.
   * @returns {string}
   */
  getFormValues () {
    const s = this
    let { formValues } = s.props
    return s.formatFormValues(formValues || null)
  },

  /**
   * Get a form id.
   * @param {string} name
   * @returns {string}
   */
  getFormId (name) {
    const s = this
    let { formPrefix } = s.props
    return [
      formPrefix || 'ap-form',
      stringcase.spinalcase(name)
    ].join('-')
  },

  /**
   * Get a label
   * @param {string} name
   * @returns {string}
   */
  getFormLabel (name) {
    const s = this
    let { formLabels } = s.props
    let label = (formLabels || {})[ name ]
    if (!label) {
      console.warn(`[ApFormMixin] Label not found with name: ${name}`)
      label = name
    }
    return label
  },

  /**
   * Get a icon
   * @param {string} name
   * @returns {string}
   */
  getFormIcon (name) {
    const s = this
    let { formIcons } = s.props
    return (formIcons || {})[ name ]
  },

  /**
   * Get a placeholder
   * @param {string} name
   * @returns {string}
   */
  getFormPlaceholder (name) {
    const s = this
    let { formPlaceholders } = s.props
    return (formPlaceholders || {})[ name ]
  },

  /**
   * Get an image
   * @param {string} name
   * @returns {string}
   */
  getFormImage (name) {
    const s = this
    let { formImages } = s.props
    return (formImages || {})[ name ]
  },

  /**
   * Get an action
   * @param {string} name
   * @returns {string}
   */
  getFormAction (name) {
    const s = this
    let { formActions } = s.props
    return (formActions || {})[ name ]
  },

  /**
   * Wrap as form handler.
   * @param {function} handler - A handler.
   * @param {object} options - Optional setttings
   * @returns {function}
   */
  asFormHandler (handler, options) {
    const s = this
    options = options || {}
    let key = options.key || 'default'
    if (!handler) {
      return null
    }
    handler.apFormWraps = handler.apFormWraps || {}
    handler.apFormWraps[ key ] = handler.apFormWraps[ key ] ||
      function formWrap (e) {
        e = Object.assign(e || {}, {
          form: s.getFormValues()
        }, options)
        handler.call(s, e)
      }
    return handler.apFormWraps[ key ]
  },

  // --------------------
  // Specs
  // --------------------

  propTypes: {
    formValues: types.object,
    formLabels: types.object,
    formIcons: types.object,
    formImages: types.object,
    formActions: types.object,
    formPlaceholders: types.object,
    formPrefix: types.string,
    onFormChange: types.func,
    onFormSubmit: types.func,
    onFormCancel: types.func
  },

  getDefaultProps () {
    return {}
  },

  // --------------------
  // Lifecycle
  // --------------------

  componentWillMount () {
    const s = this

    let noop = (value) => value
    defaults(s, {
      formatFormValues: noop
    })
  }

}

export default Object.freeze(ApFormMixin)
