import React from 'react'
import PropTypes from 'prop-types'
import Component from '../utils/Component'
import classnames from 'classnames'
import {warning} from '../utils/Tool'
import Icon from '../icon/'
import Logger from '../utils/logger'

import '../style'
import 'phoenix-styles/less/modules/input.less'

/**
 * 输入框组件<br/>
 * - 使用方式跟原生一致, 支持disabled、maxLength等原生属性。
 * - 通过type设置input的类型, 可选text,search,password。
 * - 可通过value设置默认值。
 * - 可通过设置clear属性是否显示清除按钮,默认不显示。
 * - 可通过设置visible属性判断password类型是否显示可见密码的按钮,默认不显示。
 * - 可通过设置error设置当前输入错误。
 * - 可通过getValueCallback获取当前元素的value值,仅适用于text、search。
 * - 可通过设置phReg设置正则表达式,失焦时如果不符合正则显示错误样式。
 * - className/style属性加在外层,其余属性均赋予input元素。
 *
 * 主要属性和接口:
 * - type:input类型, 默认text <br/>
 * 如:`<Input type='search' disabled/>`
 * - value:设置默认值 <br/>
 * 如:`<Input value='测试' />`
 * - clear:是否显示清除按钮 <br/>
 * 如:`<Input value='测试' clear/>`
 * - visible: 是否显示可见密码的按钮(仅适用于password类型)<br/>
 * 如:`<Input type='password' value='123456' visible />`
 * - error: 当前输入错误<br/>
 * 如:`<Input type='password' value='123456' error />`
 * - phReg: 正则表达式<br/>
 * 如:`<Input type="text" placeholder="6-18位不以数字开头的用户名" phReg={/^[a-zA-Z$_]\w{5,17}$/} />`
 * - getValueCallback: 获取当前input的value。<br/>
 * 如:`<Input ref={(inputElem)=>{this.inputElem=inputElem}} />`<br/>
 * `this.inputElem.getValueCallback();`
 *
 * @class Input
 * @module 表单组件
 * @extends Component
 * @constructor
 * @since 0.1.0
 * @demo input|input.js {展示}
 * @show true
 * */

export default class Input extends Component{

    static propTypes = {
        /**
         * input类型, 可选[text,search,password], 默认text
         * @property type
         * @type String
         * @default 'text'
         * */
        type: PropTypes.string,
        /**
         * 样式前缀
         * @property classPrefix
         * @type String
         * @default 'input'
         * */
        classPrefix:PropTypes.string,
        /**
         * 标签tagName
         * @property componentTag
         * @type String
         * */
        componentTag:PropTypes.string,
        /**
         * 是否显示[清除已经输入的内容按钮],仅适用于text,search,password的类型
         * @property clear
         * @type Boolean
         * */
        clear: PropTypes.bool,
        /**
         * 是否显示[密码是否可见按钮],仅适用于password的类型
         * @property visible
         * @type Boolean
         * */
        visible: PropTypes.bool,
        /**
         * 是否错误
         * @property error
         * @type Boolean
         * */
        error: PropTypes.bool,
        /**
         * 正则表达式
         * @property phReg
         * @type Object
         * */
        phReg: PropTypes.object,
        /**
         * icon符号类型
         * @property phIcon
         * @type string
         * @default ''
         **/
        phIcon:PropTypes.string
    };

    static defaultProps = {
        type: 'text',
        clear: false,
        error: false,
        visible: false,
        phIcon: '',
        phReg: null,
        disabled: false,
        classPrefix:'input',
        componentTag:'div',
        classMapping : {}
    };

    constructor(props, context) {
        super(props, context)

        new Logger('Input')

        this.setMethod('getValueCallback',this.getValue.bind(this))

        this.visibleIcon = ['biyan','yinsi']
        
        this.state = {
            type: props.type,
            cansee: 0,
            focus: false,
            value: props.value || '',
            error: props.error
        }
    }

    componentDidMount(){
        let o = {},
            {phReg} = this.props
        
        if(!phReg || !this.state.value) return

        o.error = !phReg.test(this.state.value)
        
        this.setState(o)
    }

