package net.sf.egonet.model; import java.util.ArrayList; import java.util.List; import net.sf.egonet.model.Answer.AnswerType; import net.sf.functionalj.tuple.Pair; import net.sf.functionalj.tuple.Triple; import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.collect.Lists; public class Expression extends Entity { public static enum Operator {All,Some,None,Equals,Contains,Greater,GreaterOrEqual,LessOrEqual,Less,Count,Sum} public static enum Type {Compound,Selection,Text,Number,Counting,Comparison} private String name; private Type type; private Operator operator; protected String valueDB; protected String valueDBOld; private Long studyId; private Long questionId; private Boolean resultForUnanswered; public Expression(Study study) { type = Type.Compound; operator = Operator.Some; studyId = study.getId(); setDefaultValues(); } public Expression(Question question) { type = typeOfQuestion(question); studyId = question.getStudyId(); questionId = question.getId(); setDefaultValues(); } public static Expression comparisonAbout(Expression expression) { Expression result = new Expression(); result.setName(""); result.type = Type.Comparison; result.setOperator(Operator.Equals); result.studyId = expression.studyId; result.setValue(new Pair<Integer,Long>(1,expression.getId())); return result; } public static Expression countingForStudy(Study study) { Expression result = new Expression(study); result.type = Type.Counting; result.setOperator(Operator.Sum); List<Long> noneSelected = Lists.newArrayList(); result.setValue(new Triple<Integer,List<Long>,List<Long>>(1,noneSelected,noneSelected)); return result; } public String toString() { return name == null || name.isEmpty() ? "Untitled expression" : name; } public Boolean isSimpleExpression() { return this.getQuestionId() != null; } public Boolean getResultForUnanswered() { return resultForUnanswered == null ? false : resultForUnanswered; } public void setResultForUnanswered(Boolean resultForUnanswered) { this.resultForUnanswered = resultForUnanswered; } public static Type typeOfQuestion(AnswerType answerType) { if(answerType.equals(AnswerType.NUMERICAL)) { return Type.Number; } if(answerType.equals(AnswerType.TEXTUAL) || answerType.equals(AnswerType.TEXTUAL_PP)) { return Type.Text; } return Type.Selection; } public static Type typeOfQuestion(Question question) { return typeOfQuestion(question.getAnswerType()); } private void setDefaultValues() { this.name = ""; setValueDB(type.equals(Type.Number) ? "0" : ""); } public Long getStudyId() { return studyId; } public Long getQuestionId() { return questionId; } public Type getType() { return type; } public void setName(String name) { this.name = name; } public String getName() { return name; } public void setOperator(Operator operator) { if(allowedOperators().contains(operator)) { this.operator = operator; } else { throw new IllegalArgumentException("Operator "+operator+" not allowed for type "+type); } } public Operator getOperator() { return operator; } public void setValue(Object value) { if(value != null) { if(type.equals(Type.Comparison)) { Pair<Integer,Long> numberExpr = (Pair<Integer,Long>) value; setValueDB(numberExpr.getFirst()+":"+numberExpr.getSecond()); } else if(type.equals(Type.Counting)) { Triple<Integer,List<Long>,List<Long>> numberExprsQuests = (Triple<Integer,List<Long>,List<Long>>) value; setValueDB(numberExprsQuests.getFirst()+":"+ Joiner.on(",").join(numberExprsQuests.getSecond())+":"+ Joiner.on(",").join(numberExprsQuests.getThird())); } else if(type.equals(Type.Compound) || type.equals(Type.Selection)) { setValueDB(Joiner.on(",").join((List<Long>) value)); } else if(type.equals(Type.Number) || type.equals(Type.Text)) { setValueDB(value.toString()); } else { throw new RuntimeException("Can't setValue("+value+") for Expression " + "because no case provided for type "+type); } } } public Object getValue() { String valDB = getValueDB(); if(type.equals(Type.Comparison)) { try { String[] numberExpr = valDB.split(":"); if(numberExpr.length == 2) { return new Pair<Integer,Long>( Integer.parseInt(numberExpr[0]), Long.parseLong(numberExpr[1])); } else { throw new RuntimeException("Wrong number of : separated parts in value."); } } catch(Exception ex) { throw new RuntimeException( "Invalid value in comparison expression: name="+ getName()+", value="+getValueDB(), ex); } } if(type.equals(Type.Counting)) { try { List<String> numberExprsQuests = colonSep(valDB); if(numberExprsQuests.size() == 3) { Integer number = Integer.parseInt(numberExprsQuests.get(0)); List<Long> exprs = commaSepToLongs(numberExprsQuests.get(1)); List<Long> quests = commaSepToLongs(numberExprsQuests.get(2)); return new Triple<Integer,List<Long>,List<Long>>(number,exprs,quests); } else { throw new RuntimeException("Wrong number of : separated parts in value: valDB"); } } catch(Exception ex) { throw new RuntimeException( "Invalid value in counting expression: name="+ getName()+", value="+getValueDB(), ex); } } if(type.equals(Type.Compound) || type.equals(Type.Selection)) { return commaSepToLongs(valDB); } if(type.equals(Type.Number)) { return getValueDB() == null ? null : Integer.parseInt(getValueDB()); } if(type.equals(Type.Text)) { return getValueDB(); } throw new RuntimeException("Can't getValue() for Expression because no case provided for type "+type); } public static List<String> colonSep(String target) { int startSearch = 0, nextColon = 0; List<String> results = Lists.newArrayList(); while(nextColon > -1) { nextColon = target.indexOf(":", startSearch); if(nextColon < 0) { results.add(target.substring(startSearch)); } else { results.add(target.substring(startSearch, nextColon)); startSearch = nextColon + 1; } } return results; } private static List<Long> commaSepToLongs(String commaSep) { return commaSep == null || commaSep.isEmpty() ? new ArrayList<Long>() : Lists.transform(Lists.newArrayList(commaSep.split(",")), parseLong); } private static Function<String,Long> parseLong = new Function<String,Long>() { public Long apply(String string) { return Long.parseLong(string); } }; public List<Operator> allowedOperators() { return allowedOperators(this.type); } public static List<Operator> allowedOperators(Type type) { if(type.equals(Type.Comparison)) { return allowedOperators(Type.Number); } if(type.equals(Type.Counting)) { return Lists.newArrayList(Operator.Count,Operator.Sum); } if(type.equals(Type.Compound)) { return Lists.newArrayList(Operator.All,Operator.Some,Operator.None); } if(type.equals(Type.Selection)) { return Lists.newArrayList(Operator.All,Operator.Some,Operator.None); } if(type.equals(Type.Text)) { return Lists.newArrayList(Operator.Equals,Operator.Contains); } if(type.equals(Type.Number)) { return Lists.newArrayList( Operator.Greater, Operator.GreaterOrEqual, Operator.Equals, Operator.LessOrEqual, Operator.Less); } throw new RuntimeException("Unrecognized expression type: "+type); } // For Hibernate only public Expression() { } public void setTypeDB(String typeString) { if(typeString != null && ! typeString.isEmpty()) { this.type = Type.valueOf(typeString); } } public String getTypeDB() { return type == null ? null : type.name(); } public void setOperatorDB(String operatorString) { if(operatorString != null && ! operatorString.isEmpty()) { this.operator = Operator.valueOf(operatorString); } } public String getOperatorDB() { return operator == null ? null : operator.name(); } public void setStudyId(Long studyId) { this.studyId = studyId; } public void setQuestionId(Long questionId) { this.questionId = questionId; } // ----------------------------------------- public void setValueDB(String valueString) { this.valueDB = valueString; } protected void setValueDBOld(String valueString) { this.valueDBOld = valueString; } public String getValueDB() { return migrateToText(this,"valueDB"); } protected String getValueDBOld() { return null; } }