/**
 * @author moxhe
 * @date 2016-12-09
 */

import React from 'react';
import PropTypes from 'prop-types';
/**
 * 返回支持Form API的继承组件
 * 1. ref拿到的实例，string时为decorator实例，function时为klass实例
 * 2. 实现context配合Form组件 API
 * 3. 始终传递value & onChange属性(受控组件),可通过options改变
 * @param  {ReactClass} klass 表单组件
 * @param  {Object}     klass 配置对象
 * @return {ReactClass}       继承组件
 */
export default function (klass, options = {}) {
  return class FormDecorator extends React.Component {
    static contextTypes = {
      form: PropTypes.object
    };

    constructor(props) {
      super(props);

      const valuePropName = options.valuePropName || 'value';
      let value = props[valuePropName];

      if (value === undefined) {
        value = props.defaultValue !== undefined ? props.defaultValue : options.initialValue;
      }

      this.state = { value };
      this.valuePropName = valuePropName;
      this.trigger = options.trigger || 'onChange';

      this.getValue = this.getValue.bind(this);
      this.setValue = this.setValue.bind(this);
      this.handleChange = this.handleChange.bind(this);
    }

    componentWillReceiveProps(nextProps) {
      const { valuePropName } = this;
      const value = nextProps[valuePropName];
      // const lastValue = this.props[valuePropName];
      const lastValue = this.state.value;

      // 过滤undefiend值，不允许表单组件有undefined的value
      if (value !== undefined && value !== lastValue) {
        // ant.design不允许被decorator封装后的表单用prop来传递value
        // 这里做个hack实现下
        if (value !== null &&
          typeof value === 'object' &&
          JSON.stringify(value) === JSON.stringify(lastValue)) {
          return;
        }

        this.setState({ value });
      }
    }

    componentDidMount() {
      const { name } = this.props;
      const { form } = this.context;

      // 提供表单实例映射给Form组件
      if (name && form.fields) {
        form.fields[name] = this;
      }
    }

    getValue() {
      return this.state.value;
    }

    setValue(value) {
      this.setState({ value });
    }

    handleChange(data, ...args) {
      // SyntheticEvent or value(不同组件的value格式不一样)
      const value = data.nativeEvent ? data.target.value : data;

      this.setState({ value });

      if (this.props.onChange) {
        // 当表单表现为受控时，需要先强行更新state中的值以供props[valueProperty]变化判断
        this.state.value = value;
        this.props.onChange(value, ...args);
      }
    }

    render() {
      const props = Object.assign({}, this.props, {
        ref: (field) => {
          this.field = field;
        },
        [this.valuePropName]: this.state.value,
        [this.trigger]: this.handleChange
      });

      return React.createElement(klass, props);
    }
  };
}