    componentWillReceiveProps(nextProps){
        let o = {}

        if(nextProps.value!==undefined && nextProps.value !== this.state.value) o.value = nextProps.value
        if(nextProps.error!==undefined && nextProps.error !== this.state.error) o.error = nextProps.error
        
        this.setState(o)
    }

    renderInput(){
        let {type, clear, visible, placeholder, phIcon, disabled, className, style} = this.props,
            {value, focus, error} = this.state;
        let clearStatus = clear && value && focus,
            visibleStatus = visible && type=='password',
            errorState = error && !focus,
            placeholderShow = !focus && value==='';
        
        if(['checkbox', 'radio'].indexOf(type) >= 0){
            warning('Input组件: type 为 checkbox|radio 请对应使用 Checkbox|Radio 组件!')
            return null
        }else{
            return (
                <div className={classnames(
                    this.getProperty(true),
                    phIcon ? this.setPhPrefix('heading'):'',
                    clearStatus ? this.setPhPrefix('clear'):'',
                    visibleStatus ? this.setPhPrefix('visible'):'',
                    errorState ? this.setPhPrefix('error'):'',
                    this.setPhPrefix(type),
                    className
                )} style={this.getStyles(style)}>
                    <input {...this.otherProps} className='' style={null} type={this.state.type} placeholder='' value={value} disabled={disabled}
                        ref={(inputElem)=>{this.inputElem=inputElem}}
                        onChange={this.onChange.bind(this)} 
                        onFocus={this.onFocus.bind(this)} 
                        onBlur={this.onBlur.bind(this)} />
                    <label className={classnames(
                        this.setPhPrefix('placeholder'),
                        !placeholderShow? this.setPhPrefix('placeholder-hide'):''
                    )}>
                        {phIcon ? <Icon phIcon={phIcon} />: null}
                        <span className={this.setPhPrefix('placeholder-text')}>{placeholder}</span>
                    </label>
                    {this.renderClearButton(clearStatus)}
                    {this.renderVisibleButton(visibleStatus)}
                    {this.renderErrorButton(errorState)}
                </div>
            );
        }
    }

    onChange(event){
        let o = {},
            {onChange, phReg} = this.props,
            value = event.target.value
        
        o.value = value
        o.focus = true
        if(phReg){
            o.error = !phReg.test(value)
        }

        if(onChange) onChange(event,value)
        
        this.setState(o)
    }

    onFocus(e){
        let {onFocus} = this.props

        this.setState({
            focus: true
        }, ()=>{
            if(onFocus) onFocus()
        })
    }

    onBlur(e){
        let {onBlur} = this.props

        this.timer = setTimeout(()=>{
            this.setState({
                focus: false
            }, ()=>{
                if(onBlur) onBlur()
            })
        },0)            
    }

    renderClearButton(clear){
        if(clear){
            return <Icon className='gfs-icon-close' phIcon='fail-fill' onClick={this.clearHandle.bind(this)} />
        }
    }

    clearHandle(e){
        clearTimeout(this.timer)
        let {clearCallback} = this.props

        if(clearCallback) clearCallback()

        this.setState({
            value: '',
            focus: true
        },()=>{
            this.inputElem.focus()
        })
    }

    renderVisibleButton(visible){
        if(visible){
            return <Icon className={classnames('gfs-icon-visible gfs-icon-active')} 
                phIcon={this.visibleIcon[this.state.cansee]} 
                onClick={this.visibleHandle.bind(this)} />
        }
    }

    visibleHandle(){
        if(this.state.cansee){
            this.setState({
                type: 'password',
                cansee: 0
            })
        }else{
            this.setState({
                type: 'text',
                cansee: 1
            })
        }        
    }

    renderErrorButton(error){
        if(error){
            return <Icon className={classnames('gfs-icon-error')} phIcon='warning-fill' />
        }
    }

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

    componentWillUnmount(){
        clearTimeout(this.timer)
    }

    render(){
        return this.renderInput()
    }

}