001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements. See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership. The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the  "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    /*
019     * $Id: Counter.java 468645 2006-10-28 06:57:24Z minchau $
020     */
021    package org.apache.xalan.transformer;
022    
023    import javax.xml.transform.TransformerException;
024    
025    import org.apache.xalan.templates.ElemNumber;
026    import org.apache.xml.dtm.DTM;
027    import org.apache.xpath.NodeSetDTM;
028    import org.apache.xpath.XPathContext;
029    
030    /**
031     * A class that does incremental counting for support of xsl:number.
032     * This class stores a cache of counted nodes (m_countNodes).
033     * It tries to cache the counted nodes in document order...
034     * the node count is based on its position in the cache list
035     * @xsl.usage internal
036     */
037    public class Counter
038    {
039    
040      /**
041       * Set the maximum ammount the m_countNodes list can
042       * grow to.
043       */
044      static final int MAXCOUNTNODES = 500;
045    
046      /**
047       * The start count from where m_countNodes counts
048       * from.  In other words, the count of a given node
049       * in the m_countNodes vector is node position +
050       * m_countNodesStartCount.
051       */
052      int m_countNodesStartCount = 0;
053    
054      /**
055       * A vector of all nodes counted so far.
056       */
057      NodeSetDTM m_countNodes;
058    
059      /**
060       * The node from where the counting starts.  This is needed to
061       * find a counter if the node being counted is not immediatly
062       * found in the m_countNodes vector.
063       */
064      int m_fromNode = DTM.NULL;
065    
066      /**
067       * The owning xsl:number element.
068       */
069      ElemNumber m_numberElem;
070    
071      /**
072       * Value to store result of last getCount call, for benifit
073       * of returning val from CountersTable.getCounterByCounted,
074       * who calls getCount.
075       */
076      int m_countResult;
077    
078      /**
079       * Construct a counter object.
080       *
081       * @param numberElem The owning xsl:number element. 
082       * @param countNodes A vector of all nodes counted so far.
083       *
084       * @throws TransformerException
085       */
086      Counter(ElemNumber numberElem, NodeSetDTM countNodes) throws TransformerException
087      {
088        m_countNodes = countNodes;
089        m_numberElem = numberElem;
090      }
091    
092      /**
093       * Construct a counter object.
094       *
095       * @param numberElem The owning xsl:number element. 
096       *
097       * @throws TransformerException
098       *
099      Counter(ElemNumber numberElem) throws TransformerException
100      {
101        m_numberElem = numberElem;
102      }*/
103    
104      /**
105       * Try and find a node that was previously counted. If found,
106       * return a positive integer that corresponds to the count.
107       *
108       * @param support The XPath context to use
109       * @param node The node to be counted.
110       * 
111       * @return The count of the node, or -1 if not found.
112       */
113      int getPreviouslyCounted(XPathContext support, int node)
114      {
115    
116        int n = m_countNodes.size();
117    
118        m_countResult = 0;
119    
120        for (int i = n - 1; i >= 0; i--)
121        {
122          int countedNode = m_countNodes.elementAt(i);
123    
124          if (node == countedNode)
125          {
126    
127            // Since the list is in backwards order, the count is 
128            // how many are in the rest of the list.
129            m_countResult = i + 1 + m_countNodesStartCount;
130    
131            break;
132          }
133          
134          DTM dtm = support.getDTM(countedNode);
135    
136          // Try to see if the given node falls after the counted node...
137          // if it does, don't keep searching backwards.
138          if (dtm.isNodeAfter(countedNode, node))
139            break;
140        }
141    
142        return m_countResult;
143      }
144    
145      /**
146       * Get the last node in the list.
147       *
148       * @return the last node in the list.
149       */
150      int getLast()
151      {
152    
153        int size = m_countNodes.size();
154    
155        return (size > 0) ? m_countNodes.elementAt(size - 1) : DTM.NULL;
156      }
157    }