'use strict';

var _interopRequire = function (obj) { return obj && obj.__esModule ? obj['default'] : obj; };

var _objectWithoutProperties = function (obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; };

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

var _inherits = function (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) subClass.__proto__ = superClass; };

/**
 * Flux Component
 *
 * Component interface to reactComponentMethods module.
 *
 * Children of FluxComponent are given access to the flux instance via
 * `context.flux`. Use this near the top of your app hierarchy and all children
 * will have easy access to the flux instance (including, of course, other
 * Flux components!):
 *
 * <FluxComponent flux={flux}>
 *    ...the rest of your app
 * </FluxComponent>
 *
 * Now any child can access the flux instance again like this:
 *
 * <FluxComponent>
 *    ...children
 * </FluxComponent>
 *
 * We don't need the flux prop this time because flux is already part of
 * the context.
 *
 * Additionally, immediate children are given a `flux` prop.
 *
 * The component has an optional prop `connectToStores`, which is passed to
 * `this.connectToStores` and used to set the initial state. The component's
 * state is injected as props to the child components.
 *
 * The practical upshot of all this is that fluxMixin, state changes, and
 * context are now simply implementation details. Among other things, this means
 * you can write your components as plain ES6 classes. Here's an example:
 *
 * class ParentComponent extends React.Component {
 *
 *   render() {
 *     <FluxComponent connectToStores="fooStore">
 *       <ChildComponent />
 *     </FluxComponent>
 *   }
 *
 * }
 *
 * ChildComponent in this example has prop `flux` containing the flux instance,
 * and props that sync with each of the state keys of fooStore.
 */

var _React = require('react/addons');

var React = _interopRequire(_React);

var _instanceMethods$staticProperties = require('./reactComponentMethods');

var _assign = require('object-assign');

var assign = _interopRequire(_assign);

var FluxComponent = (function (_React$Component) {
  function FluxComponent(props, context) {
    _classCallCheck(this, FluxComponent);

    _React$Component.call(this, props, context);

    this.initialize();

    this.state = this.connectToStores(props.connectToStores, props.stateGetter);

    this.wrapChild = this.wrapChild.bind(this);
  }

  _inherits(FluxComponent, _React$Component);

  FluxComponent.prototype.wrapChild = function wrapChild(child) {
    return React.addons.cloneWithProps(child, this.getChildProps());
  };

  FluxComponent.prototype.getChildProps = function getChildProps() {
    var _props = this.props;
    var children = _props.children;
    var render = _props.render;
    var connectToStores = _props.connectToStores;
    var stateGetter = _props.stateGetter;
    var flux = _props.flux;

    var extraProps = _objectWithoutProperties(_props, ['children', 'render', 'connectToStores', 'stateGetter', 'flux']);

    return assign({ flux: this.getFlux() }, // TODO: remove in next major version
    this.state, extraProps);
  };

  FluxComponent.prototype.render = (function (_render) {
    function render() {
      return _render.apply(this, arguments);
    }

    render.toString = function () {
      return render.toString();
    };

    return render;
  })(function () {
    var _props2 = this.props;
    var children = _props2.children;
    var render = _props2.render;

    if (typeof render === 'function') {
      return render(this.getChildProps(), this.getFlux());
    }

    if (!children) return null;

    if (!Array.isArray(children)) {
      var child = children;
      return this.wrapChild(child);
    } else {
      return React.createElement(
        'span',
        null,
        React.Children.map(children, this.wrapChild)
      );
    }
  });

  return FluxComponent;
})(React.Component);

assign(FluxComponent.prototype, _instanceMethods$staticProperties.instanceMethods);

assign(FluxComponent, _instanceMethods$staticProperties.staticProperties);

module.exports = FluxComponent;