function CheckboxNode(input) {
  if (!input || typeof input != 'object' || input.nodeType != 1 || input.nodeName.toLowerCase() != 'input') return null;
  switch (input.getAttribute('type')) {
      case 'radio' : 
        var radio = true;
        break;
      case 'checkbox' :
        radio = false;
        break;
      default : return null;  
  };
  var self = document.createElement('div');
  
  
  
  var ID_INPUT_NODE_SUFFIX = "-input";
  var CLASS_NODE_RADIO = "radio";
  var CLASS_NODE_CHECKBOX = "checkbox";
  var CLASS_CONTROL = "control";
  var CLASS_SELECT = "select";
  var CLASS_SELECTED = "selected";
  
  
  
  var control = document.createElement('div');
  var group;
  
  
  
  function addEventListener(node, event, fn) {
		if (node.addEventListener) node.addEventListener(event, fn, false);
		else if (node.attachEvent) node.attachEvent("on" + event, fn);
	}

	function removeEventListener(node, event, fn) {
		if (node.removeEventListener) node.removeEventListener(event, fn, false);
		else if (node.detachEvent) node.detachEvent("on" + event, fn);
	}

	function addClass(node, token) {
		if (!token || hasClass(node, token)) return;
		if (!node.className) {
			node.className = token;
			return;
		};
		node.className += " " + token;
	}

	function removeClass(node, token) {node.className = node.className.replace(new RegExp("\\s?\\b" + token + "\\b"), "")};

	function hasClass(node, token) {
		if (node.className.search(new RegExp("\\b" + token + "\\b")) != -1) return true;
		return false;
	}  
  
  
  
  function onInputFocus() {
    //console.log("onInputFocus", self, input.checked);    
    self.focus();
    
    if (!window.ActiveXObject || !group) return;
    for (var i = 0, item = group[0]; item; item = group[++i]) item.parentNode.parentNode.update();
  }
  
  function onChromeInputFocus() {
    //console.log("onChromeInputFocus", self, input.checked);
    input.focus();
    
    if (!group) return;
    for (var i = 0, item = group[0]; item; item = group[++i]) item.parentNode.parentNode.update();
  }
  
  function onInputBlur() {
    //console.log("onInputBlur", self);
    self.blur();
  }
  
  function onInputClick(e) {
    //console.log("onInputClick", self, input.checked);
    if (!input.checked) removeClass(control, CLASS_SELECTED);
    else addClass(control, CLASS_SELECTED);
    
    if (!group) return;
    for (var i = 0, item = group[0]; item; item = group[++i]) item.parentNode.parentNode.update();
  }
  
  function onControlFocus() {
    //console.log("onControlFocus", self, input.checked);
    input.focus();
    input.click();
  }
    
  
  
  self.focus = function() {
    //console.log("focus", self, input.checked);
    
    removeEventListener(input, 'focus', onInputFocus);
    if (!window.ActiveXObject) removeEventListener(input, 'click', onChromeInputFocus);      //bug in chrome
    removeEventListener(control, 'click', onControlFocus);
    
    addEventListener(input, 'click', onInputClick);
    addEventListener(input, 'blur', onInputBlur);
    
    addClass(control, CLASS_SELECT);
    
    if (input.checked) addClass(control, CLASS_SELECTED);
    else removeClass(control, CLASS_SELECTED);    
  };
  
  self.blur = function() {
    //console.log("blur", self, input.checked);
    //console.log("---");
    
    removeEventListener(input, 'click', onInputClick);
    removeEventListener(input, 'blur', onInputBlur);
    
    addEventListener(input, 'focus', onInputFocus);
    if (!window.ActiveXObject) addEventListener(input, 'click', onChromeInputFocus);     //bug in chrome
    addEventListener(control, 'click', onControlFocus);
    
    removeClass(control, CLASS_SELECT);
  };
  
  self.update = function() {
    //console.log("update", self);
    if (input.checked) addClass(control, CLASS_SELECTED);
    else removeClass(control, CLASS_SELECTED);
  };
  
  
    
  (function() {
    var node = document.createElement('div');
    node.className = "input-node";
    node.style.display = "inline-block";
    node.style.width = "0";
    node.style.height = "0";
    node.style.overflow = "hidden";
    
    addEventListener(input, 'focus', onInputFocus);
    if (!window.ActiveXObject) addEventListener(input, 'click', onChromeInputFocus);     //bug in chrome
    
    if (input.id) self.id = input.id + ID_INPUT_NODE_SUFFIX;
    self.className = radio ? CLASS_NODE_RADIO : CLASS_NODE_CHECKBOX;
    addClass(self, input.className);
    
    input.parentNode.insertBefore(self, input);
    node.appendChild(input);
    self.appendChild(node);
    
    var name = "";
    if (radio && (name = input.getAttribute('name'))) {
      group = [];
      var element = document.getElementsByTagName('input');
      for (var i = 0, item = element[0]; item; item = element[++i]) {
        if (item == input || item.getAttribute('type') != 'radio' || item.getAttribute('name') != name) continue;
        group.push(item);
      };      
    };    
    
    control.className = CLASS_CONTROL;
    if (input.checked) addClass(control, CLASS_SELECTED);
    addEventListener(control, 'click', onControlFocus);
    self.appendChild(control);
  })();
  
  return self;  
};

//jQuery wrapper to replace old plugin seamlessly
jQuery.fn.custCheckBox = function() {
	return this.each(function() {new CheckboxNode(this);});
};
