/* jshint node: true */
/* global window: false */
'use strict';

var paths = require('gedi-paths');
var scope = require('../scope');
var tagMappings = {
  div: 'container',
  ul: 'container'
};

// require all the supported element types
// without these requires, the browserification process will not work
require('./container');
require('./element');
require('./input');

function HtmlDriver(data, opts) {
  var autoAttach;
  var driver = this;

  if (! (this instanceof HtmlDriver)) {
    return new HtmlDriver(data, opts);
  }

  // attach to the driver
  this.data = data;

  // TODO: check data valid (looks and smells like Gedi)

  // auto attach (if not specified otherwise)
  autoAttach = (opts || {}).autoAttach;
  if (typeof autoAttach == 'undefined' || autoAttach) {
    window.addEventListener('load', function() {
      driver.attach(
        (opts || {}).target || document.body,
        (opts || {}).basePath
      );
    });
  }
}

module.exports = HtmlDriver;

HtmlDriver.prototype.attach = function(target, basePath) {
  var elementPath;
  var binding;
  var handlerType;
  var handler;
  var ii = 0;
  var count;
  var path;
  var data = this.data;
  var checkChildNodes = true;

  // if the node is text, or a comment abort
  if ((target instanceof Text) || (target instanceof Comment)) return;

  // if the target is already bound, then abort
  if (target._activeBinding) return;

  // initialise the basepath if not already provided
  basePath = paths.create(basePath);

  // check to see if we have a path on the element
  binding = target.getAttribute('data-binding');
  count = target.childNodes.length;

  // path relative to the current element
  path = paths.append(
    basePath,
    target.getAttribute('data-scope') || target.getAttribute('data-path') || ''
  );

  // bind if we have a binding
  if (binding) {
    // get the handler type
    handlerType = target.tagName.toLowerCase();

    // check if we should use another handler for the current tag
    handlerType = tagMappings[handlerType] || handlerType;

    try {
      handler = require('./' + handlerType);
    }
    catch (e) {
      handler = require('./element');
    }

    // run the handler
    checkChildNodes = handler.call(this, target, data, binding, path);

    // flag as bound
    target._activeBinding = binding; // path.append(binding);
  }

  // iterate through the child nodes of the element
  for (; (checkChildNodes || typeof checkChildNodes == 'undefined') && ii < count; ii++) {
    if (target.childNodes[ii]) {
      this.attach(target.childNodes[ii], path);
    }
  }
};

/**
  #### remove(target)

  Debind listening on the node
**/
HtmlDriver.prototype.remove = function(target) {
  // TODO: needs to be more specific
  if (target._activeBinding) {
    this.data.debind(target._activeBinding);
  }

  if (! target.childNodes) return;

  // iterate through the child nodes
  for (var ii = target.childNodes.length; ii--; ) {
    if (target.childNodes[ii] && (! (target.childNodes[ii] instanceof Text))) {
      this.remove(target.childNodes[ii]);
    }
  }
};