'use strict';

const React = require('react'),
    _ = require('lodash'),
    helpers = require('./helpers');

/**
 * Helps to use mouse events. For now supports only "`onMouseMove`" and "`onMouseLeave`".
 *
 * This component will be improved and simplified in the future.
 *
 * @example ../docs/examples/Handlers.md
 */
const Handlers = React.createClass({

    displayName: 'Handlers',

    propTypes: {
        className: React.PropTypes.string,
        series: React.PropTypes.array,
        sensitivity: React.PropTypes.number,
        optimized: React.PropTypes.bool,
        distance: React.PropTypes.oneOf(['x', 'y']),
        onMouseMove: React.PropTypes.oneOfType([React.PropTypes.func, React.PropTypes.bool]),
        onMouseLeave: React.PropTypes.oneOfType([React.PropTypes.func, React.PropTypes.bool]),
        scaleX: React.PropTypes.object,
        scaleY: React.PropTypes.object,
        layerWidth: React.PropTypes.oneOfType([React.PropTypes.number, React.PropTypes.string]),
        layerHeight: React.PropTypes.oneOfType([React.PropTypes.number, React.PropTypes.string])
    },

    // init

    getDefaultProps() {
        return {
            sensitivity: Infinity,
            optimized: true
        };
    },

    // helpers

    updatePoint0() {
        let rect = this.rect.getBoundingClientRect();
        this.left = rect.left;
        this.top = rect.top;
        this.width = rect.width;
        this.height = rect.height;
    },

    updateScales() {
        let {props} = this;
        let {scaleX, scaleY} = props;
        this.x = scaleX.factory(props);
        this.y = scaleY.factory(props);
        this.scaleX = scaleX.factory(props);
        this.scaleY = scaleY.factory(props);

        let xDomain = this.x.domain();
        let xRange = this.x.range();
        this.x.domain(xRange);
        this.x.range(xDomain);

        let yDomain = this.y.domain();
        let yRange = this.y.range();
        this.y.domain(yRange);
        this.y.range(yDomain);

        this.ratio = Math.abs((this.y(1) - this.y(0)) / (this.x(1) - this.x(0)));
    },

    // handlers

    handleMouseMove(event) {
        this.updatePoint0();

        let {clientX, clientY} = event;
        let {left, top, props} = this;
        let {onMouseMove, series, sensitivity, optimized, layerWidth, layerHeight} = props;
        let realX = (clientX - left) * layerWidth / this.width;
        let realY = (clientY - top) * layerHeight / this.height;
        let x = this.x(realX);
        let y = this.y(realY);

        let closestPoints = [];
        let minDistance = sensitivity;
        _.forEach(series, (series, seriesIndex) => {
            _.forEach(series.data, (point, pointIndex) => {
                let distance;
                switch (props.distance) {
                case 'x':
                    distance = Math.abs(point.x - x);
                    break;
                case 'y':
                    distance = Math.abs(point.y - y);
                    break;
                default:
                    distance = Math.sqrt(
                        Math.pow(Math.abs(point.x - x) * (this.ratio || 1), 2) +
                        Math.pow(Math.abs(point.y - y), 2)
                    );
                    break;
                }

                if (!optimized || distance <= minDistance) {
                    minDistance = distance;
                    closestPoints.push({
                        seriesIndex,
                        pointIndex,
                        point,
                        distance
                    });
                }
            });
        });
        closestPoints = _.sortBy(closestPoints, 'distance');

        onMouseMove({
            clientX: realX,
            clientY: realY,
            scaleX: this.scaleX,
            scaleY: this.scaleY,
            x,
            y,
            closestPoints,
            originalEvent: event
        });
    },

    // render

    render() {
        let {props} = this;
        let {className, scaleX, scaleY, layerWidth, layerHeight} = props;
        let {onMouseMove, onMouseLeave} = props;

        this.updateScales();

        let children = helpers.proxyChildren(
            props.children,
            props,
            {
                layerWidth,
                layerHeight,
                scaleX,
                scaleY
            }
        );

        return <g
            className={className}
            onMouseMove={onMouseMove && this.handleMouseMove}
            onMouseLeave={onMouseLeave}>
            <rect
                ref={ref => this.rect = ref}
                x={0} y={0} width={layerWidth} height={layerHeight}
                fill='transparent' stroke='transparent'/>
            {children}
        </g>;
    }

});

module.exports = Handlers;

@@ -159,16 +159,29 @@
 rts only
+ %22%60onClick%60%22,
  %22%60onMou
@@ -211,16 +211,16 @@
 eave%60%22.%0A
-
  *%0A * Th
@@ -629,24 +629,114 @@
 'x', 'y'%5D),%0A
+        onClick: React.PropTypes.oneOfType(%5BReact.PropTypes.func, React.PropTypes.bool%5D),%0A
         onMo
@@ -2219,18 +2219,28 @@
 ouse
-Move
+Event
 (event
+, handler
 ) %7B%0A
@@ -2361,29 +2361,16 @@
    let %7B
-onMouseMove, 
 series, 
@@ -3788,27 +3788,23 @@
         
-onMouseMove
+handler
 (%7B%0A     
@@ -4026,24 +4026,214 @@
 %7D);%0A    %7D,%0A%0A
+    handleMouseMove(event) %7B%0A        this.handleMouseEvent(event, this.props.onMouseMove);%0A    %7D,%0A%0A    handleClick(event) %7B%0A        this.handleMouseEvent(event, this.props.onClick);%0A    %7D,%0A%0A
     // rende
@@ -4365,16 +4365,25 @@
    let %7B
+onClick, 
 onMouseM
@@ -4696,16 +4696,16 @@
 turn %3Cg%0A
-
         
@@ -4730,16 +4730,66 @@
 ssName%7D%0A
+            onClick=%7BonClick && this.handleClick%7D%0A
         

Allow providing a handler for click events