text: /**
   * @class Ext.data.Tree
   * 
   * This class is used as a container for a series of nodes. The nodes themselves maintain
   * the relationship between parent/child. The tree itself acts as a manager. It gives functionality
   * to retrieve a node by its identifier: {@link #getNodeById}. 
   *
   * The tree also relays events from any of it's child nodes, allowing them to be handled in a 
   * centralized fashion. In general this class is not used directly, rather used internally 
   * by other parts of the framework.
   *
   * @constructor
   * @param {Node} root (optional) The root node
   */
  Ext.define('Ext.data.Tree', {
      alias: 'data.tree',
      
      mixins: {
          observable: "Ext.util.Observable"
      },
  
      /**
       * The root node for this tree
       * @type Node
       */
      root: null,
          
      constructor: function(root) {
          var me = this;
          
          me.nodeHash = {};
  
          me.mixins.observable.constructor.call(me);
                          
          if (root) {
              me.setRootNode(root);
          }
      },
  
      /**
       * Returns the root node for this tree.
       * @return {Ext.data.NodeInterface}
       */
      getRootNode : function() {
          return this.root;
      },
  
      /**
       * Sets the root node for this tree.
       * @param {Ext.data.NodeInterface} node
       * @return {Ext.data.NodeInterface} The root node
       */
      setRootNode : function(node) {
          var me = this;
          
          me.root = node;
          Ext.data.NodeInterface.decorate(node);
          
          if (me.fireEvent('beforeappend', null, node) !== false) {
              node.set('root', true);
              node.updateInfo();
              
              me.relayEvents(node, [
                  /**
                   * @event append
                   * Fires when a new child node is appended to a node in this tree.
                   * @param {Tree} tree The owner tree
                   * @param {Node} parent The parent node
                   * @param {Node} node The newly appended node
                   * @param {Number} index The index of the newly appended node
                   */
                  "append",
  
                  /**
                   * @event remove
                   * Fires when a child node is removed from a node in this tree.
                   * @param {Tree} tree The owner tree
                   * @param {Node} parent The parent node
                   * @param {Node} node The child node removed
                   */
                  "remove",
  
                  /**
                   * @event move
                   * Fires when a node is moved to a new location in the tree
                   * @param {Tree} tree The owner tree
                   * @param {Node} node The node moved
                   * @param {Node} oldParent The old parent of this node
                   * @param {Node} newParent The new parent of this node
                   * @param {Number} index The index it was moved to
                   */
                  "move",
  
                  /**
                   * @event insert
                   * Fires when a new child node is inserted in a node in this tree.
                   * @param {Tree} tree The owner tree
                   * @param {Node} parent The parent node
                   * @param {Node} node The child node inserted
                   * @param {Node} refNode The child node the node was inserted before
                   */
                  "insert",
  
                  /**
                   * @event beforeappend
                   * Fires before a new child is appended to a node in this tree, return false to cancel the append.
                   * @param {Tree} tree The owner tree
                   * @param {Node} parent The parent node
                   * @param {Node} node The child node to be appended
                   */
                  "beforeappend",
  
                  /**
                   * @event beforeremove
                   * Fires before a child is removed from a node in this tree, return false to cancel the remove.
                   * @param {Tree} tree The owner tree
                   * @param {Node} parent The parent node
                   * @param {Node} node The child node to be removed
                   */
                  "beforeremove",
  
                  /**
                   * @event beforemove
                   * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
                   * @param {Tree} tree The owner tree
                   * @param {Node} node The node being moved
                   * @param {Node} oldParent The parent of the node
                   * @param {Node} newParent The new parent the node is moving to
                   * @param {Number} index The index it is being moved to
                   */
                  "beforemove",
  
                  /**
                   * @event beforeinsert
                   * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
                   * @param {Tree} tree The owner tree
                   * @param {Node} parent The parent node
                   * @param {Node} node The child node to be inserted
                   * @param {Node} refNode The child node the node is being inserted before
                   */
                  "beforeinsert",
  
                   /**
                    * @event expand
                    * Fires when this node is expanded.
                    * @param {Node} this The expanding node
                    */
                   "expand",
  
                   /**
                    * @event collapse
                    * Fires when this node is collapsed.
                    * @param {Node} this The collapsing node
                    */
                   "collapse",
  
                   /**
                    * @event beforeexpand
                    * Fires before this node is expanded.
                    * @param {Node} this The expanding node
                    */
                   "beforeexpand",
  
                   /**
                    * @event beforecollapse
                    * Fires before this node is collapsed.
                    * @param {Node} this The collapsing node
                    */
                   "beforecollapse" ,
  
                   /**
                    * @event rootchange
                    * Fires whenever the root node is changed in the tree.
                    * @param {Ext.data.Model} root The new root
                    */
                   "rootchange"
              ]);
              
              node.on({
                  scope: me,
                  insert: me.onNodeInsert,
                  append: me.onNodeAppend,
                  remove: me.onNodeRemove
              });
  
              me.registerNode(node);        
              me.fireEvent('append', null, node);
              me.fireEvent('rootchange', node);
          }
              
          return node;
      },
      
      /**
       * Flattens all the nodes in the tree into an array.
       * @private
       * @return {Array} The flattened nodes.
       */
      flatten: function(){
          var nodes = [],
              hash = this.nodeHash,
              key;
              
          for (key in hash) {
              if (hash.hasOwnProperty(key)) {
                  nodes.push(hash[key]);
              }
          }
          return nodes;
      },
      
      /**
       * Fired when a node is inserted into the root or one of it's children
       * @private
       * @param {Ext.data.NodeInterface} parent The parent node
       * @param {Ext.data.NodeInterface} node The inserted node
       */
      onNodeInsert: function(parent, node) {
          this.registerNode(node);
      },
      
      /**
       * Fired when a node is appended into the root or one of it's children
       * @private
       * @param {Ext.data.NodeInterface} parent The parent node
       * @param {Ext.data.NodeInterface} node The appended node
       */
      onNodeAppend: function(parent, node) {
          this.registerNode(node);
      },
      
      /**
       * Fired when a node is removed from the root or one of it's children
       * @private
       * @param {Ext.data.NodeInterface} parent The parent node
       * @param {Ext.data.NodeInterface} node The removed node
       */
      onNodeRemove: function(parent, node) {
          this.unregisterNode(node);
      },
  
      /**
       * Gets a node in this tree by its id.
       * @param {String} id
       * @return {Ext.data.NodeInterface} The match node.
       */
      getNodeById : function(id) {
          return this.nodeHash[id];
      },
  
      /**
       * Registers a node with the tree
       * @private
       * @param {Ext.data.NodeInterface} The node to register
       */
      registerNode : function(node) {
          this.nodeHash[node.getId() || node.internalId] = node;
      },
  
      /**
       * Unregisters a node with the tree
       * @private
       * @param {Ext.data.NodeInterface} The node to unregister
       */
      unregisterNode : function(node) {
          delete this.nodeHash[node.getId() || node.internalId];
      },
      
      /**
       * Sorts this tree
       * @private
       * @param {Function} sorterFn The function to use for sorting
       * @param {Boolean} recursive True to perform recursive sorting
       */
      sort: function(sorterFn, recursive) {
          this.getRootNode().sort(sorterFn, recursive);
      },
      
       /**
       * Filters this tree
       * @private
       * @param {Function} sorterFn The function to use for filtering
       * @param {Boolean} recursive True to perform recursive filtering
       */
      filter: function(filters, recursive) {
          this.getRootNode().filter(filters, recursive);
      }
  });