import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import IDUtil from '../../../util/IDUtil';

export default class TimeInput extends React.PureComponent {
    constructor(props) {
        super(props);
        this.hours = React.createRef();
        this.minutes = React.createRef();
        this.seconds = React.createRef();

        this.state = this.parseTime(this.props.time);
    }

    parseTime(time) {
        const hours = Math.floor(time / 3600);
        time -= hours * 3600;
        const minutes = Math.floor(time / 60);
        time -= minutes * 60;
        const seconds = Math.floor(time);
        time -= seconds;

        return { hours, minutes, seconds };
    }

    getTime(hours, minutes, seconds) {
        return Math.max(0, hours * 3600 + minutes * 60 + seconds);
    }

    onUpdate = () => {
        const values = this.getFormValues();
        const time = this.getTime(values.hours, values.minutes, values.seconds);
        this.setState(this.parseTime(time), () => {
            // always force update to prevent negative inputs
            this.forceUpdate();
        });

        // optional callback
        if (this.props.onUpdate) {
            this.props.onUpdate(time);
        }
    };

    // can be called from ref
    getValue() {
        const values = this.getFormValues();
        return this.getTime(values.hours, values.minutes, values.seconds);
    }

    // can be called from ref
    setValue(time) {
        this.setState(this.parseTime(time));
    }

    getFormValues = () => {
        // additional checks to make the value increase/decrease, but not zero out smaller values

        // hours
        let hours = Math.max(0, parseInt(this.hours.current.value));
        hours = isNaN(hours) ? 0 : hours;

        // minutes
        let minutes = parseInt(this.minutes.current.value.toString().slice(-2));
        minutes = isNaN(minutes) ? 0 : minutes;
        if (hours == 0) {
            minutes = Math.max(0, minutes);
        }

        // seconds
        let seconds = parseInt(this.seconds.current.value.toString().slice(-2));
        seconds = isNaN(seconds) ? 0 : seconds;
        if (minutes == 0) {
            seconds = Math.max(0, seconds);
        }

        return { hours, minutes, seconds };
    };

    zeroPad(v) {
        const zero = 2 - v.toString().length + 1;
        return Array(+(zero > 0 && zero)).join('0') + v;
    }

    onFocus = e => {
        e.target.select();
    };

    onKeyDown = e => {
        switch (e.keyCode) {
            case 38: // up
                e.target.value =
                    parseInt(e.target.value) + (e.shiftKey ? 10 : 1);
                this.onUpdate();
                break;
            case 40: // down
                e.target.value =
                    parseInt(e.target.value) - (e.shiftKey ? 10 : 1);
                this.onUpdate();
                break;
            case 13: // enter
                this.onFinish();
                break;
        }
    };

    onBlur = () => {
        this.forceUpdate();
    };

    // optional onFinish callback will be called on blur or on enter-key
    // to let parent know input can be progressed
    onFinish = () => {
        if (this.props.onFinish) {
            const values = this.getFormValues();
            const time = this.getTime(
                values.hours,
                values.minutes,
                values.seconds
            );
            this.props.onFinish(time);
        }
    };

    render() {
        return (
            <div className={classNames(IDUtil.cssClassName('time-input'))}>
                <input
                    type="text"
                    ref={this.hours}
                    value={
                        this.hours.current == document.activeElement
                            ? this.state.hours
                            : this.zeroPad(this.state.hours)
                    }
                    onChange={this.onUpdate}
                    onFocus={this.onFocus}
                    onKeyDown={this.onKeyDown}
                    onBlur={this.onBlur}
                />
                :
                <input
                    type="text"
                    ref={this.minutes}
                    value={
                        this.minutes.current == document.activeElement
                            ? this.state.minutes
                            : this.zeroPad(this.state.minutes)
                    }
                    maxLength={2}
                    onChange={this.onUpdate}
                    onFocus={this.onFocus}
                    onKeyDown={this.onKeyDown}
                    onBlur={this.onBlur}
                />
                :
                <input
                    type="text"
                    ref={this.seconds}
                    value={
                        this.seconds.current == document.activeElement
                            ? this.state.seconds
                            : this.zeroPad(this.state.seconds)
                    }
                    maxLength={2}
                    onChange={this.onUpdate}
                    onFocus={this.onFocus}
                    onKeyDown={this.onKeyDown}
                    onBlur={this.onBlur}
                />
            </div>
        );
    }
}

TimeInput.propTypes = {
    // time in seconds
    time: PropTypes.number.isRequired,
    onUpdate: PropTypes.func,
    onFinish: PropTypes.func
};
