class Input extends React.Component {
    constructor(props) {
        super(props);

        const input = {
            label: props.data.label,
            name: props.data.name,
            description: props.data.description,
            defaultValue: props.data.defaultValue ? props.data.defaultValue : '',
        };

        if (props.data.inputType !== 'checkbox') {
            input.required = props.data.required === true;
            input.className = "form-control";
        }

        if (props.data.inputType === 'select' || props.data.inputType === 'textarea') {
            input.tag = props.data.inputType;
        } else if (props.data.inputType === 'multiple_select') {
            input.tag = 'select';
            input.multiple = true;
        } else {
            input.tag = 'input';
            input.type = props.data.inputType;
        }

        let child;
        switch (props.data.inputType) {
            case 'input':
                break;  //Nothing to do
            case 'hidden':
                break;  //Nothing to do
            case 'number':
                break;  //Nothing to do
            case 'file':
                break;  //Nothing to do
            case 'date':
                input['dateTimeFormat'] = 'YYYY-MM-DD';
                if (props.data.defaultValue) {
                    input['defaultValue'] = moment(input['defaultValue']).format(input['dateTimeFormat']);
                }
                break;
            case 'datetime':
                input['dateTimeFormat'] = 'YYYY-MM-DD HH:mm:ss';
                if (props.data.defaultValue) {
                    input['defaultValue'] = moment(input['defaultValue']).format(input['dateTimeFormat']);
                }
                break;
            case 'checkbox':
                input['defaultChecked'] = input['defaultValue'] = props.data.defaultValue === true;
                break;
            case 'text':
                input['size'] = props.data.args.field_len;
                input['maxLength'] = props.data.args.max_value_len;
                break;
            case 'textarea':
                input['rows'] = props.data.args.rows;
                input['cols'] = props.data.args.columns;
                break;
            case 'select':
                child = this.getOptionsForSelectInput(props.data.allowedValues);
                if (!props.data.required) {
                    input['defaultValue'] = '';
                    child.unshift(<option key="empty_key" value="">-</option>);
                }
                break;
            case 'multiple_select':
                child = this.getOptionsForSelectInput(props.data.allowedValues);
                break;
            default:
                alert("Unknown inputType: " + props.data.inputType);
        }

        this.element = input;
        this.children = child;
        this.state = {
            value: input.defaultValue,
        };

        this.onChange = this.onChange.bind(this);
        this.updateDateTime = this.updateDateTime.bind(this);
    }

    getOptionsForSelectInput(optionsData) {
        return optionsData.map(function (choice) {
            return <option key={choice} value={choice}>{choice}</option>;
        });
    }

    componentWillMount() {
        this.setFormParams(this.element.name, this.state.value);
    }

    componentDidMount() {
        if (this.element.type === 'date' || this.element.type === 'datetime') {
            this.attachDateTimePicker(this.element.name, this.state.value);
        }
    }

    setFormParams(name, value) {
        if (value === '' && !this.element.required && this.element.type !== 'checkbox') {
            value = null; //Для необязательного элемента отправляем null на сервер, если ничего не выбрали или не проставили
        } else if (value && this.element.type === 'datetime') {
            value = moment(value).format('YYYY-MM-DDTHH:mm:ss'); //На сервер отправляем время в этом формате
        }
        this.props.setFormParams(name, value);
    }

    onChange(event) {
        const name = event.target.name;
        let value = event.target.value;
        if (this.element.type === 'checkbox') {
            value = !this.state.value;
        } else if (this.element.tag === 'select' && this.element.multiple) {
            const options = event.target.options;
            value = [];
            for (const option of options) {
                if (option.selected) {
                    value.push(option.value);
                }
            }
        }

        this.setState({value: value});
        this.setFormParams(name, value);
    }

    updateDateTime(value) {
        const dateTime = value.format(this.element.dateTimeFormat);

        this.setState({value: dateTime});
        this.setFormParams(this.element.name, dateTime);
    }

    attachDateTimePicker(name, value) {
        const props = {
            startDate: value,
            singleDatePicker: true,
            alwaysShowCalendars: true,
            locale: {
                format: this.element.dateTimeFormat,
            }
        };

        if (value === '') {
            delete props.startDate;
            props.autoUpdateInput = false;
        }

        if (this.element.type === 'datetime') {
            Object.assign(props, {
                timePicker: true,
                timePicker24Hour: true,
                timePickerSeconds: true
            })
        }

        $('input[name=' + name + ']').daterangepicker(props, this.updateDateTime);
    }

    render() {
        const props = $.extend(true, {}, this.element);
        props.value = this.state.value;
        props.onChange = this.onChange;
        props.id = "form_" + this.element.name;
        const input = React.createElement(
            this.element.tag,
            props,
            this.children,
        );

        const helpBlock = props.description ?
            <p className="help-block" dangerouslySetInnerHTML={{__html: props.description}}>
            </p>
            : '';
        const requiredBlock = props.required && props.type !== 'checkbox' ? " *" : '';

        if (props.type === 'hidden') {
            return this.renderHidden(props, input);
        } else if (props.type === 'checkbox') {
            return this.renderCheckBox(props, input, helpBlock);
        }
        return <div className="form-group">
            <label htmlFor={props.id}>{props.label}{requiredBlock}</label>
            {input}
            {helpBlock}
        </div>;
    }

    renderHidden(element, input) {
        return input
    }

    renderCheckBox(element, input, helpBlock) {
        return (
            <div className="checkbox">
                <label>
                    {input} {element.label}
                </label>
                {helpBlock}
            </div>
        );
    }
}

class InputGroup extends React.Component {
    render() {
        return (
            <div>
                <h3>{this.props.data.name}</h3>
                {this.props.data.inputs.map((element) => <Input key={element.name} data={element}
                                                                setFormParams={this.props.setFormParams}/>)}
            </div>
        );
    }
}

class Form extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            __counter: 0,
        };

        this.formParams = {};

        this.files = [];
        for (const group of this.props.data.inputGroups) {
            for (const element of group.inputs) {
                if (element.inputType === 'file') {
                    this.files.push("form_" + element.name);
                }
            }
        }
        this.submitting = false;

        this.handleSubmit = this.handleSubmit.bind(this);
        this.setFormParams = this.setFormParams.bind(this);
        this.handleSubmitSuccess = this.handleSubmitSuccess.bind(this);
        this.handleSubmitError = this.handleSubmitError.bind(this);
    }

    setFormParams(name, value) {
        this.formParams[name] = value;
    }

    handleSubmit(event) {
        event.preventDefault();

        if (this.submitting === true) {
            return;
        }
        this.submitting = true;

        const formData = $.extend(true, {}, this.formParams);

        this.props.onSubmit(this.props.data.label, this.props.data.method, formData, this.files,
            this.handleSubmitSuccess, this.handleSubmitError);
    }

    handleSubmitSuccess() {
        this.setState((prevState) => ({__counter: prevState.__counter + 1}));
        this.submitting = false;
    }

    handleSubmitError() {
        this.submitting = false;
    }

    render() {
        const groups = [];
        for (const group of this.props.data.inputGroups) {
            groups.push(<InputGroup key={group.name + this.state.__counter} data={group}
                                    setFormParams={this.setFormParams}/>);
        }

        return (
            <div className="row it-form-row">
                <div className="col-sm-12">
                    <form id="it-form" onSubmit={this.handleSubmit}>
                        {groups}
                        <input id="it-form-submit" className="btn btn-primary" value={this.props.data.action}
                               type="submit"/>
                    </form>
                </div>
            </div>
        );
    }
}
