import { extend_selection } from "./core/extend_selection";
import { Dispatcher } from './core/Dispatcher';
import { EventEmitter } from './core/EventEmitter';
import { assign } from './core/utils';

var SubUnit = {};

if ( typeof module === 'object' ) {
  module.exports = SubUnit;
}

SubUnit.select = function (object) {
  var node = typeof object === "function" ? object(): object;
  var root = extend_selection([[new THREE.Object3D()]]);
  root.parentNode = node;
  root[0][0].__data__ = {};
  root[0][0].__tags__ = [];
  node.add(root[0][0]);
  return root;
};

SubUnit.object = function (object) {
  return extend_selection([[object]]);
};

SubUnit.createDispatcher = function () {

  var dispatcher = new Dispatcher();

  dispatcher.serverAction = function (action) {
    var payload = {
      source: 'SERVER_ACTION',
      action: action
    };
    this.dispatch(payload);
  };

  dispatcher.viewAction = function (action) {
    var payload = {
      source: 'VIEW_ACTION',
      action: action
    };
    this.dispatch(payload);
  };

  return dispatcher;
};

SubUnit.createStore = function (methods) {
  var store = assign({}, EventEmitter.prototype, methods);

  store.emitChange = function() {
    this.emit('change');
  };

  store.addChangeListener = function (callback) {
    this.on('change', callback);
  };

  store.removeChangeListener = function(callback) {
    this.removeListener('change', callback);
  };

  return store;
};


SubUnit.createView = function (parentNode, methods) {

  var view = assign(new SubUnitView(), methods);

  function SubUnitView () {
    this.state = {};
    this.root  = new THREE.Object3D();

    parentNode.add(this.root);

    this.render = function () {};

    this.setState = function (data) {
      this.state = data;
      this.render();
    };
  };

  if (!view.getInitialState) {
    console.warn('SubUnit view must have getIntialState method');
  } else {
    view.setState(view.getInitialState());
  }

  if (view.viewDidMount) {
    view.viewDidMount.call(view);
  }

  if (!view.render || typeof view.render !== 'function') {
    console.warn('SubUnit view must have render method');
  } else {
    view.render();
  }

  return view;
};


this.SubUnit = SubUnit;
@@ -1481,20 +1481,16 @@
  (parent
-Node
 , method
@@ -1598,22 +1598,21 @@
 %7B%7D;%0A
+%0A
     
-this.root 
+var node
  = n
@@ -1636,49 +1636,136 @@
 ();%0A
-%0A    parentNode.add(this.root
+    this.parentNode = parent;%0A    this.parentNode.add(node);%0A%0A    this.root = SubUnit.object(node
 );%0A
-%0A
   
-  this
+%7D%0A%0A  SubUnitView.prototype
 .ren
@@ -1789,22 +1789,37 @@
  %7B%7D;%0A%0A  
-  this
+SubUnitView.prototype
 .setStat
@@ -1840,26 +1840,24 @@
 data) %7B%0A    
- 
- 
 this.state =
@@ -1867,18 +1867,16 @@
 ta;%0A    
-  
 this.ren
@@ -1888,46 +1888,298 @@
 ;%0A  
-  %7D;%0A  %7D;%0A%0A  if (!view.getInitialState
+%7D;%0A%0A  SubUnitView.prototype.remove = function () %7B%0A    if (view.viewWillUnmount && typeof view.viewWillUnmount === 'function') %7B%0A      view.viewWillUnmount();%0A    %7D%0A    this.parentNode.remove(this.root.node());%0A  %7D;%0A%0A  if (!view.getInitialState %7C%7C typeof view.getInitialState !== 'function'
 ) %7B%0A
@@ -2219,21 +2219,24 @@
 st have 
+a 
 getIn
+i
 tialStat
@@ -2329,16 +2329,59 @@
 DidMount
+ && typeof view.viewDidMount === 'function'
 ) %7B%0A    
@@ -2401,18 +2401,9 @@
 ount
-.call(view
+(
 );%0A 
@@ -2506,16 +2506,18 @@
 st have 
+a 
 render m

store parent node and return wrapped root node