import React, {Component, PropTypes} from 'react';
import ReactDOM from 'react-dom';
import {connect, Provider} from 'react-redux';
import {bindActionCreators} from 'redux';
import {fromJS} from 'immutable';
import {addLocaleData, IntlProvider, intlShape, injectIntl} from 'react-intl';
import {injectSpark} from '@ciscospark/react-redux-spark';

import createRootReducer from './root-reducer';
import initStore from './store';
import {removeWidget} from './actions';
import registerWidget from './browser-globals';
import setupDataAPI from './data-api';


function getDisplayName(C) {
  return C.displayName || C.name || `C`;
}

const defaultOptions = fromJS({
  intl: {
    messages: null,
    locale: `en`
  },
  browserGlobals: true,
  dataAPI: true,
  reducers: {},
  propTypes: {
    accessToken: PropTypes.string,
    injectProvider: PropTypes.bool,
    onEvent: PropTypes.func,
    spark: PropTypes.object,
    store: PropTypes.object
  }
});

/**
 * Constructs a connected component with necessary redux modules
 * @param {String} widgetName Unique name for widget, camel cased
 * @param  {Object} Widget React container for the widget
 * @param  {Object} [options={}] Options matching format of defaultOptions above
 * @returns {Object} React Component
 */
export default function constructSparkWidget(widgetName, Widget, options = {}) {
  let widgetEl;
  const widgetOptions = defaultOptions.mergeDeep(options);
  const reducers = widgetOptions.get(`reducers`);
  const allowedPropTypes = widgetOptions.get(`propTypes`).toJS();
  // Setup Reducers
  const rootReducer = createRootReducer(reducers.toJS());

  /**
   * Injects widget into DOM
   * @param  {DOMNode} element DOM Element or Node where widget will inject
   * @param  {Object} props Any props that should be passed to widget
   * @returns {DOMNode} DOM Element where widget is rendered
   */
  function initSparkWidget(element, props) {
    // Filter props based on options passed to constructor
    let filteredProps = {};
    const allowedProps = Object.keys(allowedPropTypes);
    if (allowedProps === `all`) {
      filteredProps = props;
    }
    else {
      Object.keys(props).forEach((k) => {
        if (allowedProps.includes(k)) {
          filteredProps[k] = props[k];
        }
      });
    }

    ReactDOM.render(
      <SparkWidget {...filteredProps} />, element
    );

    widgetEl = element;
    return element;
  }

  function removeSparkWidget(el) {
    ReactDOM.unmountComponentAtNode(el);
  }

  const registerTuple = [widgetName, initSparkWidget, removeSparkWidget];

  // Setup Browser globals for widget
  if (widgetOptions.get(`browserGlobals`)) {
    registerWidget(...registerTuple);
  }

  // Setup Data API
  if (widgetOptions.get(`dataAPI`)) {
    setupDataAPI(...registerTuple);
  }


  // Setup React-intl
  const intlMessages = widgetOptions.getIn([`intl`, `messages`]).toJS();
  const intlLocale = widgetOptions.getIn([`intl`, `locale`]);
  if (intlMessages) {
    // eslint-disable-next-line global-require
    const localeData = require(`react-intl/locale-data/${intlLocale}`);
    addLocaleData(localeData);
    allowedPropTypes.intl = intlShape;
  }

  let WidgetComponent = injectSpark(Widget);

  if (intlMessages) {
    WidgetComponent = injectIntl(WidgetComponent);
  }

  // Connect widget to Redux store
  // Will prefer to return passed props than what's stored in state
  WidgetComponent = connect(
    (state, ownProps) => Object.assign({}, state, ownProps),
    (dispatch) => bindActionCreators({removeWidget}, dispatch)
  )(WidgetComponent);


  /**
   * Spark Widget HOC
   * @type {class}
   * @extends {Component}
   */
  class SparkWidget extends Component {

    constructor(props) {
      super(props);
      this.el = widgetEl;
      this.handleEvent = this.handleEvent.bind(this);
    }

    shouldComponentUpdate() {
      return true;
    }

<<<<<<< HEAD
    handleEvent(name, data) {
      const {onEvent} = this.props;
      if (typeof onEvent === `function`) {
        this.props.onEvent(name, data);
      }
    }

=======
>>>>>>> master
    render() {
      const {
        store,
        injectProvider
      } = this.props;
      let widgetStore = store;
      if (injectProvider && !widgetStore) {
        widgetStore = initStore(rootReducer);
      }

      let widget = <WidgetComponent {...this.props} onEvent={this.handleEvent} />;

      if (widgetStore && injectProvider) {
        widget = <Provider store={widgetStore}>{widget}</Provider>;
      }

      if (intlMessages) {
        widget = ( // eslint-disable-line no-extra-parens
          <IntlProvider locale={intlLocale} messages={intlMessages} >
            {widget}
          </IntlProvider>
        );
      }

      return widget;
    }
  }

  const injectedProps = {
    removeWidget: PropTypes.func
  };

  SparkWidget.propTypes = {
    ...injectedProps,
    ...allowedPropTypes
  };

  SparkWidget.defaultProps = {
    injectProvider: true
  };

  SparkWidget.displayName = `SparkWidget(${getDisplayName(Widget)})`;
  SparkWidget.Widget = Widget;

  return SparkWidget;
}

@@ -3874,21 +3874,8 @@
  %7D%0A%0A
-%3C%3C%3C%3C%3C%3C%3C HEAD%0A
     
@@ -4038,31 +4038,8 @@
  %7D%0A%0A
-=======%0A%3E%3E%3E%3E%3E%3E%3E master%0A
     

Remove bad merge