import React, {Component, PropTypes} from 'react';
import Plotly from 'plotly.js';
import {omit, map} from 'ramda';

const filterEventData = (eventData) => {
    // Create a new object
    return {
        points: map(omit(
            /*
             * remove figure objects from the event data since it's so big
             * (and most likely redudant for the user on the backend).
             * layout and fullLayout may not actually be in points,
             * just including them to be safe.
             */
            ['data', 'fullData', 'layout', 'fullLayout']), eventData.points
        )
    };
};

export default class PlotlyGraph extends Component {
    constructor(props) {
        super(props);
        this.bindEvents = this.bindEvents.bind(this);
    }

    plot(props) {
        const {id, figure} = props;
        return Plotly.newPlot(id, figure).then(() => {
            this.bindEvents(props);
        });
    }

    bindEvents(props) {
        const {id, fireEvent, valueChanged} = props;

        // Get DOM node to call jQuery-provided `on` event binder.
        const gd = document.getElementById(id);

        gd.on('plotly_click', (eventData) => {
            const clickData = filterEventData(eventData);
            if (valueChanged) {
                valueChanged({clickData});
            }
            if (fireEvent) fireEvent({event: 'click'});
        });
        gd.on('plotly_hover', (eventData) => {
            const hoverData = filterEventData(eventData);
            if (valueChanged) valueChanged({hoverData});
            if (fireEvent) fireEvent({event: 'hover'})
        });
        gd.on('plotly_selected', (eventData) => {
            const selectedData = filterEventData(eventData);
            if (valueChanged) valueChanged({selectedData});
            if (fireEvent) fireEvent({event: 'selected'});
        });
        // TODO - Is there a zoom event?
    }

    componentDidMount() {
        this.plot(this.props).then(() => {
            window.addEventListener('resize', () => {
                Plotly.Plots.resize(document.getElementById(this.props.id));
            });
        });
    }

    componentWillUnmount() {
        if (this.eventEmitter) {
            this.eventEmitter.removeAllListeners();
        }
    }

    shouldComponentUpdate() {
        // Never re-render after initialization, let Plotly.js own the DOM node.
        return false;
    }

    componentWillReceiveProps(nextProps) {
        // TODO optimize this check
        const figureChanged = JSON.stringify(this.props.figure) !== JSON.stringify(nextProps.figure)

        /*
         * Rebind events in case fireEvent or valueChanged
         * wasn't defined on initial render
         * TODO - Is it safe to rebind events?
         */
        const shouldBindEvents = (
            (!this.props.valueChanged && nextProps.valueChanged) ||
            (!this.props.fireEvent && nextProps.fireEvent)
        );
        if (figureChanged) {
            this.plot(nextProps);
        } else if (shouldBindEvents) {
            this.bindEvents(nextProps);
        }
    }

    render(){
        const {style, id} = this.props

        return (
            <div
                id={id}
                style={style}
            />
        );
    }
}

PlotlyGraph.propTypes = {
    /**
     * Data from latest click event
     */
    clickData: PropTypes.object,

    /**
     * Data from latest hover event
     */
    hoverData: PropTypes.object,

    /**
     * Data from latest select event
     */
    selectedData: PropTypes.object,

    /**
     * Data from latest zoom event
     */
    zoomData: PropTypes.object,

    /**
     * Plotly `figure` object. See schema:
     * https://plot.ly/javascript/reference
     */
    figure: PropTypes.object,

    /**
     * Generic style overrides on the plot div
     */
    style: PropTypes.object,

    /**
     * Function that updates the state tree.
     */
    valueChanged: PropTypes.func,

    /**
     * Function that fires events
     */
    fireEvent: PropTypes.func
}

PlotlyGraph.defaultProps = {
    clickData: null,
    hoverData: null,
    selectedData: null,
    zoomData: null,
    figure: {data: [], layout: {}},
    layout: {}
};

@@ -88,17 +88,35 @@
 rt %7B
-omit, map
+contains, filter, map, type
 %7D fr
@@ -221,69 +221,70 @@
     
-points: map(omit(%0A            /*%0A             * remove figure
+/*%0A         * remove %60data%60, %60layout%60, %60xaxis%60, etc%0A         *
  obj
@@ -318,12 +318,15 @@
 nce 
-it's
+they're
  so 
@@ -342,137 +342,95 @@
     
-   
- 
 * 
-(
 and 
-most likely redudant for the user on the backend).%0A             * layout and fullLayout may not actually be in
+cause JSON stringify ciricular structure errors.%0A         */%0A       
  points
-,
+: map(
 %0A   
@@ -442,115 +442,102 @@
     
- * just including them to be safe.%0A             */%0A            %5B'data', 'fullData', 'layout', 'fullLayout'%5D
+filter(function(o) %7B%0A                return !contains(type(o), %5B'Object', 'Array'%5D)%0A         %7D
 ), e
@@ -551,25 +551,16 @@
 a.points
-%0A        
 )%0A    %7D;

remove `xaxis`, and `yaxis` from event data too