// Subclass: use TagNode or PreferencesNode.
/**
 * The check boxes mark a task complete.  It is a simulated form field
 * with three states ...
 * 0=unchecked, 1=some children checked, 2=all children checked
 * When a task is clicked, the state of the nodes and parent and children
 * are updated, and this behavior cascades.
 *
 * @extends YAHOO.widget.TextNode
 * @constructor
 */
YAHOO.widget.MultiCheckNode = function() {}

YAHOO.extend(YAHOO.widget.MultiCheckNode, YAHOO.widget.TextNode, {
  /**
   * True if checkstate is 1 (some children checked) or 2 (all children checked),
   * false if 0.
   * @type boolean Array
   */
  checked: null,

  /**
   * checkState
   * 0=unchecked, 1=some children checked, 2=all children checked
   * @type int Array
   */
  checkState: null,
  
  setCurrentBox: function(box) {
    this.tree.currentBox = box;
  },
  
  getCurrentBox: function() {
    return this.tree.currentBox;
  },
  
  taskNodeParentChange: function() {
  /**
   * Custom event that is fired when the check box is clicked.  The
   * custom event is defined on the tree instance, so there is a single
   * event that handles all nodes in the tree.  The node clicked is
   * provided as an argument.  Note, your custom node implentation can
   * implement its own node specific events this way.
   *
   * @event checkClick
   * @for YAHOO.widget.TreeView
   * @param {YAHOO.widget.Node} node the node clicked
   */
    if (this.tree && !this.tree.hasEvent("checkClick")) {
      this.tree.createEvent("checkClick", this.tree);
    }
  },

  setUpCheck: function(checked, numBoxes) {
    this.checked = new Array();
    this.checkState = new Array();
    for (var i = 0; i < numBoxes; i++) {
      this.checked[i] = false;
      this.checkState[i] = 0;
      this.setCurrentBox(i);
      if (checked && checked[i] && checked[i] === true) {
        this.check();
      }
    }
    // set up the custom event on the tree
    this.taskNodeParentChange();
    this.subscribe("parentChange", this.taskNodeParentChange);
  },

  /**
   * The id of the check element
   * @for YAHOO.widget.TagNode
   * @type string
   */
  getCheckElId: function() {
    return "ygtvcheck" + this.index + '_' + this.getCurrentBox();
  },

  /**
   * Returns the check box element
   * @return the check html element (img)
   */
  getCheckEl: function() {
    return document.getElementById(this.getCheckElId());
  },

  /**
   * The style of the check element, derived from its current state
   * @return {string} the css style for the current check state
   */
  getCheckStyle: function() {
    return "ygtvcheck" + this.checkState[this.getCurrentBox()];
  },

  /**
   * Returns the link that will invoke this node's check toggle
   * @return {string} returns the link required to adjust the checkbox state
   */
  getCheckLink: function() {
    return "YAHOO.widget.TreeView.getNode(\'" + this.tree.id + "\'," +
      this.index + ").checkClick(" + this.getCurrentBox() + ")";
  },

  /**
   * Invoked when the user clicks the check box
   */
  checkClick: function(box) {
    if (typeof box != 'undefined') {
      this.setCurrentBox(box);
    } else { alert('checkClick(undefined)'); }
    // this.logger.log("previous checkstate: " + this.checkState[this.getCurrentBox()]);
    if (this.checkState[this.getCurrentBox()] === 0) {
      this.check();
    } else {
      this.uncheck();
    }
    this.onCheckClick();
    this.tree.fireEvent("checkClick", this);
  },

  /**
   * Override to get the check click event
   */
  onCheckClick: function() {
    // this.logger.log("onCheckClick: " + this);
  },

  /**
   * Refresh the state of this node's parent, and cascade up.
   */
  updateParent: function() {
    var p = this.parent;

    if (!p || !p.updateParent) {
      // this.logger.log("Abort udpate parent: " + this.index);
      return;
    }

    var somethingChecked = false;
    var somethingNotChecked = false;

    for (var i=0;i< p.children.length;++i) {
      if (p.children[i].checked[this.getCurrentBox()]) {
        somethingChecked = true;
        // checkState will be 1 if the child node has unchecked children
        if (p.children[i].checkState[this.getCurrentBox()] == 1) {
          somethingNotChecked = true;
        }
      } else {
        somethingNotChecked = true;
      }
    }

    if (somethingChecked) {
      p.setCheckState( (somethingNotChecked) ? 1 : 2 );
    } else {
      p.setCheckState(0);
    }

    p.updateCheckHtml();
    p.updateParent();
  },

  /**
   * If the node has been rendered, update the html to reflect the current
   * state of the node.
   */
  updateCheckHtml: function() {
    if (this.parent && this.parent.childrenRendered) {
      this.getCheckEl().className = this.getCheckStyle();
    }
  },

  defaultSetCheckState: function(state) {
    this.checkState[this.getCurrentBox()] = state;
    this.checked[this.getCurrentBox()] = (state > 0);
  },
  
  /**
   * Updates the state.  The checked property is true if the state is 1 or 2
   *
   * @param the new check state
   */
  setCheckState: function(state) {
    this.defaultSetCheckState(state);
  },

  /**
   * Check this node
   */
  check: function() {
    // this.logger.log("check");
    this.setCheckState(2);
    for (var i=0; i<this.children.length; ++i) {
      this.children[i].check();
    }
    this.updateCheckHtml();
    this.updateParent();
  },
  
  /**
   * Uncheck this node
   */
  uncheck: function() {
    this.setCheckState(0);
    for (var i=0; i<this.children.length; ++i) {
      this.children[i].uncheck();
    }
    this.updateCheckHtml();
    this.updateParent();
  },

  getNodeHtmlSpacer: function() {
    var sb = new Array();
    for (var i=0;i<this.depth;++i) {
      sb[sb.length] = '<td class="' + this.getDepthStyle(i) + '"><div class="ygtvspacer"></div></td>';
    }
    return sb.join('');
  },

  getNodeHtmlToggle: function() {
    var sb = new Array();
    sb[sb.length] = '<td';
    sb[sb.length] = ' id="' + this.getToggleElId() + '"';
    sb[sb.length] = ' class="' + this.getStyle() + '"';
    if (this.hasChildren(true)) {
      sb[sb.length] = ' onmouseover="this.className=';
      sb[sb.length] = 'YAHOO.widget.TreeView.getNode(\'';
      sb[sb.length] = this.tree.id + '\',' + this.index +  ').getHoverStyle()"';
      sb[sb.length] = ' onmouseout="this.className=';
      sb[sb.length] = 'YAHOO.widget.TreeView.getNode(\'';
      sb[sb.length] = this.tree.id + '\',' + this.index +  ').getStyle()"';
    }
    sb[sb.length] = ' onclick="javascript:' + this.getToggleLink() + '">&#160;';
    sb[sb.length] = '<div class="ygtvspacer"></div></td>';
    return sb.join('');
  },

  getNodeHtmlCheckBox: function(box) {
    this.setCurrentBox(box);
    var sb = new Array();
    sb[sb.length] = '<td';
    sb[sb.length] = ' id="' + this.getCheckElId() + '"';
    sb[sb.length] = ' class="' + this.getCheckStyle() + '"';
    sb[sb.length] = ' onclick="javascript:' + this.getCheckLink() + '">';
    sb[sb.length] = '<div class="ygtvspacer"></div></td>';
    return sb.join('');
  },

  getNodeHtmlLabel: function() {
    var sb = new Array();
    sb[sb.length] = '<td style="width:8em">';
    sb[sb.length] = '<span';
    sb[sb.length] = ' id="' + this.labelElId + '"';
    sb[sb.length] = ' class="' + this.labelStyle + '"';
    sb[sb.length] = ' title="' + this.href + '"';
    if (this.hasChildren(true)) {
      sb[sb.length] = ' onmouseover="document.getElementById(\'';
      sb[sb.length] = this.getToggleElId() + '\').className=';
      sb[sb.length] = 'YAHOO.widget.TreeView.getNode(\'';
      sb[sb.length] = this.tree.id + '\',' + this.index +  ').getHoverStyle()"';
      sb[sb.length] = ' onmouseout="document.getElementById(\'';
      sb[sb.length] = this.getToggleElId() + '\').className=';
      sb[sb.length] = 'YAHOO.widget.TreeView.getNode(\'';
      sb[sb.length] = this.tree.id + '\',' + this.index +  ').getStyle()"';
    }
    sb[sb.length] = (this.nowrap) ? ' nowrap="nowrap" ' : '';
    sb[sb.length] = ' >';
    sb[sb.length] = this.label;
    sb[sb.length] = '</span>';
    sb[sb.length] = '</td>';
    return sb.join('');
  },

  // Overrides YAHOO.widget.TextNode. The html that draws the label and boxes
  getNodeHtml: function() {
    alert('MultiClickNode.getNodeHtml should be overriden');
  },

  toString: function() {
    return "TagNode (" + this.index + ") " + this.label;
  }

});
