1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
25 
26 import java.io.ByteArrayOutputStream;
27 import java.io.IOException;
28 import java.util.Vector;
29 import java.util.Enumeration;
30 
31 import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.Workbook;
32 
33 /**
34  * This Helper class provides a simplified interface to conversion between PocketXL formula representation
35  * and Calc formula representation.<p>
36  * The class is used by {@link org.openoffice.xmerge.converter.xml.sxc.pexcel.Records.Formula}
37  */
38 public class FormulaHelper {
39 
40 	private static FormulaParser parser;
41 	private static FormulaCompiler compiler;
42 	private static TokenEncoder encoder;
43 	private static TokenDecoder decoder;
44 	private boolean rangeType = false;
45 	private boolean expressionType = false;
46 
47 	static {
48 		parser   = new FormulaParser();
49 		compiler = new FormulaCompiler();
50 		encoder = new TokenEncoder();
51 		decoder  = new TokenDecoder();
52 	}
53 
54 	/**
55 	 * Sets the workbook cache so that global data such as
56 	 * <code>DefinedNames</code>, <code>Boundsheets</code> can be read
57 	 *
58 	 * @param wb Wrokbook object containing all the global data
59 	 */
setWorkbook(Workbook wb)60 	public void setWorkbook(Workbook wb) {
61 
62 		encoder.setWorkbook(wb);
63 		decoder.setWorkbook(wb);
64 		parser.setWorkbook(wb);
65 	}
66 
67 	/**
68 	 * Convertes a string representation of a calc formula into an array of PocketXL bytes
69 	 * @param	formula	The Formula String (e.g. 1+SUM(A1,B1))
70 	 *
71 	 * @throws	UnsupportedFunctionException	Thrown if a function in the formula is nto supported by Pocket Excel
72 	 * @throws	FormulaParsingException	Thrown when the formula is not well formed
73 	 *
74 	 */
convertCalcToPXL(String formula)75 	public byte[] convertCalcToPXL(String formula) throws UnsupportedFunctionException, FormulaParsingException {
76 
77 		Vector parseTokens = parser.parse(formula);
78 		Vector rpnTokens = compiler.infix2RPN(parseTokens);
79 
80 		ByteArrayOutputStream bytes = null;
81 		try {
82 			bytes = new ByteArrayOutputStream();
83 			for (Enumeration e = rpnTokens.elements(); e.hasMoreElements();) {
84 				Token t = (Token)e.nextElement();
85 				bytes.write(encoder.getByte(t));
86 			}
87 		} catch (IOException e) {
88 		}
89 
90 		return bytes.toByteArray();
91 	}
92 
93 	/**
94 	 * Converts a PocketXL byte array into a Calc function string
95 	 * @param 	formula	A byte array that contains the PocketXL bytes for a formula
96 	 *
97 	 */
convertPXLToCalc(byte[] formula)98 	public String convertPXLToCalc(byte[] formula) {
99 
100 		Vector parseTokens = decoder.getTokenVector(formula);
101 		Vector infixTokens = compiler.RPN2Infix(parseTokens);
102 
103 		StringBuffer buff = new StringBuffer();
104 		for (Enumeration e = infixTokens.elements();e.hasMoreElements();) {
105 			Token t = (Token)e.nextElement();
106 			buff.append(t.toString());
107 			// If we are parsing a Name definition we need to know if it is of
108 			// type range or expression
109 			if(!t.isOperand()) {
110 				expressionType = true;
111 			}
112 		}
113 		if(!expressionType) {
114 			rangeType = true;
115 		}
116 		return "=" + buff.toString();
117 	}
118 
119 	/**
120 	 * Returns a boolean indicating whether or not the byte[] parsed is of
121 	 * type range. This means it contains only a cell reference and no
122 	 * operators. This is necessry because the syntax for range and expression
123 	 * types differs. This is only of interest when dealing with
124 	 * <code>DefinedNames</code> and not <code>Formula</code>
125 	 *
126 	 * @return a boolean true if of type range otherwise false
127 	 *
128 	 */
isRangeType()129 	 public boolean isRangeType() {
130 
131 		return rangeType;
132     }
133 
134 	/**
135 	 * Returns a boolean indicating whether or not the byte[] parsed is of
136 	 * type expression. This means it contains operators. This is necessry
137 	 * because the syntax for range and expression types differs. This is
138 	 * only of interest when dealing with <code>DefinedNames</code> and not
139 	 * <code>Formula</code>
140 	 *
141 	 * @return a boolean true if of type expression otherwise false
142 	 *
143 	 */
isExpressionType()144 	 public boolean isExpressionType() {
145 
146 		return expressionType;
147     }
148 }
149