import _fromPairs from "lodash/fromPairs";
import _isEmpty from "lodash/isEmpty";
import _defaults from "lodash/defaults";
import _isFunction from "lodash/isFunction";
import _assign from "lodash/assign";

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

import React from "react";
import PropTypes from "prop-types";
import CustomPropTypes from "../victory-util/prop-types";
import Events from "../victory-util/events";
import Helpers from "../victory-util/helpers";
import Timer from "../victory-util/timer";

var VictorySharedEvents = function (_React$Component) {
  _inherits(VictorySharedEvents, _React$Component);

  function VictorySharedEvents(props) {
    _classCallCheck(this, VictorySharedEvents);

    var _this = _possibleConstructorReturn(this, (VictorySharedEvents.__proto__ || Object.getPrototypeOf(VictorySharedEvents)).call(this, props));

    _this.state = _this.state || {};
    _this.getScopedEvents = Events.getScopedEvents.bind(_this);
    _this.getEventState = Events.getEventState.bind(_this);
    _this.getTimer = _this.getTimer.bind(_this);
    _this.baseProps = _this.getBaseProps(props);
    return _this;
  }

  _createClass(VictorySharedEvents, [{
    key: "getChildContext",
    value: function getChildContext() {
      return {
        getTimer: this.getTimer
      };
    }
  }, {
    key: "componentWillReceiveProps",
    value: function componentWillReceiveProps(newProps) {
      this.baseProps = this.getBaseProps(newProps);
      var externalMutations = this.getExternalMutations(newProps, this.baseProps);
      this.applyExternalMutations(newProps, externalMutations);
    }
  }, {
    key: "getTimer",
    value: function getTimer() {
      if (this.context.getTimer) {
        return this.context.getTimer();
      }
      if (!this.timer) {
        this.timer = new Timer();
      }
      return this.timer;
    }
  }, {
    key: "getAllEvents",
    value: function getAllEvents(props) {
      var components = ["container", "groupComponent"];
      var componentEvents = Events.getComponentEvents(props, components);
      if (Array.isArray(componentEvents)) {
        return Array.isArray(props.events) ? componentEvents.concat.apply(componentEvents, _toConsumableArray(props.events)) : componentEvents;
      }
      return props.events;
    }
  }, {
    key: "applyExternalMutations",
    value: function applyExternalMutations(props, externalMutations) {
      if (!_isEmpty(externalMutations)) {
        var callbacks = props.externalEventMutations.reduce(function (memo, mutation) {
          memo = _isFunction(mutation.callback) ? memo.concat(mutation.callback) : memo;
          return memo;
        }, []);
        var compiledCallbacks = callbacks.length ? function () {
          callbacks.forEach(function (c) {
            return c();
          });
        } : undefined;
        this.setState(externalMutations, compiledCallbacks);
      }
    }
  }, {
    key: "getExternalMutations",
    value: function getExternalMutations(props, baseProps) {
      return !_isEmpty(props.externalEventMutations) ? Events.getExternalMutationsWithChildren(props.externalEventMutations, baseProps, this.state, Object.keys(baseProps)) : undefined;
    }
  }, {
    key: "getBaseProps",
    value: function getBaseProps(props) {
      var container = props.container;

      var children = React.Children.toArray(this.props.children);
      var childBaseProps = this.getBasePropsFromChildren(children);
      var parentBaseProps = container ? container.props : {};
      return _assign({}, childBaseProps, { parent: parentBaseProps });
    }
  }, {
    key: "getBasePropsFromChildren",
    value: function getBasePropsFromChildren(childComponents) {
      var iteratee = function (child, childName, parent) {
        if (child.type && _isFunction(child.type.getBaseProps)) {
          child = parent ? React.cloneElement(child, parent.props) : child;
          var _baseProps = child.props && child.type.getBaseProps(child.props);
          return _baseProps ? [[childName, _baseProps]] : null;
        } else {
          return null;
        }
      };

      var baseProps = Helpers.reduceChildren(childComponents, iteratee);
      return _fromPairs(baseProps);
    }
  }, {
    key: "getNewChildren",
    value: function getNewChildren(props, baseProps) {
      var _this2 = this;

      var events = props.events,
          eventKey = props.eventKey;

      var childNames = Object.keys(baseProps);
      var alterChildren = function (children) {
        return children.reduce(function (memo, child, index) {
          if (child.props.children) {
            return memo.concat(React.cloneElement(child, child.props, alterChildren(React.Children.toArray(child.props.children))));
          } else if (child.type && _isFunction(child.type.getBaseProps)) {
            var name = child.props.name || childNames.shift() || index;
            var childEvents = Array.isArray(events) && events.filter(function (event) {
              if (event.target === "parent") {
                return false;
              }
              return Array.isArray(event.childName) ? event.childName.indexOf(name) > -1 : event.childName === name || event.childName === "all";
            });
            var sharedEvents = {
              events: childEvents,
              // partially apply child name and baseProps,
              getEvents: function (evts, target) {
                return _this2.getScopedEvents(evts, target, name, baseProps);
              },
              // partially apply child name
              getEventState: function (key, target) {
                return _this2.getEventState(key, target, name);
              }
            };
            return memo.concat(React.cloneElement(child, _assign({ key: "events-" + name, sharedEvents: sharedEvents, eventKey: eventKey, name: name }, child.props)));
          } else {
            return memo.concat(child);
          }
        }, []);
      };
      var childComponents = React.Children.toArray(props.children);
      return alterChildren(childComponents);
    }
  }, {
    key: "getContainer",
    value: function getContainer(props, baseProps, events) {
      var _this3 = this;

      var children = this.getNewChildren(props, baseProps);
      var parents = Array.isArray(events) && events.filter(function (event) {
        return event.target === "parent";
      });
      var sharedEvents = parents.length > 0 ? {
        events: parents,
        // partially apply childName (null) and baseProps,
        getEvents: function (evts, target) {
          return _this3.getScopedEvents(evts, target, null, baseProps);
        },
        getEventState: this.getEventState
      } : null;
      var container = props.container || props.groupComponent;
      var role = container.type && container.type.role;
      var containerProps = container.props || {};
      var boundGetEvents = Events.getEvents.bind(this);
      var parentEvents = sharedEvents && boundGetEvents({ sharedEvents: sharedEvents }, "parent");
      var parentProps = _defaults({}, this.getEventState("parent", "parent"), containerProps, baseProps.parent, { children: children });
      var containerEvents = _defaults({}, Events.getPartialEvents(parentEvents, "parent", parentProps), containerProps.events);
      return role === "container" ? React.cloneElement(container, _assign({}, parentProps, { events: containerEvents })) : React.cloneElement(container, containerEvents, children);
    }
  }, {
    key: "render",
    value: function render() {
      var events = this.getAllEvents(this.props);
      if (events) {
        return this.getContainer(this.props, this.baseProps, events);
      }
      return React.cloneElement(this.props.container, { children: this.props.children });
    }
  }]);

  return VictorySharedEvents;
}(React.Component);

