001    /*
002     * TreeHelper.java
003     *
004     * Created on February 4, 2007, 11:54 PM
005     */
006    
007    package net.sf.tacos.components.tree;
008    
009    import java.util.Stack;
010    import org.apache.tapestry.AbstractComponent;
011    import org.apache.tapestry.IMarkupWriter;
012    import org.apache.tapestry.IRequestCycle;
013    import org.apache.tapestry.engine.NullWriter;
014    
015    /**
016     *
017     * @author andyhot
018     */
019    public abstract class TreeHelper extends AbstractComponent {
020        
021        private Stack stack;
022        
023        public abstract TreeIterator getTreeIterator();
024        
025        private Stack getCycleStack(IRequestCycle cycle) {
026            Stack currStack = (Stack) cycle.getAttribute(TreeHelper.class.getName());
027            if (currStack == null) {
028                currStack = new Stack();
029            }
030            return currStack;
031        }
032        
033        private void setCycleStack(IRequestCycle cycle, Stack currStack) {
034            cycle.setAttribute(TreeHelper.class.getName(), currStack);
035        }
036    
037        protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle) {          
038            stack = getCycleStack(cycle);
039            if (getTreeIterator() == null) {
040                finalRenderComponent();
041            } else {  
042                int diff = getTreeIterator().getDepth() - getTreeIterator().getPreviousDepth();
043                boolean empty = stack.empty();
044                
045                if (writer == NullWriter.getSharedInstance()  && cycle.getResponseBuilder().isDynamic()
046                        && (empty || stack.peek()==writer)) {
047                    renderBody(writer, cycle);
048                    return;
049                }
050    
051                if (empty) {
052                    stack.push(writer.getNestedWriter()); 
053                    diff = 0;
054                }
055                IMarkupWriter writerGive = (IMarkupWriter) stack.peek();
056                normalRenderComponent(writerGive, cycle, diff, empty);
057            }
058            
059            setCycleStack(cycle, stack);
060        }
061        
062        protected void finalRenderComponent() {
063            while (!stack.empty()) {
064                IMarkupWriter inner = (IMarkupWriter) stack.pop();            
065                inner.close();
066            }
067            stack = null;        
068            return;
069        }
070        
071        protected void normalRenderComponent(IMarkupWriter writer, IRequestCycle cycle, 
072                int diff, boolean empty) {                    
073            //System.out.println("Doing: " + getClientId() + " Diff:" + diff + "Wr:" + writer);
074            if (diff==0) {
075                if (!empty)
076                    writer.end();
077                
078                writer.begin("div");            
079                renderIdAttribute(writer, cycle);
080                writer.closeTag();
081                renderBody(writer, cycle);
082            } else if (diff>0) {            
083                writer = writer.getNestedWriter();
084                stack.push(writer);
085                
086                writer.begin("div");            
087                renderIdAttribute(writer, cycle);
088                writer.closeTag();            
089                renderBody(writer, cycle);            
090            } else {
091                writer = (IMarkupWriter) stack.pop();
092                for (int c = diff; c < 0 && !stack.empty(); c++) {
093                    writer.close();
094                    writer = (IMarkupWriter) stack.pop();
095                }
096                if (stack.empty() && cycle.getResponseBuilder().isDynamic()) {
097                    renderBody(NullWriter.getSharedInstance(), cycle);
098                    writer.close();
099                    stack.push(NullWriter.getSharedInstance());
100                    return;
101                }
102                
103                writer.end();
104                stack.push(writer);
105                
106                writer.begin("div");            
107                renderIdAttribute(writer, cycle);
108                writer.closeTag();
109                renderBody(writer, cycle);
110            }
111            
112        }
113    
114    }