import React from 'react';
import { View, StyleSheet } from 'react-native';
import Svg, { Polyline, Text, Circle } from 'react-native-svg';
import { connect } from 'react-redux';


function computeTickMarks(largest, mostTicks) {
    const minimum = largest / mostTicks
    const magnitude = 10 ** Math.floor(Math.log10(minimum))
    const residual = minimum / magnitude
    let tickInterval = 0;
    if (residual > 5)
        tickInterval = 10 * magnitude;
    else if (residual > 2)
        tickInterval = 5 * magnitude;
    else if (residual > 1)
        tickInterval = 2 * magnitude;
    else
        tickInterval = magnitude;

    let result = [];
    let nextTick = tickInterval;
    while (nextTick < largest) {
        result.push(nextTick);
        nextTick += tickInterval;
    }
    return result;
}

const Graph = props => {
    const graphHeight = 100;
    const numPoints = 300;
    const yLabelSpace = 40;
    const graphWidth = numPoints + yLabelSpace;
    const minKgScale = 4; // scale such that upper graph value is n kg

    const data = props.data.slice(-numPoints);
    const maxValueDeviceCoord = data.reduce((running, x) => Math.max(x, running), minKgScale / props.kgFactor);
    const maxValueKg = Math.max(maxValueDeviceCoord * props.kgFactor, minKgScale);

    const devCoordToSvgX = x => yLabelSpace + x;
    const devCoordToSvgY = y => graphHeight - (y * 100 / maxValueDeviceCoord);
    const dataInKgToSvgCoordX = devCoordToSvgX;
    const dataInKgToSvgCoordY = y => devCoordToSvgY(y / props.kgFactor);

    const coordStr = data.map((element, i) => `${devCoordToSvgX(i)}, ${devCoordToSvgY(element)}`).join(" ");
    const ticks = computeTickMarks(maxValueKg * 0.9, 4);
    let viewBox = `0 0 ${graphWidth} ${graphHeight}`;

    const cutOffIndex = Math.max(0, props.data.size - numPoints);
    const peaksToDisplay = props.peaks.filter(p => p > cutOffIndex)
    const peaksXCoords = peaksToDisplay.map(p => devCoordToSvgX(p - cutOffIndex));
    const peaksYCoords = peaksToDisplay.map(p => devCoordToSvgY(props.data.get(p)));

    return (
        <View style={{ aspectRatio: graphWidth / graphHeight }}>
            <Svg height="100%" width="100%" viewBox={viewBox} preserveAspectRatio="none" >
                <Polyline
                    points={coordStr}
                    stroke="black"
                    strokeWidth="2"
                    strokeLinejoin="round"
                    fill="none"
                />
                {ticks.map(tick => (
                    <React.Fragment key={`fragment${tick}`} >
                        <Polyline
                            points={`${yLabelSpace},  ${dataInKgToSvgCoordY(tick)} ${graphWidth}, ${dataInKgToSvgCoordY(tick)}`}
                            stroke="black"
                            key={`line${tick}`}
                            strokeWidth="1"
                            strokeDasharray="5,5"
                            strokeLinejoin="round"
                            fill="none"
                        />
                        <Text x="5" y={`${dataInKgToSvgCoordY(tick)}`}
                            alignmentBaseline="center"
                            key={`label${tick}`}
                            fontSize="9pt">{tick} kg </Text>
                    </React.Fragment>
                )
                )}
                {peaksXCoords.zip(peaksYCoords).map(peak => (
                    <Circle
                        cx={peak[0]}
                        key={`peak${peak[0]}`}
                        stroke="black"
                        fill="black"
                        cy={peak[1]}
                        r="3"
                    />
                ))}
            </Svg>
        </View>
    );
};


const mapStateToProps = (state) => {
    return {
        data: state.deviceState.measurements,
        kgFactor: state.settings.analysis.kgFactor,
        peaks: state.deviceState.analysis.peaks,
    };
};

export default connect(mapStateToProps)(Graph);
