package org.openrosa.client.xforms;
import java.util.Vector;
import org.openrosa.client.model.Condition;
import org.openrosa.client.model.FormDef;
import org.openrosa.client.model.IFormElement;
import org.openrosa.client.model.QuestionDef;
import org.openrosa.client.model.SkipRule;
import org.openrosa.client.model.ValidationRule;
import org.openrosa.client.model.ModelConstants;
import org.openrosa.client.xforms.XformConstants;
import com.google.gwt.xml.client.Element;
/**
* Builds constraint attributes of xforms documents from validation rule definition objects.
*
* @author daniel
*
*/
public class ConstraintBuilder {
/**
* All methods in this class are static and hence we expect no external
* Instantiation of this class.
*/
private ConstraintBuilder(){
}
/**
* A slightly higher level function that figures out
* if the question associated with this rule has
* an 'advanced' relevant or if it should be extracted
* out of the SkipRule in the traditional way (for less
* complex relevants)
* @param rule The SkipRule associated with the specified skip rule.
* @param qID The internal ID for the question for which the relevant will be generated
* @param formDef
* @return
*/
public static String getConstraintFromRule(ValidationRule rule, int qID, FormDef formDef){
IFormElement elementDef = formDef.getElement(qID);
String constraint = "";
if(elementDef.hasAdvancedConstraint()){
constraint = elementDef.getAdvancedConstraint();
if(constraint != null){
return constraint;
}else{
return "";
}
}
Vector conditions = rule.getConditions();
if(conditions == null || conditions.size() == 0){
return null;
}
for(int i=0; i<conditions.size(); i++){
if(constraint.length() > 0){
constraint += XformBuilderUtil.getConditionsOperatorText(rule.getConditionsOperator());
}
constraint += fromValidationRuleCondition2Xform((Condition)conditions.elementAt(i),formDef,rule.getConditionsOperator());
}
return constraint;
}
/**
* Converts a validation rule to its xforms representation.
* The question definition object referenced by the validation rule
* is expected to already have reference to the xforms document nodes
* that we need to manipulate for the validation rule's xforms contents.
*
* @param rule the validation rule.
* @param formDef the form definition object.
*/
public static void fromValidationRule2Xform(ValidationRule rule, FormDef formDef){
QuestionDef questionDef = formDef.getQuestion(rule.getQuestionId());
if(questionDef == null){
formDef.removeValidationRule(rule);
return; //possibly question deleted.
}
Element node = questionDef.getBindNode();
if(node == null)
node = questionDef.getControlNode();
String constraint = getConstraintFromRule(rule,questionDef.getId(),formDef);
// constraint = constraint.replace(">", ">").replace("<", "<");
if(constraint == null){
node.removeAttribute(XformConstants.ATTRIBUTE_NAME_CONSTRAINT);
node.removeAttribute(XformConstants.ATTRIBUTE_NAME_CONSTRAINT_MESSAGE);
return;
}
// constraint = XmlUtil.escapeXMLAttribute(constraint);
node.setAttribute(XformConstants.ATTRIBUTE_NAME_CONSTRAINT, constraint);
node.setAttribute(XformConstants.ATTRIBUTE_NAME_CONSTRAINT_MESSAGE, rule.getErrorMessage());
}
/**
* Takes in a SkipRule and returns the completed Relevant
* attribute value
* @param rule
* @param formDef - the underlying formdef for this mess.
* @return - The reconstructed relevant attribute.
*/
public static String fromValidationRule2String(ValidationRule rule, FormDef formDef){
String constraint = "";
if(rule == null){
return constraint;
}
Vector conditions = rule.getConditions();
if(conditions == null){
return null;
}
for(int i=0; i<conditions.size(); i++){
if(constraint.length() > 0){
constraint += XformBuilderUtil.getConditionsOperatorText(rule.getConditionsOperator());
}
constraint += fromValidationRuleCondition2Xform((Condition)conditions.elementAt(i),
formDef,
rule.getConditionsOperator());
}
return constraint;
}
/**
* Creates an xforms representation of a validation rule condition.
*
* @param condition the condition object.
* @param formDef the form definition object to which the skip rule belongs.
* @param action the validation rule action.
* @param actionQtnDef the question referenced by the validation rule.
* @return the condition xforms representation.
*/
private static String fromValidationRuleCondition2Xform(Condition condition, FormDef formDef, int action){
String constraint = null;
QuestionDef questionDef = formDef.getQuestion(condition.getQuestionId());
if(questionDef != null){
String value = " '" + condition.getValue() + "'";
if(questionDef.getDataType() == QuestionDef.QTN_TYPE_BOOLEAN || questionDef.getDataType() == QuestionDef.QTN_TYPE_DECIMAL ||
questionDef.getDataType() == QuestionDef.QTN_TYPE_NUMERIC || questionDef.getDataType() == QuestionDef.QTN_TYPE_LONG ||
questionDef.getDataType() == QuestionDef.QTN_TYPE_REPEAT || condition.getFunction() == ModelConstants.FUNCTION_LENGTH ||
condition.getValue().endsWith("()"))
value = " " + condition.getValue();
constraint = ". ";
//if(actionQtnDef.getDataType() == QuestionDef.QTN_TYPE_REPEAT)
// constraint = "count(.) ";
if(condition.getFunction() == ModelConstants.FUNCTION_LENGTH)
constraint = "length(.) ";
if(condition.getOperator() == ModelConstants.OPERATOR_BETWEEN){
constraint += XformBuilderUtil.getXpathOperator(ModelConstants.OPERATOR_GREATER,action)+value + " and "+ "." + XformBuilderUtil.getXpathOperator( ModelConstants.OPERATOR_LESS,action)+ condition.getSecondValue();
}else if(condition.getOperator() == ModelConstants.OPERATOR_NOT_BETWEEN){
constraint +=XformBuilderUtil.getXpathOperator(ModelConstants.OPERATOR_GREATER,action)+condition.getSecondValue() + " or "+ "." + XformBuilderUtil.getXpathOperator( ModelConstants.OPERATOR_LESS,action)+value ;
}else if (condition.getOperator() == ModelConstants.OPERATOR_STARTS_WITH){
constraint += "starts-with(.,"+ value+")";
}else if (condition.getOperator() == ModelConstants.OPERATOR_NOT_START_WITH){
constraint += "not(starts-with(.,"+ value+"))";
}else if (condition.getOperator() == ModelConstants.OPERATOR_CONTAINS){
constraint += "contains(.,"+ value+")";
}else if (condition.getOperator() == ModelConstants.OPERATOR_NOT_CONTAIN){
constraint += "not(contains(.,"+ value+"))";
}else{
constraint += XformBuilderUtil.getXpathOperator(condition.getOperator(),action)+value;
}
}
return constraint;
}
}