/*
* OpenClinica is distributed under the
* GNU Lesser General Public License (GNU LGPL).
* For details see: http://www.openclinica.org/license
* copyright 2003-2005 Akaza Research
*/
package org.akaza.openclinica.logic.score;
/**
* The <code>Parser</code> is used to parse expression String into ScoreToken
* ArrayList and parse item variables in expression.
*
* @author ywang
* @version 1.0, 01-16-2008
*
*/
import org.akaza.openclinica.bean.submit.ItemBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.TreeSet;
public class Parser {
private Logger logger = LoggerFactory.getLogger(getClass().getName());
private HashMap<String, ItemBean> map;
private HashMap<String, String> itemdata;
private StringBuffer errors;
public Parser(HashMap<String, ItemBean> map, HashMap<String, String> itemdata) {
this.map = map;
this.itemdata = itemdata;
this.errors = new StringBuffer();
}
/**
* Convert expression string to ScoreToken arrayList;
* <p>
* Supported expression could start with a key word 'func' and include
* <ul>
* <li>operators +, -, *, /
* <li>parenthesises (, )
* <li>formula as the pattern that starts with formula name, formula
* arguments are grouped in parenthesises with delimiter as ',' For example:
* sum(item_x,item_y,item_z)
* </ul>
*
* @param expression
* @return
*/
public ArrayList<ScoreToken> parseScoreTokens(String expression) {
ArrayList<ScoreToken> list = new ArrayList<ScoreToken>();
if (expression == null || expression.length() < 1) {
return list;
}
// process the prefix
String exp = expression;
if (exp.startsWith("func:")) {
exp = exp.substring(5).trim();
}
exp = exp.replaceAll("##", ",");
exp = exp.replace(" ", "");
char contents[] = exp.toCharArray();
String token = "";
int pos = 0;
int listpos = 0;
ScoreToken scoretoken = new ScoreToken();
while (pos < contents.length) {
char c = contents[pos];
// ignore spaces
if (c == ' ') {
// do nothing
} else if (ScoreUtil.isOperator(c)) {
if (token.length() > 0) {
scoretoken = new ScoreToken(ScoreSymbol.TERM_SYMBOL, token);
list.add(scoretoken);
++listpos;
token = "";
}
scoretoken = new ScoreToken(ScoreSymbol.ARITHMETIC_OPERATOR_SYMBOL, c + "");
list.add(scoretoken);
++listpos;
} else if (c == '(') {
String funcname = ScoreUtil.getFunctionName(token);
if (funcname != null) {
scoretoken = new ScoreToken(ScoreSymbol.FUNCTION_SYMBOL, token);
list.add(scoretoken);
++listpos;
token = "";
} else if (token.length() > 0) {
scoretoken = new ScoreToken(ScoreSymbol.TERM_SYMBOL, token);
list.add(scoretoken);
++listpos;
token = "";
}
scoretoken = new ScoreToken(ScoreSymbol.OPEN_PARENTH_SYMBOL, c + "");
list.add(scoretoken);
++listpos;
} else if (c == ')') {
if (token.length() > 0) {
scoretoken = new ScoreToken(ScoreSymbol.TERM_SYMBOL, token);
list.add(scoretoken);
++listpos;
token = "";
}
scoretoken = new ScoreToken(ScoreSymbol.CLOSE_PARENTH_SYMBOL, c + "");
list.add(scoretoken);
++listpos;
} else if (c == ',') {
if (token.length() > 0) {
scoretoken = new ScoreToken(ScoreSymbol.TERM_SYMBOL, token);
list.add(scoretoken);
++listpos;
token = "";
}
scoretoken = new ScoreToken(ScoreSymbol.COMMA_SYMBOL, c + "");
list.add(scoretoken);
++listpos;
} else {
token += c;
}
pos++;
}
if (token.length() > 0) {
scoretoken = new ScoreToken(ScoreSymbol.TERM_SYMBOL, token);
list.add(scoretoken);
}
return list;
}
/**
* Given a ScoreToken ArrayList, assign variables with their values
*
* @param expression
* @param ordinal
* @return
*/
public ArrayList<ScoreToken> assignVariables(ArrayList<ScoreToken> expression, int ordinal) {
if (expression.isEmpty()) {
errors.append("Expression is empty" + "; ");
return expression;
}
boolean isEmpty = false;
for (int i = 0; i < expression.size(); ++i) {
ScoreToken t = expression.get(i);
if (t.getSymbol() == ScoreSymbol.TERM_SYMBOL) {
char next = i < expression.size() - 1 ? expression.get(i + 1).getSymbol() : ' ';
if (map.containsKey(t.getName().trim()) && next != '(') {
// String key = ((ItemBean)map.get(var.trim())).getId() +
// "_" + ordinal;
String key = map.get(t.getName().trim()).getId() + "_" + ordinal;
if (itemdata.containsKey(key)) {
String idvalue = itemdata.get(key);
if (idvalue.length() > 0) {
t.setName(idvalue);
} else {
// if no item value found, score result will be
// empty
errors.append(" " + t.getName().trim() + " " + "is empty" + "; ");
isEmpty = true;
}
} else {
// if no item value found, score result will be empty
errors.append(" " + t.getName().trim() + " " + "is empty" + "; ");
isEmpty = true;
}
}
}
}
if (isEmpty) {
return new ArrayList<ScoreToken>();
} else {
return expression;
}
}
/**
* Given a ScoreToken ArrayList, assign variables with their values
*
* @param expression
* @param itemOrdinals
* @return
*/
public ArrayList<ScoreToken> assignVariables(ArrayList<ScoreToken> expression, HashMap<Integer, TreeSet<Integer>> itemOrdinals) {
if (expression.isEmpty()) {
errors.append("Expression is empty" + "; ");
return expression;
}
boolean isEmpty = false;
ArrayList<ScoreToken> list = new ArrayList<ScoreToken>();
for (int i = 0; i < expression.size(); ++i) {
ScoreToken t = expression.get(i);
if (t.getSymbol() != ScoreSymbol.TERM_SYMBOL) {
list.add(t);
} else {
char next = i < expression.size() - 1 ? expression.get(i + 1).getSymbol() : ' ';
if (map.containsKey(t.getName().trim()) && next != '(') {
int itemId = map.get(t.getName().trim()).getId();
if (itemOrdinals.containsKey(itemId)) {
TreeSet<Integer> ordinals = itemOrdinals.get(itemId);
int groupsize = ordinals.size();
int count = 0;
Iterator it = ordinals.iterator();
while (it.hasNext()) {
String key = itemId + "_" + it.next();
String idvalue = "";
if (itemdata.containsKey(key)) {
idvalue = itemdata.get(key);
if (idvalue.length() > 0) {
ScoreToken temp0 = new ScoreToken();
temp0.setSymbol(ScoreSymbol.TERM_SYMBOL);
temp0.setName(idvalue);
list.add(temp0);
if (count < groupsize - 1) {
ScoreToken temp = new ScoreToken(ScoreSymbol.COMMA_SYMBOL, ",");
list.add(temp);
}
} else {
// if no item value found, score result will
// be empty
errors.append(" " + t.getName().trim() + " " + "is empty" + "; ");
isEmpty = true;
}
} else {
// if no item value found, score result will be
// empty
errors.append(" " + t.getName().trim() + " " + "is empty" + "; ");
isEmpty = true;
}
++count;
}
} else {
errors.append(" " + t.getName().trim() + " " + "is not available" + "; ");
isEmpty = true;
}
}
}
}
if (isEmpty) {
return new ArrayList<ScoreToken>();
} else {
return list;
}
}
public boolean isChanged(TreeSet<String> changedItems, ArrayList<ScoreToken> expression) {
for (ScoreToken t : expression) {
if (t.getSymbol() == ScoreSymbol.TERM_SYMBOL) {
if (changedItems.contains(t.getName().trim()))
return true;
}
}
return false;
}
/**
* A helper function to create a function class name.
*
* @param functionName
* a function name.
* @return the function class name.
*
* @author Hailong Wang, 08/25/2006
*/
public static String convertToClassName(String packageName, String functionName) {
if (functionName == null || functionName.length() == 0) {
return null;
}
return packageName + "." + functionName.substring(0, 1).toUpperCase() + functionName.substring(1, functionName.length());
}
public HashMap<String, ItemBean> getMap() {
return this.map;
}
public HashMap<String, String> getItemData() {
return this.itemdata;
}
public StringBuffer getErrors() {
return this.errors;
}
public void setErrors(StringBuffer e) {
this.errors = e;
}
}