001/*
002// This software is subject to the terms of the Eclipse Public License v1.0
003// Agreement, available at the following URL:
004// http://www.eclipse.org/legal/epl-v10.html.
005// You must accept the terms of that agreement to use this software.
006//
007// Copyright (C) 2006-2011 Pentaho
008// All Rights Reserved.
009*/
010package mondrian.calc;
011
012import org.apache.commons.collections.map.CompositeMap;
013
014import java.io.PrintWriter;
015import java.util.IdentityHashMap;
016import java.util.Map;
017
018/**
019 * Visitor which serializes an expression to text.
020 *
021 * @author jhyde
022 * @since Dec 23, 2005
023 */
024public class CalcWriter {
025    private static final int INDENT = 4;
026    private static String BIG_STRING = "                ";
027
028    private final PrintWriter writer;
029    private final boolean profiling;
030    private int linePrefixLength;
031    private final Map<Calc, Map<String, Object>> parentArgMap =
032        new IdentityHashMap<Calc, Map<String, Object>>();
033
034    public CalcWriter(PrintWriter writer, boolean profiling) {
035        this.writer = writer;
036        this.profiling = profiling;
037    }
038
039    public PrintWriter getWriter() {
040        return writer;
041    }
042
043    public void visitChild(int ordinal, Calc calc) {
044        indent();
045        calc.accept(this);
046        outdent();
047    }
048
049    public void visitCalc(
050        Calc calc,
051        String name,
052        Map<String, Object> arguments,
053        Calc[] childCalcs)
054    {
055        writer.print(getLinePrefix());
056        writer.print(name);
057        final Map<String, Object> parentArgs = parentArgMap.get(calc);
058        if (parentArgs != null && !parentArgs.isEmpty()) {
059            //noinspection unchecked
060            arguments = new CompositeMap(arguments, parentArgs);
061        }
062        if (!arguments.isEmpty()) {
063            writer.print("(");
064            int k = 0;
065            for (Map.Entry<String, Object> entry : arguments.entrySet()) {
066                if (k++ > 0) {
067                    writer.print(", ");
068                }
069                writer.print(entry.getKey());
070                writer.print("=");
071                writer.print(entry.getValue());
072            }
073            writer.print(")");
074        }
075        writer.println();
076        int k = 0;
077        for (Calc childCalc : childCalcs) {
078            visitChild(k++, childCalc);
079        }
080    }
081
082    /**
083     * Increases the indentation level.
084     */
085    public void indent() {
086        linePrefixLength += INDENT;
087    }
088
089    /**
090     * Decreases the indentation level.
091     */
092    public void outdent() {
093        linePrefixLength -= INDENT;
094    }
095
096    private String getLinePrefix() {
097        return spaces(linePrefixLength);
098    }
099
100    /**
101     * Returns a string of N spaces.
102     * @param n Number of spaces
103     * @return String of N spaces
104     */
105    private static synchronized String spaces(int n)
106    {
107        while (n > BIG_STRING.length()) {
108            BIG_STRING = BIG_STRING + BIG_STRING;
109        }
110        return BIG_STRING.substring(0, n);
111    }
112
113    public void setParentArgs(Calc calc, Map<String, Object> argumentMap) {
114        parentArgMap.put(calc, argumentMap);
115    }
116
117    /**
118     * Whether to print out attributes relating to how a statement was actually
119     * executed. If false, client should only send attributes relating to the
120     * plan.
121     *
122     * @return Whether client should send attributes about profiling
123     */
124    public boolean enableProfiling() {
125        return profiling;
126    }
127}
128
129// End CalcWriter.java