VictorySharedEvents.displayName = "VictorySharedEvents";
VictorySharedEvents.role = "shared-event-wrapper";
VictorySharedEvents.propTypes = {
  children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
  container: PropTypes.node,
  eventKey: PropTypes.oneOfType([PropTypes.array, PropTypes.func, CustomPropTypes.allOfType([CustomPropTypes.integer, CustomPropTypes.nonNegative]), PropTypes.string]),
  events: PropTypes.arrayOf(PropTypes.shape({
    childName: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
    eventHandlers: PropTypes.object,
    eventKey: PropTypes.oneOfType([PropTypes.array, PropTypes.func, CustomPropTypes.allOfType([CustomPropTypes.integer, CustomPropTypes.nonNegative]), PropTypes.string]),
    target: PropTypes.string
  })),
  externalEventMutations: PropTypes.arrayOf(PropTypes.shape({
    callback: PropTypes.function,
    childName: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
    eventKey: PropTypes.oneOfType([PropTypes.array, CustomPropTypes.allOfType([CustomPropTypes.integer, CustomPropTypes.nonNegative]), PropTypes.string]),
    mutation: PropTypes.function,
    target: PropTypes.oneOfType([PropTypes.string, PropTypes.array])
  })),
  groupComponent: PropTypes.node
};
VictorySharedEvents.defaultProps = {
  groupComponent: React.createElement("g", null)
};
VictorySharedEvents.contextTypes = {
  getTimer: PropTypes.func
};
VictorySharedEvents.childContextTypes = {
  getTimer: PropTypes.func
};
export default VictorySharedEvents;