1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the  "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18/*
19 * $Id: Counter.java 468645 2006-10-28 06:57:24Z minchau $
20 */
21package org.apache.xalan.transformer;
22
23import javax.xml.transform.TransformerException;
24
25import org.apache.xalan.templates.ElemNumber;
26import org.apache.xml.dtm.DTM;
27import org.apache.xpath.NodeSetDTM;
28import org.apache.xpath.XPathContext;
29
30/**
31 * A class that does incremental counting for support of xsl:number.
32 * This class stores a cache of counted nodes (m_countNodes).
33 * It tries to cache the counted nodes in document order...
34 * the node count is based on its position in the cache list
35 * @xsl.usage internal
36 */
37public class Counter
38{
39
40  /**
41   * Set the maximum ammount the m_countNodes list can
42   * grow to.
43   */
44  static final int MAXCOUNTNODES = 500;
45
46  /**
47   * The start count from where m_countNodes counts
48   * from.  In other words, the count of a given node
49   * in the m_countNodes vector is node position +
50   * m_countNodesStartCount.
51   */
52  int m_countNodesStartCount = 0;
53
54  /**
55   * A vector of all nodes counted so far.
56   */
57  NodeSetDTM m_countNodes;
58
59  /**
60   * The node from where the counting starts.  This is needed to
61   * find a counter if the node being counted is not immediatly
62   * found in the m_countNodes vector.
63   */
64  int m_fromNode = DTM.NULL;
65
66  /**
67   * The owning xsl:number element.
68   */
69  ElemNumber m_numberElem;
70
71  /**
72   * Value to store result of last getCount call, for benifit
73   * of returning val from CountersTable.getCounterByCounted,
74   * who calls getCount.
75   */
76  int m_countResult;
77
78  /**
79   * Construct a counter object.
80   *
81   * @param numberElem The owning xsl:number element.
82   * @param countNodes A vector of all nodes counted so far.
83   *
84   * @throws TransformerException
85   */
86  Counter(ElemNumber numberElem, NodeSetDTM countNodes) throws TransformerException
87  {
88    m_countNodes = countNodes;
89    m_numberElem = numberElem;
90  }
91
92  /**
93   * Construct a counter object.
94   *
95   * @param numberElem The owning xsl:number element.
96   *
97   * @throws TransformerException
98   *
99  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}
158