## -*- Ruby -*-
## XML::SimpleTree::Visitor
## 1998 by yoshidam
##
## Oct 23, 1998 yoshidam Fix each
##

module XML
  module SimpleTree

    ## Skeleton visitor
    class Visitor
      ## You can override the following methods and implement the other
      ## "visit_TYPE" methods.
      ## You should implement some "visit_name_NAME" methods and
      ## "method_missing" method for accept_name.

      def visit_Document(grove, *rest)
        grove.children_accept(self, *rest)
      end

      def visit_Element(element, *rest)
        element.children_accept(self, *rest)
      end

      def visit_Text(text, *rest)
      end

      def visit_CDATASection(text, *rest)
      end

      def visit_Comment(comment, *rest)
      end

      def visit_ProcessingInstruction(pi, *rest)
      end

    end


    class Node

      ## XML::Grove::Visitor like interfaces
      def accept(visitor, *rest)
        typename = type.to_s.sub!(/.*?([^:]+)$/, '\1')
        visitor.send("visit_" + typename, self, *rest)
      end

      def accept_name(visitor, *rest)
        if nodeType == ELEMENT
          name_method = "visit_name_" + nodeName
          visitor.send(name_method, self, *rest)
        else
          self.accept(visitor, *rest)
        end
      end

      def children_accept(visitor, *rest)
        ret = []
        @children && @children.each { |node|
          ret.push(node.accept(visitor, *rest))
        }
        ret
      end

      def children_accept_name(visitor, *rest)
        ret = []
        @children && @children.each { |node|
          ret.push(node.accept_name(visitor, *rest))
        }
        ret
      end

      ## Iterator interface
      include Enumerable
      def each
        sibstack = []
        siblings = [ self ]
        while true
          if siblings.length == 0
            break if sibstack.length == 0
            siblings = sibstack.pop
            next
          end
          node = siblings.shift
          yield(node)
          children = node.childNodes
          if !children.nil?
            sibstack.push(siblings)
            siblings = children.to_a.dup
          end
        end
      end
    end
  end
end
