import React from 'react';
import * as Dropdown from '../../atoms/dropdown';

function match(key, a, b) {
    return a[key] === b[key];
}

/**\

    title: SequencedDropdowns
    category: component
    description:
        Manages the sequencing of several dropdowns. Subsequent
        dropdowns are only enabled after the current dropdown
        has a selection.
    props:
        className[String]:
            Additional classes to apply to the FormDropdown
        disabled[Boolean]:
            disables this component. default is false.
        settings[Array]:
            Array of prop maps to be applied to each dropdown.
            SequencedDropdowns merely manages the enabled/disabled state
            of each.
        onSelect[Function]:
            When a selection has been made. This function will
            be called with the 0-based index of the dropdown
            for which a selection was made, and the selected Model.
            i.e. f(idx, model).
            Optionally, use this function to return an array of
            options for the next dropdown (see Dropdown 'items').
        onComplete[Function]:
            When all dropdowns are completed, this function will
            be called with the array of selected Models. onSelect is
            called on the last dropdown before this is called.

\**/
class SequencedDropdowns extends React.Component {
    static defaultProps = {
        disabled: false,
        settings: []
    };

    state = {
        at: 0, // the idx of furthest enabled dropdown
        selections: [] // the Models of completed dropdowns
    };

    constructor(props) {
        super(props);

        this.itemOverrides = {};

        if (this.props.disabled) {
            this.state.at = -1;
        } else {
            this.state.at = this.getAt();
        }
    }

    // returns index of furthest consecutive dropdown with a value
    getAt(props) {
        const _props = props || this.props;
        let i, setting;

        for (i = 0; i < _props.settings.length; i++) {
            setting = _props.settings[i];

            if (setting.value !== null && setting.value !== undefined) {
                this.state.selections[i] = setting.items
                    .find(match.bind(this, 'key', setting));
                return i + 1;
            }
        }

        return 0;
    }

    componentWillReceiveProps(props) {
        /* istanbul ignore else: no one cares */
        if (props.hasOwnProperty('disabled')) {
            this.setState({
                at: props.disabled ? -1 : this.getAt(props)
            });
        }
    }

    _settingToDropdown(setting, idx) {
        let onSelect = null,
            value = null;

        // only define onSelect for enabled dropdowns
        if (this.state.at >= idx) {
            onSelect = (option) => {
                const _state = {};

                _state.at = idx + 1;

                _state.selections = this.state.selections.slice(0, idx);
                _state.selections[idx] = option;

                if (typeof setting.onSelect === 'function') {
                    setting.onSelect(option);
                }

                if (typeof this.props.onSelect === 'function') {
                    const items = this.props.onSelect(idx, option);

                    if (Array.isArray(items)) {
                        this.itemOverrides[idx + 1] = items;
                    }
                }

                // if last dropdown selected
                if (idx === this.props.settings.length - 1) {
                    /* istanbul ignore else: no one cares */
                    if (typeof this.props.onComplete === 'function') {
                        this.props.onComplete(_state.selections);
                    }
                }

                this.setState(_state);
            };
        }

        if (this.itemOverrides[idx]) {
            setting.items = this.itemOverrides[idx];
            delete this.itemOverrides[idx];
        }

        if (this.state.selections[idx]) {
            value = this.state.selections[idx].value;
        }

        return (
            <Dropdown.View
                key={ idx }
                { ...setting }
                value={ value }
                onSelect={ onSelect }
                disabled={ this.state.at < idx } />
        );
    }

    render() {
        const classer = 'sequenced-dropdowns';
        let dropdowns;

        dropdowns = this.props.settings
            .map(this._settingToDropdown.bind(this));

        return (
            <div className={ `${classer} ${this.props.className}` }>
                { dropdowns }
            </div>
        );
    }
}

export default SequencedDropdowns;
