/**
 * imui.Input
 * @author moxhe
 * @date 2016-08-29
 */

import React from 'react';
import classnames from 'classnames';
import PropTypes from 'prop-types';
// @require '../style/index.scss'
// 为什么要封装一个Input
// 1. 实现placeholder兼容(ie8，不管了)
// 2. 实现textarea的计数
// 3. 实现UI以及支持Form和Validator组件

const CHReg = /[\u4e00-\u9fa5]/g; // 匹配中文

export default class Input extends React.Component {
  static propTypes = {
    /**
     * 类型，同原生的type属性，另外提供textarea
     */
    type: PropTypes.string,
    /**
     * 输入框大小，仅对type=text时有效
     */
    size: PropTypes.oneOf(['l', 'm', 's', 'long']),
    /**
     * 是否显示计数器及限制字数，仅对type=textarea时有效
     */
    counter: PropTypes.number,
    /**
     * 是否可用，如为true，则组件有im-textarea--disabled类名
     */
    disabled: PropTypes.bool,
    /**
     * textarea模式自动增高
     */
    autogrow: PropTypes.bool,
    /**
     * 同input元素原有的onChange属性
     */
    onChange: PropTypes.func,
  };

  static defaultProps = {
    prefixCls: 'im-input-wrapper',
    type: 'text',
    size: 'm',
  };

  constructor(props) {
    super(props);
    const { value, defaultValue, lan } = props;
    let count = 0;
    const val = value || defaultValue;
    if (val) {
      count = lan === 'ch' ? Math.floor(val.replace(CHReg, 'xx').length / 2) : val.length;
    }
    this.state = { count };

    this.onChange = this.onChange.bind(this);
    this.getValue = this.getValue.bind(this);
    this.focus = this.focus.bind(this);
    this.blur = this.blur.bind(this);
    this.grow = this.grow.bind(this);
    this.updateCount = this.updateCount.bind(this);
    this.checkAutogrow = this.checkAutogrow.bind(this);
  }

  onChange(e) {
    // 计数
    const { type, counter, onChange } = this.props;

    if (type === 'textarea' && counter) {
      this.updateCount(this.getValue());
    }

    if (onChange) {
      onChange(e);
    }
  }

  getValue() {
    return this.$input.value;
  }

  focus() {
    return this.$input.focus();
  }

  blur() {
    return this.$input.blur();
  }

  grow() {
    // growing... or keeping or shrinking...
    const textarea = this.$input;
    const div = document.createElement('pre');
    const style = window.getComputedStyle(textarea);

    div.style.cssText = `
      ${style.cssText}
      height: auto;
      position: absolute;
      left: -9999px;
      top: -9999px;
      left: 0;
      top: 0;
    `;
    // 注意clientHeight受到padding影响
    if (style.boxSizing === 'content-box') {
      div.style.paddingTop = div.style.paddingBottom = 0;
    }
    div.innerText = textarea.value.replace(/(\n|\r\n)$/, '\n\n');
    document.body.appendChild(div);
    const textHeight = div.clientHeight;
    document.body.removeChild(div);
    textarea.style.height = `${textHeight}px`;
  }

  // 更新计数显示
  updateCount(val) {
    let count = 0;
    const { lan } = this.props;
    if (val) {
      count = lan === 'ch' ? Math.floor(val.replace(CHReg, 'xx').length / 2) : val.length;
    }
    this.setState({ count });
  }

  // textarea模式自动增高事件绑定/解绑
  checkAutogrow() {
    const { type, autogrow } = this.props;
    if (type === 'textarea' && this.$input) {
      if (autogrow) {
        this.$input.addEventListener('input', this.grow);
      } else {
        this.$input.removeEventListener('input', this.grow);
      }
    }
  }

  componentDidMount() {
    this.checkAutogrow();
  }

  componentDidUpdate() {
    this.checkAutogrow();
    if (this.shouldFixHeight) {
      this.shouldFixHeight = false;
      if (this.$input) {
        this.grow();
        // 重置完height后，重置动画属性
        this.$input.style.transition = '';
      }
    }
  }

  componentWillReceiveProps(nextProps) {
    const { value, defaultValue, style } = nextProps;
    const nowValue = this.props.value || this.props.defaultValue;
    const newValue = value || defaultValue;
    if (newValue !== nowValue) {
      this.updateCount(newValue);
    }
    const { style: nowStyle, type, autogrow } = this.props;
    if (
      type === 'textarea' &&
      autogrow &&
      (style.minHeight !== nowStyle.minHeight || style.maxHeight !== nowStyle.maxHeight)
    ) {
      this.shouldFixHeight = true;
      if (this.$input) {
        this.$input.style.transition = 'none';
      }
    }
  }

  render() {
    const { onChange } = this;
    const { count } = this.state;
    const { type, size, counter, autogrow, disabled, prefixCls, className, ...others } = this.props;

    const typeStr = type === 'textarea' ? type : 'text';
    const isCounting = type === 'textarea' && counter;

    const wrapperCls = {
      [prefixCls]: true,
      [`${prefixCls}--counting`]: isCounting,
    };

    const allCls = {
      [className]: !!className,
      [`im-${typeStr}`]: true,
      [`im-${typeStr}-${size}`]: true,
      [`im-${typeStr}--disabled`]: disabled,
      [`im-${typeStr}--autogrow`]: autogrow,
    };

    // 补上该有的props
    const allProps = {
      type,
      disabled,
      onChange,
      className: classnames(allCls),
      ref: ($input) => (this.$input = $input),
    };

    // textarea计数器
    let $counter = null;
    if (isCounting) {
      const countCls = {
        'im-textarea-count': true,
        'im-textarea-count--error': count > counter,
      };

      $counter = (
        <span className="im-textarea-counter">
          <span className={classnames(countCls)}>{`${count}`}</span>/{`${counter}`}
        </span>
      );
    }

    return type === 'textarea' ? (
      <span className={classnames(wrapperCls)}>
        <textarea {...others} {...allProps} />
        {$counter}
      </span>
    ) : (
      <input {...others} {...allProps} />
    );
  }
}
