001    /**
002     * ========================================
003     * JFreeReport : a free Java report library
004     * ========================================
005     *
006     * Project Info:  http://reporting.pentaho.org/
007     *
008     * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors.
009     *
010     * This library is free software; you can redistribute it and/or modify it under the terms
011     * of the GNU Lesser General Public License as published by the Free Software Foundation;
012     * either version 2.1 of the License, or (at your option) any later version.
013     *
014     * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015     * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016     * See the GNU Lesser General Public License for more details.
017     *
018     * You should have received a copy of the GNU Lesser General Public License along with this
019     * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020     * Boston, MA 02111-1307, USA.
021     *
022     * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
023     * in the United States and other countries.]
024     *
025     * ------------
026     * $Id: PrecomputeNodeImpl.java 3525 2007-10-16 11:43:48Z tmorgner $
027     * ------------
028     * (C) Copyright 2000-2005, by Object Refinery Limited.
029     * (C) Copyright 2005-2007, by Pentaho Corporation.
030     */
031    
032    package org.jfree.report.data;
033    
034    import java.util.ArrayList;
035    
036    /**
037     * A precompute-node represents a resolved element or section of the report definition. Unlike the structural nodes,
038     * these nodes can always have childs.
039     * <p/>
040     * The resulting tree gets pruned as early as possible - nodes which do not contain precomputed or preserved expressions
041     * will not be stored.
042     *
043     * @author Thomas Morgner
044     */
045    public class PrecomputeNodeImpl implements PrecomputeNode
046    {
047      private PrecomputeNodeImpl parent;
048      private PrecomputeNodeImpl next;
049      private PrecomputeNodeImpl firstChild;
050      private PrecomputeNodeImpl lastChild;
051    
052      private PrecomputeNodeKey key;
053      private ArrayList functionResults;
054      private ArrayList functionNames;
055    
056      public PrecomputeNodeImpl(final PrecomputeNodeKey key)
057      {
058        if (key == null)
059        {
060          throw new NullPointerException();
061        }
062        this.key = key;
063      }
064    
065      public PrecomputeNodeKey getKey()
066      {
067        return key;
068      }
069    
070      public PrecomputeNode getParent()
071      {
072        return parent;
073      }
074    
075      protected void setParent(final PrecomputeNodeImpl parent)
076      {
077        this.parent = parent;
078      }
079    
080      public PrecomputeNode getNext()
081      {
082        return next;
083      }
084    
085      protected void setNext(final PrecomputeNodeImpl next)
086      {
087        this.next = next;
088      }
089    
090      public PrecomputeNode getFirstChild()
091      {
092        return firstChild;
093      }
094    
095      protected void setFirstChild(final PrecomputeNodeImpl firstChild)
096      {
097        this.firstChild = firstChild;
098      }
099    
100      public PrecomputeNode getLastChild()
101      {
102        return lastChild;
103      }
104    
105      protected void setLastChild(final PrecomputeNodeImpl lastChild)
106      {
107        this.lastChild = lastChild;
108      }
109    
110      public void add(final PrecomputeNodeImpl node)
111      {
112        if (firstChild == null)
113        {
114          firstChild = node;
115          firstChild.setParent(this);
116          lastChild = node;
117          return;
118        }
119    
120        lastChild.setNext(node);
121        lastChild.setParent(this);
122      }
123    
124      public void addFunction(final String name, final Object value)
125      {
126        if (this.functionNames == null)
127        {
128          functionNames = new ArrayList();
129          functionResults = new ArrayList();
130        }
131    
132        this.functionNames.add(name);
133        this.functionResults.add(value);
134      }
135    
136      public int getFunctionCount()
137      {
138        if (functionNames == null)
139        {
140          return 0;
141        }
142        return functionNames.size();
143      }
144    
145      public String getFunctionName(final int idx)
146      {
147        if (functionNames == null)
148        {
149          throw new IndexOutOfBoundsException();
150        }
151        return (String) functionNames.get(idx);
152      }
153    
154      public Object getFunctionResult(final int idx)
155      {
156        if (functionResults == null)
157        {
158          throw new IndexOutOfBoundsException();
159        }
160        return functionResults.get(idx);
161      }
162    
163      public void prune()
164      {
165        if (parent == null)
166        {
167          return;
168        }
169    
170        if (parent.getLastChild() != this)
171        {
172          throw new IllegalStateException("Cannot prune. Not the last child.");
173        }
174        if (parent.getFirstChild() == this)
175        {
176          parent.setFirstChild(null);
177        }
178        parent.setLastChild(null);
179      }
180    }