'use strict';

Object.defineProperty(exports, '__esModule', {
  value: true
});

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 _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }

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

var _refsStack = require('./refs-stack');

var _refsStack2 = _interopRequireDefault(_refsStack);

// Instances of this class interface with an [extension mechanism](https://github.com/Matt-Esch/virtual-dom/blob/master/docs/widget.md)
// in the `virtual-dom` library that allows us to manually manage specific DOM
// nodes within a `virtual-dom` tree. It is designed to wrap a *component*,
// which is just a plain JavaScript object that implements a simple interface.

var ComponentWidget = (function () {
  function ComponentWidget(componentConstructor, properties, children) {
    _classCallCheck(this, ComponentWidget);

    this.type = 'Widget';
    this.componentConstructor = componentConstructor;
    this.properties = properties;
    this.children = children;

    if (this.properties && this.properties.key) {
      this.key = this.properties.key;
    }
  }

  // The `virtual-dom` library expects this method to return a DOM node. It
  // calls this method when creating a DOM tree for the first time or when
  // updating a DOM tree via patch. We create an instance of the component based
  // on the constructor we saved when the widget was created, deal with the
  // `ref` property if it is present, then return the component's associated DOM
  // element.

  _createClass(ComponentWidget, [{
    key: 'init',
    value: function init() {
      this.component = new this.componentConstructor(this.properties, this.children);
      if (this.properties && this.properties.ref && _refsStack2['default'].length > 0) {
        _refsStack2['default'][_refsStack2['default'].length - 1][this.properties.ref] = this.component;
      }
      return this.component.element;
    }

    // The `virtual-dom` library calls this method when applying updates to the
    // DOM by `diff`ing two virtual trees and then `patch`ing an element.
    //
    // If a widget with the same `componentConstructor` occurs at the same
    // location of the tree, we attempt to update the underlying component by
    // calling the `update` method with the component's new properties and
    // children. If the component doesn't have an `update` method or if the
    // widgets have *different* component constructors, we destroy the old
    // component and build a new one in its place.
  }, {
    key: 'update',
    value: function update(oldWidget, oldElement) {
      var oldRef = undefined,
          newRef = undefined;

      if (oldWidget.properties && oldWidget.properties.ref) {
        oldRef = oldWidget.properties.ref;
      }

      if (this.properties && this.properties.ref) {
        newRef = this.properties.ref;
      }

      if (this.componentConstructor === oldWidget.componentConstructor) {
        this.component = oldWidget.component;

        // If the ref properties have changed, delete the old reference and create
        // a new reference to this widget's component.
        if (newRef !== oldRef && _refsStack2['default'].length > 0) {
          delete _refsStack2['default'][_refsStack2['default'].length - 1][oldRef];
          _refsStack2['default'][_refsStack2['default'].length - 1][newRef] = this.component;
        }

        this.component.update(this.properties, this.children);
      } else {
        // If `ref` properties are defined, delete the reference to the old
        // component. Only do this if the reference name changed because otherwise
        // the new reference (created in the call to `this.init`) will overwrite
        // the old one anyway.
        if (_refsStack2['default'].length > 0) {
          if (newRef !== oldRef) {
            delete _refsStack2['default'][_refsStack2['default'].length - 1][oldRef];
          }
        }

        // Build a new component instance by calling `init`.
        this.init();
      }

      // Return the element so virtual-dom will replace the element if it changed
      return this.component.element;
    }
  }, {
    key: 'destroy',
    value: function destroy() {
      if (typeof this.component.destroy === 'function') {
        this.component.destroy();
      }
    }
  }]);

  return ComponentWidget;
})();

exports['default'] = ComponentWidget;
module.exports = exports['default'];