/**
 * apeman react package for range input component.
 * @constructor ApRange
 */

"use strict";

const React = require('react'),
    ReactDOM = require('react-dom'),
    types = React.PropTypes,
    chopcal = require('chopcal'),
    rangecal = require('rangecal'),
    numcal = require('numcal'),
    classnames = require('classnames'),
    ApTouchable = require('apeman-react-touchable')['ApTouchable'],
    ApDraggable = require('apeman-react-draggable')['ApDraggable'],
    ApRangeLabel = require('./ap_range_label');

/** @lends ApRange */
const ApRange = React.createClass({


    //--------------------
    // Specs
    //--------------------

    propTypes: {
        from: types.number,
        to: types.number,
        min: types.number,
        max: types.number,
        step: types.number,
        onChange: types.func,
        barOnly: types.bool
    },

    statics: {},

    getInitialState: function () {
        let s = this,
            props = s.props;
        return {
            minX: 0,
            maxX: 1200,
            fromX: 0,
            toX: 1200,
            fromValue: props.from,
            toValue: props.to
        };
    },

    getDefaultProps: function () {
        return {
            from: 25,
            to: 75,
            min: 0,
            max: 100,
            step: 0.01,
            barOnly: false
        }
    },

    render: function () {
        let s = this,
            props = s.props,
            state = s.state;

        return (
            <div className={classnames('ap-range', props.className)}>
                <div className="ap-range-inner">
                    {s._renderLabel(props.min)}
                    <div className="ap-range-bar-wrap">
                        <ApTouchable onTap={s.rangeBarDidTap}>
                            <div className="ap-range-bar">
                                <div className="ap-range-bar-bg"></div>
                                <div className="ap-range-bar-highlight"
                                     style={
                                            {left:state.fromX, width:(state.toX - state.fromX)}
                                }>
                                </div>
                            </div>
                        </ApTouchable>
                        <ApDraggable onMove={s.rangeFromHandleDidMove}
                                     shouldMove={s.shouldRangeFromHandleMove}
                                     x={state.fromX}
                                     minX={state.minX}
                                     maxX={state.maxX}
                                     className="ap-range-handle ap-range-handle-from"
                                     direction="HORIZONTAL">
                            <div className="ap-range-handle-icon">
                            </div>
                        </ApDraggable>
                        <ApDraggable onMove={s.rangeToHandleDidMove}
                                     shouldMove={s.shouldRangeToHandleMove}
                                     x={state.toX}
                                     minX={state.minX}
                                     maxX={state.maxX}
                                     className="ap-range-handle ap-range-handle-to"
                                     direction="HORIZONTAL">
                            <div className="ap-range-handle-icon">
                            </div>
                        </ApDraggable>
                    </div>
                    {s._renderLabel(props.max)}
                </div>
            </div>
        )
    },


    //--------------------
    // Lifecycle
    //--------------------

    componentDidMount: function () {
        let s = this;

        window.addEventListener('resize', s.resizeRange);
        s.resizeRange();
        s.resetRangeValues();
    },

    componentWillReceiveProps: function (nextProps) {
        let s = this;
        s.resetRangeValues();
    },

    componentWillUnmount: function () {
        let s = this;
        window.removeEventListener('resize', s.resizeRange);
    },

    //------------------
    // Helper
    //------------------

    resizeRange: function (e) {
        let s = this;
        let state = s.state;
        let w = ReactDOM.findDOMNode(s).offsetWidth;
        let minX = 0,
            maxX = w;
        let fromRate = s._rateWithValue(state.fromValue),
            toRate = s._rateWithValue(state.toValue);
        s.setState({
            minX: minX,
            maxX: maxX,
            fromX: rangecal.value(minX, maxX, fromRate),
            toX: rangecal.value(minX, maxX, toRate)
        });
    },

    rangeBarDidTap: function () {

    },

    rangeFromHandleDidMove: function (e) {
        let s = this,
            fromValue = s._valueWithX(e.detail.x);
        s.setRangeValues(fromValue, s.state.toValue, true);
    },

    rangeToHandleDidMove: function (e) {
        let s = this,
            toValue = s._valueWithX(e.detail.x);
        s.setRangeValues(s.state.fromValue, toValue, false);
    },

    shouldRangeFromHandleMove: function () {
        let s = this;
        return true;
    },

    shouldRangeToHandleMove: function () {
        let s = this;
        return true;
    },

    resetRangeValues: function () {
        let s = this;
        setTimeout(function () {
            let state = s.state;
            s.setRangeValues(state.fromValue, state.toValue, true);
        });
    },

    setRangeValues: function (fromValue, toValue, forwarding) {
        let s = this;
        let state = s.state,
            props = s.props;
        let minX = state.minX,
            maxX = state.maxX;
        let step = props.step;
        if (toValue < fromValue) {
            if (forwarding) {
                toValue = fromValue;
            } else {
                fromValue = toValue;
            }
        }

        let fromRate = s._rateWithValue(fromValue),
            toRate = s._rateWithValue(toValue);

        s.setState({
            fromValue: fromValue,
            toValue: toValue,
            fromX: rangecal.value(minX, maxX, fromRate),
            toX: rangecal.value(minX, maxX, toRate)
        });

        fromValue = chopcal.round(fromValue, step);
        toValue = chopcal.round(toValue, step);

        let duplicate = (s._fromValue === fromValue) && (s._toValue === toValue);
        if (duplicate) {
            return;
        }

        s._fromValue = fromValue;
        s._toValue = toValue;

        if (props.onChange) {
            props.onChange(
                fromValue,
                toValue,
                {
                    element: s
                }
            );
        }
    },

    //------------------
    // Private
    //------------------

    _rateWithValue: function (value) {
        let s = this;
        let min = s.props.min,
            max = s.props.max;
        value = rangecal.round(min, max, value);
        return chopcal.round(rangecal.rate(min, max, value), 0.01);
    },

    _valueWithRate: function (rate) {
        let s = this;
        let min = s.props.min,
            max = s.props.max;
        let value = chopcal.round(rangecal.value(min, max, rate), 0.01);
        return rangecal.round(min, max, value);
    },

    _valueWithX: function (x) {
        let s = this;
        let minX = s.state.minX,
            maxX = s.state.maxX;
        let rate = rangecal.rate(minX, maxX, x + 2);
        return s._valueWithRate(rate);
    },

    _renderLabel: function (value) {
        let s = this,
            props = s.props;
        if (props.barOnly) {
            return null;
        }
        return (<ApRangeLabel value={value}/>);
    }
});

module.exports = ApRange;
