import React, { PureComponent } from 'react';
import { Animated, Image, StyleSheet, PanResponder, View, Text, Platform } from 'react-native';
import variables from '../../common/styles/variables';
import sliderStyles from './styles';
import Coord from './Coord';
const thumbImage = require('./images/rectangle.png');
const otherThumbImage = require('./images/rectangle.png');
const styles = StyleSheet.create(sliderStyles);
export default class Slider extends PureComponent {
    constructor(props) {
        super(props);
        /**
         * 通过props获取滑块对应的value值
         */
        this.getValueByProps = (isOther) => {
            const { value, range } = this.props;
            if (range && value instanceof Array) {
                if (isOther) {
                    return value[1];
                }
                return value[0];
            }
            return value;
        };
        /**
         * 判断用户触控的区域是否在滑块上
         */
        this.thumbTouchCheck = (e) => {
            const nativeEvent = e.nativeEvent;
            const { range } = this.props;
            if (range) {
                const otherThumbCoord = this.getThumbCoord(range);
                const otherCheckResult = otherThumbCoord.contain(nativeEvent.locationX, nativeEvent.locationY);
                if (otherCheckResult) {
                    this.isOther = true;
                    return otherCheckResult;
                }
            }
            const ThumbCoord = this.getThumbCoord();
            const checkResult = ThumbCoord.contain(nativeEvent.locationX, nativeEvent.locationY);
            if (checkResult) {
                this.isOther = false;
                return checkResult;
            }
            return false;
        };
        this.getThumbCoord = (isOther) => {
            const { thumbSize, otherThumbSize, containerSize } = this.state;
            let currThumb = thumbSize;
            if (isOther) {
                currThumb = otherThumbSize;
            }
            const { vertical } = this.props;
            let x = null;
            let y = null;
            if (vertical) {
                x = (containerSize.width - currThumb.width) / 2;
                y = this.getThumbLeft(this.getCurrentValue(isOther));
            }
            else {
                x = this.getThumbLeft(this.getCurrentValue(isOther));
                y = (containerSize.height - currThumb.height) / 2;
            }
            return new Coord(x, y, currThumb.width, currThumb.height);
        };
        /**
         * 滚动状态响应
         */
        this.scroll = (gestureState) => {
            if (this.props.disabled) {
                return;
            }
            if (this.isOther) {
                const isOtherValue = this.getValue(gestureState, this.isOther);
                this.setCurrentValue(isOtherValue, this.isOther);
            }
            else {
                const value = this.getValue(gestureState);
                this.setCurrentValue(value);
            }
        };
        this.touchStart = (e) => {
            this.oldValue = this.state.value.__getValue();
            this.oldOtherValue = this.state.otherValue.__getValue();
            return this.thumbTouchCheck(e);
        };
        this.pressStart = () => {
            if (this.isOther) {
                this.otherPreviousLeft = this.getThumbLeft(this.getCurrentValue(this.isOther));
            }
            else {
                this.previousLeft = this.getThumbLeft(this.getCurrentValue());
            }
        };
        this.lastMove = (_, gestureState) => {
            this.scroll(gestureState);
        };
        this.touchEnd = (_, gestureState) => {
            this.scroll(gestureState);
            if (this.oldValue !== this.getCurrentValue()) {
                this.triggerEvent('onChange');
            }
            if (this.props.range && this.oldOtherValue !== this.getCurrentValue(true)) {
                this.triggerEvent('onChange');
            }
        };
        this.measureContainer = (x) => {
            this.handleMeasure('containerSize', x);
        };
        this.measureTrack = (x) => {
            this.handleMeasure('trackSize', x);
        };
        this.measureThumb = (x) => {
            this.handleMeasure('thumbSize', x);
        };
        this.measureOtherThumb = (x) => {
            this.handleMeasure('otherThumbSize', x);
        };
        this.handleMeasure = (name, x) => {
            const { width, height } = x.nativeEvent.layout;
            const size = { width, height };
            const currentSize = this.state[name];
            if (currentSize &&
                width === currentSize.width &&
                height === currentSize.height) {
                return;
            }
            const newState = {
                [name]: size
            };
            // 双滑块
            this.setState(newState);
        };
        /**
         * 获取可滑动长度
         */
        this.getScrollLength = () => {
            const { vertical } = this.props;
            const { trackSize } = this.state;
            if (vertical) {
                return trackSize.height;
            }
            else {
                return trackSize.width;
            }
        };
        /**
         * 获取滑块的坐标的宽度
         * 如果是横向slider则取width,纵向取height
         */
        this.getThumbOffset = (isOther) => {
            const { vertical } = this.props;
            const { thumbSize, otherThumbSize } = this.state;
            if (vertical && isOther) {
                return otherThumbSize.height;
            }
            else if (!vertical && isOther) {
                return otherThumbSize.width;
            }
            else if (vertical && !isOther) {
                return thumbSize.height;
            }
            else if (!vertical && !isOther) {
                return thumbSize.height;
            }
        };
        /**
         * 获取当前value值所占的百分比
         */
        this.getRatio = (value) => {
            const { min, max } = this.props;
            if (max === min) {
                return 0;
            }
            return (value - min) / (max - min);
        };
        /**
         * 滑块在滑动轴上的偏移量
         * value => x
         */
        this.getThumbLeft = (value) => {
            const { vertical } = this.props;
            let ratio = this.getRatio(value);
            if (vertical) {
                ratio = 1 - ratio;
            }
            const scrollLength = this.getScrollLength();
            return (ratio * scrollLength);
        };
        /**
         * 互斥prop
         * 刻度属性只有正在非纵向轴、非双滑块下才生效
         */
        this.showStep = () => {
            const { vertical, step, range } = this.props;
            if (!range && !vertical && step) {
                return true;
            }
            return false;
        };
        /**
         * 获取滑动位置所对应的value值，和getThumbLeft方法对应
         * x => value
         */
        this.getValue = (gestureState, isOther) => {
            let previousLeft = this.previousLeft;
            if (isOther) {
                previousLeft = this.otherPreviousLeft;
            }
            const scrollLength = this.getScrollLength();
            const { step, min, max, vertical } = this.props;
            let thumbLeft = null;
            if (vertical) {
                thumbLeft = previousLeft + gestureState.dy;
            }
            else {
                thumbLeft = previousLeft + gestureState.dx;
            }
            let ratio = thumbLeft / scrollLength;
            if (vertical) {
                ratio = 1 - ratio;
            }
            if (this.showStep()) {
                return Math.max(min, Math.min(max, min + Math.round(ratio * (max - min) / step) * step));
            }
            return Math.max(min, Math.min(max, ratio * (max - min) + min));
        };
        /**
         * 获取滑块的value值
         */
        this.getCurrentValue = (isOther) => {
            let value = this.state.value;
            if (isOther) {
                value = this.state.otherValue;
            }
            return value.__getValue();
        };
        this.setCurrentValue = (value, isOther) => {
            if (isOther) {
                this.setState({
                    otherTip: `${Math.round(value)}`
                });
                this.state.otherValue.setValue(value);
            }
            else {
                this.setState({
                    tip: `${Math.round(value)}`
                });
                this.state.value.setValue(value);
            }
        };
        this.triggerEvent = (event) => {
            if (this.props[event]) {
                let args = [Math.round(this.getCurrentValue())];
                const { range } = this.props;
                if (range) {
                    if (this.compareValue()) {
                        args.unshift(Math.round(this.getCurrentValue(range)));
                    }
                    else {
                        args.push(Math.round(this.getCurrentValue(range)));
                    }
                    this.props[event](args);
                }
                else {
                    this.props[event](args[0]);
                }
            }
        };
        /**
         * 默认滑块的的滑块图片渲染
         */
        this.renderThumbImage = (isOther) => {
            if (!isOther && !thumbImage)
                return;
            if (isOther && !otherThumbImage)
                return;
            const { renderThumb } = this.props;
            const { thumbSize } = this.state;
            if (typeof renderThumb === 'function') {
                return renderThumb(isOther);
            }
            return React.createElement(Image, { style: [{width:thumbSize.width-20,height:thumbSize.height-50}, {translateX:thumbSize.width/2 - 10,position:"absolute",bottom:0, borderRadius: this.getThumbOffset() / 2 }], source: isOther ? otherThumbImage : thumbImage });
        };
        /**
         * 刻度模块的渲染
         */
        this.renderMarks = () => {
            const { step, marks, min, max, thumbSize } = this.props;
            if (!this.showStep() || !marks) {
                return null;
            }
            const maxStep = Math.ceil(Math.abs((max - min) / step)) + 1;
            let currStep = 0;
            const markViewArr = [];
            while (maxStep > currStep) {
                if (React.isValidElement(marks[currStep])) {
                    markViewArr.push(marks[currStep]);
                }
                else {
                    markViewArr.push(React.createElement(View, { key: currStep, style: { width: thumbSize, alignItems: 'center' } },
                        React.createElement(Text, { style: styles.markItemText }, marks[currStep]),
                        React.createElement(View, { style: styles.markItemLine })));
                }
                currStep += 1;
            }
            return (React.createElement(View, { style: styles.markContainer }, markViewArr));
        };
        /**
         * 渲染滑块的toopTip提示
         */
        this.renderThumbToolTip = (isOther) => {
            const { showTip,thumbSize, renderTip } = this.props;
            if (!showTip) {
                return;
            }
            const { tip, otherTip } = this.state;
            return (React.createElement(View, { style: [
                    styles.tip,
                      { bottom:20 + (thumbSize - 30) / 2}
                ] },
                React.createElement(View, { key: 1, style: styles.tipContent }, renderTip ? renderTip(isOther ? otherTip : tip)
                    :
                        React.createElement(Text, { style: styles.tipText }, isOther ? otherTip : tip)),
                React.createElement(View, { key: 2, style: styles.tipIcon })));
        };
        /**
         * 滑动的起始和结束x值
         */
        this.getScrollRange = () => {
            const scrollLength = this.getScrollLength();
            return [0, scrollLength];
        };
        /**
         * 滑块渲染
         */
        this.renderThumb = (isOther) => {
            const { vertical, range } = this.props;
            if (isOther && !range)
                return;
            const { value, otherValue, thumbSize, otherThumbSize } = this.state;
            let currValue = value;
            let currThumb = thumbSize;
            let measureFn = this.measureThumb;
            if (isOther) {
                currValue = otherValue;
                currThumb = otherThumbSize;
                measureFn = this.measureOtherThumb;
            }

            const thumbLeft = this.getThumbLeft(currValue.__getValue());
            let thumbStyle = {
                transform: [{ translateX: thumbLeft+7.5 + (currThumb.width - 20) / 2 }, { translateY: -20 + (currThumb.width -50) / 2 }],
                alignItems: 'center',
            };
            if (vertical) {
                thumbStyle.transform = [{ translateX: 0 }, { translateY: thumbLeft }];
            }
            if (this.showAndroidTip) {
                return (React.createElement(Animated.View, { onLayout: measureFn, renderToHardwareTextureAndroid: true, style: [
                        styles.thumb,
                        thumbStyle,
                    ] },
                    this.renderThumbToolTip(isOther),
                    React.createElement(View, { style: [
                            currThumb,
                            { }
                        ] }, this.renderThumbImage(isOther))));
            }
            return (React.createElement(Animated.View, { onLayout: measureFn, renderToHardwareTextureAndroid: true, style: [
                    styles.thumb,
                    currThumb,
                    thumbStyle,
                ] },
                this.renderThumbToolTip(isOther),
                this.renderThumbImage(isOther)));
        };
        /**
         * 两个滑块值比较，滑块A的值是否大于B
         */
        this.compareValue = () => {
            const { range } = this.props;
            return range && this.getCurrentValue() >= this.getCurrentValue(true);
        };
        /**
         * 滑轨色值计算
         * 双滑块模式下，需要根据两个滑块的值大小结果互换色值
         * 垂直滑块模式下，因为滑块的渲染是从顶部计算的，所以滑块需要使用反向色值来实现从底部滑动的效果
         * 假设滑块A,B
         */
        this.getTrackColor = (isOther) => {
            const { minTrackColor, midTrackColor, maxTrackColor, range, vertical } = this.props;
            let activeColor = '';
            // 双滑块B
            if (isOther) {
                if (this.compareValue()) {
                    if (vertical) {
                        // 纵向双滑块A>=B B => midTrackColor
                        activeColor = midTrackColor;
                    }
                    else {
                        // 横向双滑块A>=B B => minTrackColor
                        activeColor = minTrackColor;
                    }
                }
                else {
                    if (vertical) {
                        // 纵向双滑块A<B B => trackColor
                        activeColor = maxTrackColor;
                    }
                    else {
                        // 横向双滑块A<B B => midTrackColor
                        activeColor = midTrackColor;
                    }
                }
                // 双滑块A
            }
            else if (range) {
                if (this.compareValue()) {
                    if (vertical) {
                        // 纵向双滑块A<B A => trackColor
                        activeColor = maxTrackColor;
                    }
                    else {
                        // 横向双滑块A<B A => midTrackColor
                        activeColor = midTrackColor;
                    }
                }
                else {
                    if (vertical) {
                        // 纵向双滑块A>=B A => midTrackColor
                        activeColor = midTrackColor;
                    }
                    else {
                        // 横向单滑块A>=B A => minTrackColor
                        activeColor = minTrackColor;
                    }
                }
                // 单滑块
            }
            else {
                if (vertical) {
                    // 纵向单滑块 A => trackColor
                    activeColor = maxTrackColor;
                }
                else {
                    // 横向单滑块 A => minTrackColor
                    activeColor = minTrackColor;
                }
            }
            return [activeColor];
        };
        /**
         * 默认滑块划过的滑轨
         */
        this.renderMinimumTrack = (isOther) => {
            const { disabled, range, vertical, trackWeight } = this.props;
            if (isOther && !range)
                return;
            const { value, otherValue } = this.state;
            let currValue = value;
            let minimumTrackColor = null;
            let currKey = 'minTrack';
            if (isOther) {
                currValue = otherValue;
                currKey = 'otherMinTrack';
            }
            const minimumTrackWidth = this.getThumbLeft(currValue.__getValue());
            // 滑轨颜色值设定
            const trackColors = this.getTrackColor(isOther);
            minimumTrackColor = trackColors[0];
            const minimumTrackStyle = {
                position: 'absolute',
                backgroundColor: minimumTrackColor
            };
            let trackStyle = null;
            if (vertical) {
                minimumTrackStyle.height = minimumTrackWidth;
                minimumTrackStyle.width = this.props.trackWeight;
                trackStyle = { marginVertical: this.getThumbOffset(isOther) / 2 };
            }
            else {
                minimumTrackStyle.height = this.props.trackWeight;
                minimumTrackStyle.width = minimumTrackWidth;
                trackStyle = { marginHorizontal: this.getThumbOffset(isOther) / 2 };
            }
            return (React.createElement(Animated.View, { key: currKey, renderToHardwareTextureAndroid: true, style: [{ borderRadius: trackWeight / 2 }, minimumTrackStyle, trackStyle] }));
        };
        this.getTrackStyle = () => {
            const { range, vertical, maxTrackColor, minTrackColor, trackWeight, thumbSize } = this.props;
            const trackStyle = { backgroundColor: maxTrackColor };
            let marginArr = ['marginLeft', 'marginRight', 'marginHorizontal', 'height'];
            const rest = thumbSize - trackWeight;
            const spacing = rest > 0 ? Math.ceil(rest / 2) : 0;
            if (vertical) {
                marginArr = ['marginTop', 'marginBottom', 'marginVertical', 'width'];
                trackStyle.flex = 1;
                trackStyle.alignItems = 'flex-start';
                trackStyle.backgroundColor = minTrackColor;
                trackStyle.marginHorizontal = spacing;
            }
            else {
                trackStyle.marginVertical = spacing;
            }
            // 样式处理
            if (range) {
                trackStyle[marginArr[0]] = this.getThumbOffset() / 2;
                trackStyle[marginArr[1]] = this.getThumbOffset(true) / 2;
            }
            else {
                trackStyle[marginArr[2]] = this.getThumbOffset() / 2;
            }
            trackStyle[marginArr[3]] = this.props.trackWeight;
            return trackStyle;
        };
        this.renderTracks = () => {
            const { vertical, trackWeight } = this.props;
            const trackStyle = this.getTrackStyle();
            // 如果value > oldValue，则代表两个滑块滑动位置互换，则更新渲染层级
            let tracks = [
                React.createElement(View, { style: [{ borderRadius: trackWeight / 2 }, trackStyle], onLayout: this.measureTrack })
            ];
            // vertical的值和this.compareValue()值相同时，次滑块轴在底层，反之主滑块轴在底层
            if (vertical === this.compareValue()) {
                tracks.push(this.renderMinimumTrack(true));
                tracks.push(this.renderMinimumTrack());
            }
            else {
                tracks.push(this.renderMinimumTrack());
                tracks.push(this.renderMinimumTrack(true));
            }
            return tracks;
        };
        this.state = {
            containerSize: { width: 0, height: 0 },
            trackSize: { width: 0, height: 0 },
            thumbSize: { width: props.thumbSize, height: props.thumbSize },
            otherThumbSize: { width: props.thumbSize, height: props.thumbSize },
            value: new Animated.Value(this.getValueByProps()),
            otherValue: new Animated.Value(this.getValueByProps(true)),
            tip: `${this.getValueByProps()}`,
            otherTip: `${this.getValueByProps(true)}`
        };
        this.isOther = false;
        this.showAndroidTip = this.props.showTip && Platform.OS === 'android';
    }
    componentWillMount() {
        this.panResponder = PanResponder.create({
            onStartShouldSetPanResponder: this.touchStart,
            onMoveShouldSetPanResponder: _ => false,
            onPanResponderGrant: this.pressStart,
            onPanResponderMove: this.lastMove,
            onPanResponderRelease: this.touchEnd,
            onPanResponderTerminationRequest: _ => false,
            onPanResponderTerminate: this.touchEnd
        });
    }
    componentWillReceiveProps(nextProps) {
        let newValue = 0;
        let newOtherValue = 0;
        const { range } = this.props;
        if (range && nextProps.value instanceof Array) {
            newValue = nextProps.value[0];
            newOtherValue = nextProps.value[1];
        }
        else {
            newValue = nextProps.value;
        }
        if (this.getValueByProps() !== newValue) {
            this.setCurrentValue(newValue);
        }
        if (range && this.getValueByProps(true) !== newOtherValue) {
            this.setCurrentValue(newOtherValue, range);
        }
    }
    render() {
        const { style, vertical } = this.props;
        return (React.createElement(View, { style: [
                { flexDirection: vertical ? 'row' : 'column' },
                style
            ] },
            this.renderMarks(),
            React.createElement(View, { style: {
                    alignItems: vertical ? 'center' : undefined,
                    justifyContent: vertical ? undefined : 'center'
                }, onLayout: this.measureContainer },
                this.renderTracks(),
                this.renderThumb(),
                this.renderThumb(true),
                React.createElement(View, Object.assign({ renderToHardwareTextureAndroid: true, style: styles.touchArea }, this.panResponder.panHandlers)))));
    }
}
Slider.defaultProps = {
    value: 0,
    min: 0,
    max: 1,
    step: 0,
    maxTrackColor: variables.mtdFillGray,
    minTrackColor: variables.mtdBrandPrimary,
    midTrackColor: variables.mtdBrandDanger,
    range: false,
    vertical: false,
    showTip: false,
    trackWeight: 5,
    thumbSize: 30
};
//# sourceMappingURL=Slider.js.map
