001/*
002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     bstefanescu
011 *
012 * $Id$
013 */
014
015package org.nuxeo.ecm.platform.rendering.fm.extensions;
016
017import java.io.IOException;
018import java.io.Writer;
019import java.util.ArrayList;
020import java.util.List;
021
022import freemarker.template.TemplateException;
023
024/**
025 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
026 */
027public class BlockWriter extends Writer {
028
029    BlockWriterRegistry reg;
030
031    final String page;
032
033    final String name;
034
035    StringBuilder buf = new StringBuilder();
036
037    List<String> segments = new ArrayList<String>();
038
039    List<String> blocks = new ArrayList<String>();
040
041    BlockWriter superBlock; // the direct parent in the hierarchy - null if none
042
043    BlockWriter baseBlock; // the root of the block hierarchy - null if none
044
045    String ifBlockDefined;
046
047    // used to avoid writing blocks or characters in the current block writer.
048    // This is the case of the extension tag - that should ignore any content
049    // and blocks too because blocks inside extension tag
050    // must be derived blocks (the base hierarchy block will be found later when
051    // the extended base template will be parsed)
052    boolean suppressOutput = false;
053
054    public BlockWriter(String page, String name, BlockWriterRegistry reg) {
055        this.reg = reg;
056        this.name = name;
057        this.page = page;
058    }
059
060    public final BlockWriterRegistry getRegistry() {
061        return reg;
062    }
063
064    public void setSuppressOutput(boolean suppressOutput) {
065        this.suppressOutput = suppressOutput;
066    }
067
068    public boolean getSuppressOutput() {
069        return suppressOutput;
070    }
071
072    @Override
073    public void close() throws IOException {
074        buf = null;
075        segments = null;
076        blocks = null;
077        superBlock = null;
078        reg = null;
079    }
080
081    @Override
082    public void flush() throws IOException {
083        // do nothing
084    }
085
086    public boolean isEmpty() {
087        return buf.length() == 0 && segments.isEmpty() && blocks.isEmpty();
088    }
089
090    @Override
091    public void write(char[] cbuf, int off, int len) throws IOException {
092        if (!suppressOutput) {
093            buf.append(cbuf, off, len);
094        }
095    }
096
097    public void writeBlock(BlockWriter bw) {
098        if (!suppressOutput) {
099            // add the current buffer to the segments list
100            segments.add(buf.toString());
101            // reset buffer
102            buf.setLength(0);
103            // ad the sub block to the children block list
104            blocks.add(bw.name);
105        }
106        // inform the container about the new block
107        reg.addBlock(bw.name, bw);
108    }
109
110    public void writeSuperBlock() {
111        if (!suppressOutput) {
112            segments.add(buf.toString()); // add the current buffer to the
113            // segments list
114            buf.setLength(0); // reset buffer
115            blocks.add(".."); // add a special key that represent the super
116            // block
117        }
118    }
119
120    public void copyTo(Writer writer) throws TemplateException, IOException {
121        // check first if you need to suppress this block
122        if (ifBlockDefined != null) {
123            BlockWriter bw = reg.getBlock(ifBlockDefined);
124            if (bw == null || bw.isEmpty()) {
125                return;
126            }
127        }
128        for (int i = 0, len = segments.size(); i < len; i++) {
129            writer.write(segments.get(i));
130            String key = blocks.get(i);
131            BlockWriter bw = null;
132            if (key == "..") { // the super block
133                bw = superBlock;
134            } else { // a regular block
135                bw = reg.getBlock(key);
136            }
137            bw.copyTo(writer);
138        }
139        writer.write(buf.toString());
140    }
141
142    @Override
143    public String toString() {
144        return name + "@" + page;
145    }
146}