import { select } from 'd3-selection';

const setInstance = (node, value) => { node.__instance__ = value; }; // no operation
const getInstance = node => node.__instance__;
const noop = () => {};

export default function (tagName, className) {
  let create = noop;
  let render = noop;
  let destroy = noop;
  let key;

  function component(selection, data, context) {
    const instances = (selection.nodeName ? select(selection) : selection)
      .selectAll(mine)
      .data(dataArray(data, context), key);
    instances
      .exit()
        .each(destroyInstance);
    return instances
      .enter().append(tagName)
        .attr('class', className)
        .each(createInstance)
      .merge(instances)
        .each(render);
  }

  function mine() {
    return Array.from(this.children).filter(belongsToMe);
  }

  function belongsToMe(node) {
    const instance = getInstance(node);
    return instance && instance.owner === component;
  }

  function dataArray(data, context) {
    data = Array.isArray(data) ? data : [data];
    return context ? data.map(d => Object.assign(Object.create(context), d)) : data;
  }

  function createInstance(d, i, nodes) {
    setInstance(this, {
      owner: component,
      destroy: () => destroy.call(this, d, i, nodes),
    });
    create.call(this, d, i, nodes);
  }

  function destroyInstance() {
    select(this).selectAll('*').each(destroyDescendant);
    (getInstance(this).destroy() || select(this)).remove();
  }

  function destroyDescendant() {
    const instance = getInstance(this);
    if (instance) { instance.destroy(); }
  }

  component.render = (_) => {
    render = (_, component);
    return render;
  };
  component.create = (_) => {
    create = (_, component);
    return create;
  };
  component.destroy = (_) => {
    destroy = (_, component);
    return destroy;
  };
  component.key = (_) => {
    key = (_, component);
    return key;
  };

  return component;
}

@@ -1627,30 +1627,17 @@
 ender = 
-(_, component)
+_
 ;%0A    re
@@ -1641,22 +1641,25 @@
  return 
-render
+component
 ;%0A  %7D;%0A 
@@ -1700,30 +1700,17 @@
 reate = 
-(_, component)
+_
 ;%0A    re
@@ -1715,21 +1715,24 @@
 return c
-reate
+omponent
 ;%0A  %7D;%0A 
@@ -1771,38 +1771,25 @@
   destroy = 
-(_, component)
+_
 ;%0A    return
@@ -1789,23 +1789,25 @@
  return 
-destroy
+component
 ;%0A  %7D;%0A 
@@ -1846,22 +1846,9 @@
 y = 
-(_, component)
+_
 ;%0A  
@@ -1856,19 +1856,25 @@
  return 
-key
+component
 ;%0A  %7D;%0A%0A

Fix setters.