import React, { Component } from 'react';
import ReactDOM from "react-dom";
import PropTypes from "prop-types";
import * as d3 from 'd3';

class LineChart extends Component {
    static propTypes = {
        yLabel: PropTypes.string,
        xLabel: PropTypes.string,
        width: PropTypes.number.isRequired,
        height: PropTypes.number.isRequired,
        data: PropTypes.array.isRequired,
    };

    render() {
        const margin = { top: 50, right: 40, bottom: 10, left: 50 };
        const padding = { top: 10, right: 10, bottom: 10, left: 10 };
        const x = this.props.width;
        const y = this.props.height;
        const width = x - margin.right - margin.left;
        const height = padding.top + padding.right + padding.bottom + padding.left + y + margin.top + margin.bottom;

        const parseTime = d3.timeParse("%Y-%m-%d %H:%M:%S");

        const plotData = this.props.data.map(({month, value}) => ({
            x: parseTime(month),
            y: parseFloat(value) / 1000,
        }));

        const xExtent = d3.extent(plotData, ({x}) => x);
        const yExtent = d3.extent(plotData, ({y}) => y);

        yExtent[1] += 0.15 * (yExtent[1] - yExtent[0]);

        const xScale = d3
            .scaleTime()
            .domain(xExtent)
            .range([0, width]);

        const yScale = d3
            .scaleLinear()
            .domain(yExtent)
            .range([height, 0]);

        // Line generator.
        const line = d3.line()
            .x(({x}) => xScale(x)) 
            .y(({y}) => yScale(y))
            .curve(d3.curveMonotoneX);

        const yAxis = d3
            .axisLeft(yScale)
            .tickSizeOuter(0)
            .tickSizeInner(-width);

        const xAxis = d3.axisBottom(xScale)
            .tickFormat(d3.timeFormat("%m/%Y"));

        return <svg style={{
                marginTop: margin.top + "px",
                marginLeft: margin.left + "px",
                width: width + 100,
                height: height + 100,
            }}>
            <text className="yLabel" y={(height + 100) / 2}>{this.props.yLabel}</text>
            <text className="xLabel" y={height + 100} x={width / 2}>{this.props.xLabel}</text>
            <g style={{
                transform: `translate(${margin.left}px, ${margin.top}px)`,
            }}>
                <Axis h={height} axis={yAxis} axisType="y" />
                <Axis h={height} axis={xAxis} axisType="x"/>
                <path
                    className="line"
                    stroke="red"
                    fill="none"
                    strokeLinecap="round"
                    strokeWidth="2"
                    d={line(plotData)} />
            </g>
        </svg>;
    }
}

class Axis extends React.Component {
    static propTypes = {
        h: PropTypes.number,
        axis: PropTypes.func,
        axisType: PropTypes.oneOf(['x','y'])
    };
 
    componentDidUpdate() {
        this.renderAxis();
    }
    
    componentDidMount() {
        this.renderAxis();
    }
    
    renderAxis() {
        const node = ReactDOM.findDOMNode(this);
        d3.select(node).call(this.props.axis);
    }

    render() {
        const translate = "translate(0,"+(this.props.h)+")";
 
        return (
            <g className="axis" transform={this.props.axisType=='x'?translate:""}></g>
        );
    }
}

export default LineChart;