var Element = require('./Element')
var mapValues = require('./utils/mapValues')
var createClass = require('create-react-class')

function withFauxDOM (WrappedComponent) {
  // use inheritance inversion to access and extend WrappedComponent's
  // state and lifecycle/class methods. More details on this technique at
  // https://medium.com/@franleplant/react-higher-order-components-in-depth-cf9032ee6c3e

  function applySuper (name, args) {
    var fn = WrappedComponent.prototype[name]

    if (typeof fn === 'function') {
      fn.apply(this, args)
    }
  }

  var WithFauxDOM = createClass({
    componentWillMount: function () {
      applySuper('componentWillMount')
      this.connectedFauxDOM = {}
      this.animateFauxDOMUntil = 0
    },

    componentWillUnmount: function () {
      applySuper('componentWillUnmount')
      this.stopAnimatingFauxDOM()
    },

    connectFauxDOM: function (node, name, discardNode) {
      if (!this.connectedFauxDOM[name] || discardNode) {
        this.connectedFauxDOM[name] = typeof node !== 'string' ? node : new Element(node)
        setTimeout(this.drawFauxDOM)
      }
      return this.connectedFauxDOM[name]
    },

    drawFauxDOM: function () {
      var virtualDOM = mapValues(this.connectedFauxDOM, function (n) {
        return n.toReact()
      })
      this.setState(virtualDOM)
    },

    animateFauxDOM: function (duration) {
      this.animateFauxDOMUntil = Math.max(Date.now() + duration, this.animateFauxDOMUntil)
      if (!this.fauxDOMAnimationInterval) {
        this.fauxDOMAnimationInterval = setInterval(function () {
          if (Date.now() < this.animateFauxDOMUntil) {
            this.drawFauxDOM()
          } else {
            this.stopAnimatingFauxDOM()
          }
        }.bind(this), 16)
      }
    },

    stopAnimatingFauxDOM: function () {
      this.fauxDOMAnimationInterval = clearInterval(this.fauxDOMAnimationInterval)
      this.animateFauxDOMUntil = 0
    },

    isAnimatingFauxDOM: function () {
      return !!this.fauxDOMAnimationInterval
    },

    render: function () {
      return WrappedComponent.prototype.render()
    }
  })

  WithFauxDOM.displayName = ['WithFauxDOM(', getDisplayName(WrappedComponent), ')'].join('')

  return WithFauxDOM
}

function getDisplayName (WrappedComponent) {
  return WrappedComponent.displayName || WrappedComponent.name || 'Component'
}

module.exports = withFauxDOM

@@ -427,16 +427,25 @@
 r (name,
+ thisArg,
  args) %7B
@@ -441,24 +441,24 @@
 rg, args) %7B%0A
-
     var fn =
@@ -534,16 +534,23 @@
 %7B%0A      
+return 
 fn.apply
@@ -554,16 +554,19 @@
 ply(this
+Arg
 , args)%0A
@@ -681,24 +681,41 @@
 ntWillMount'
+, this, arguments
 )%0A      this
@@ -812,32 +812,32 @@
 : function () %7B%0A
-
       applySuper
@@ -859,16 +859,33 @@
 Unmount'
+, this, arguments
 )%0A      
@@ -2138,42 +2138,44 @@
 urn 
-Wr
 app
-edComponent.prototype.render(
+lySuper('render', this, arguments
 )%0A  

Improve calls to applySuper, use in render