/**
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
* the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
*
* Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
* graphic logo is a trademark of OpenMRS Inc.
*/
package org.openmrs.module.xforms;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.kxml2.kdom.Element;
import org.openmrs.Patient;
import org.openmrs.Person;
import org.openmrs.Relationship;
import org.openmrs.RelationshipType;
import org.openmrs.api.context.Context;
public class RelativeBuilder {
public static final String NODE_RELATIVE = "patient_relative";
public static final String NODE_PERSON = "patient_relative.person";
public static final String NODE_RELATIONSHIP = "patient_relative.relationship";
public static final String BIND_RELATIVE = "patient_relative";
public static final String BIND_PERSON = "patient_relative.person";
public static final String BIND_RELATIONSHIP = "patient_relative.relationship";
private static final Log log = LogFactory.getLog(RelativeBuilder.class);
public static void build(Element modelElement, Element bodyNode, Element dataNode) {
buildBindNodes(modelElement);
buildInputNodes(bodyNode);
}
private static void buildBindNodes(Element modelElement) {
//Create bind node for relative.
Element bindNode = modelElement.createElement(XformBuilder.NAMESPACE_XFORMS, null);
bindNode.setName(XformBuilder.NODE_BIND);
bindNode.setAttribute(null, XformBuilder.ATTRIBUTE_ID, BIND_RELATIVE);
bindNode.setAttribute(null, XformBuilder.ATTRIBUTE_NODESET, "/form/patient/patient_relative");
modelElement.addChild(Element.ELEMENT, bindNode);
//Create bind node for person.
bindNode = modelElement.createElement(XformBuilder.NAMESPACE_XFORMS, null);
bindNode.setName(XformBuilder.NODE_BIND);
bindNode.setAttribute(null, XformBuilder.ATTRIBUTE_ID, BIND_PERSON);
bindNode.setAttribute(null, XformBuilder.ATTRIBUTE_NODESET, "/form/patient/patient_relative/patient_relative.person");
modelElement.addChild(Element.ELEMENT, bindNode);
//Create bind node for relationship.
bindNode = modelElement.createElement(XformBuilder.NAMESPACE_XFORMS, null);
bindNode.setName(XformBuilder.NODE_BIND);
bindNode.setAttribute(null, XformBuilder.ATTRIBUTE_ID, BIND_RELATIONSHIP);
bindNode.setAttribute(null, XformBuilder.ATTRIBUTE_NODESET,
"/form/patient/patient_relative/patient_relative.relationship");
modelElement.addChild(Element.ELEMENT, bindNode);
}
private static void buildInputNodes(Element bodyNode) {
Element repeatNode = buildRepeatInputNode(bodyNode);
buildPersonInputNode(repeatNode);
buildRelationshipInputNode(repeatNode);
}
private static Element buildRepeatInputNode(Element bodyNode) {
//Create the parent repeat ui node.
Element groupNode = bodyNode.createElement(XformBuilder.NAMESPACE_XFORMS, null);
groupNode.setName(XformBuilder.NODE_GROUP);
bodyNode.addChild(Element.ELEMENT, groupNode);
Element labelNode = bodyNode.createElement(XformBuilder.NAMESPACE_XFORMS, null);
labelNode.setName(XformBuilder.NODE_LABEL);
labelNode.addChild(Element.TEXT, "RELATIONSHIPS");
groupNode.addChild(Element.ELEMENT, labelNode);
Element hintNode = bodyNode.createElement(XformBuilder.NAMESPACE_XFORMS, null);
hintNode.setName(XformBuilder.NODE_HINT);
hintNode.addChild(Element.TEXT, "Relationships that this patient has.");
groupNode.addChild(Element.ELEMENT, hintNode);
Element repeatNode = bodyNode.createElement(XformBuilder.NAMESPACE_XFORMS, null);
repeatNode.setName(XformBuilder.CONTROL_REPEAT);
repeatNode.setAttribute(null, XformBuilder.ATTRIBUTE_BIND, BIND_RELATIVE);
groupNode.addChild(Element.ELEMENT, repeatNode);
return repeatNode;
}
private static void buildPersonInputNode(Element repeatNode) {
//Create person input node.
Element inputNode = repeatNode.createElement(XformBuilder.NAMESPACE_XFORMS, null);
inputNode.setName(XformBuilder.CONTROL_INPUT);
inputNode.setAttribute(null, XformBuilder.ATTRIBUTE_BIND, BIND_PERSON);
repeatNode.addChild(Element.ELEMENT, inputNode);
//Create person label.
Element labelNode = repeatNode.createElement(XformBuilder.NAMESPACE_XFORMS, null);
labelNode.setName(XformBuilder.NODE_LABEL);
labelNode.addChild(Element.TEXT, "RELATIVE");
inputNode.addChild(Element.ELEMENT, labelNode);
repeatNode.addChild(Element.ELEMENT, inputNode);
}
private static void buildRelationshipInputNode(Element repeatNode) {
//Create relationship input node.
Element inputNode = repeatNode.createElement(XformBuilder.NAMESPACE_XFORMS, null);
inputNode.setName(XformBuilder.CONTROL_SELECT1);
inputNode.setAttribute(null, XformBuilder.ATTRIBUTE_BIND, BIND_RELATIONSHIP);
populateRelationshipTypes(inputNode);
repeatNode.addChild(Element.ELEMENT, inputNode);
//Create relationship label.
Element labelNode = repeatNode.createElement(XformBuilder.NAMESPACE_XFORMS, null);
labelNode.setName(XformBuilder.NODE_LABEL);
labelNode.addChild(Element.TEXT, "RELATIONSHIP");
inputNode.addChild(Element.ELEMENT, labelNode);
repeatNode.addChild(Element.ELEMENT, inputNode);
}
private static void populateRelationshipTypes(Element controlNode) {
List<RelationshipType> relationshipTypes = Context.getPersonService().getAllRelationshipTypes(false);
for (RelationshipType type : relationshipTypes) {
Element itemNode;
//The value is of the form relationTypeId:A
itemNode = createRelationTypeOptionNode(type, controlNode, true);
controlNode.addChild(Element.ELEMENT, itemNode);
//For relationships like sibling/sibling just display one option. Otherwise, we need 2
//items for each side of the relationship, one for each side of the relationship so that
//the user can select which side the of the relationship the relative is i.e A Vs B
if (!type.getbIsToA().equalsIgnoreCase(type.getaIsToB())) {
itemNode = createRelationTypeOptionNode(type, controlNode, false);
controlNode.addChild(Element.ELEMENT, itemNode);
}
}
}
/**
* Creates a node for a select option for the specified relation type
*
* @param relationshipType the relationshipType object.
* @param controlNode the select node
* @param isA specifies which side of the relationship we are adding the option for
* @return the Element for the select option
*/
private static Element createRelationTypeOptionNode(RelationshipType relationshipType, Element controlNode, boolean isA) {
Element itemNode = controlNode.createElement(XformBuilder.NAMESPACE_XFORMS, null);
itemNode.setName(XformBuilder.NODE_ITEM);
Element node = itemNode.createElement(XformBuilder.NAMESPACE_XFORMS, null);
node.setName(XformBuilder.NODE_LABEL);
node.addChild(Element.TEXT, "is " + ((isA) ? relationshipType.getaIsToB() : relationshipType.getbIsToA()) + " ["
+ relationshipType.getRelationshipTypeId() + "]");
itemNode.addChild(Element.ELEMENT, node);
node = itemNode.createElement(XformBuilder.NAMESPACE_XFORMS, null);
node.setName(XformBuilder.NODE_VALUE);
node.addChild(Element.TEXT, relationshipType.getRelationshipTypeId() + ((isA) ? "A" : "B"));
itemNode.addChild(Element.ELEMENT, node);
return itemNode;
}
public static void fillRelationships(Patient patient, Element dataNode) throws Exception {
Element relativeNode = XformBuilder.getElement(dataNode, NODE_RELATIVE);
if (relativeNode == null)
return;
int index = 0;
List<Relationship> relationships = Context.getPersonService().getRelationshipsByPerson(patient);
for (Relationship relationship : relationships) {
if (++index > 1)
relativeNode = XformBuilder.createCopy(relativeNode, new ArrayList<String>());
relativeNode.setAttribute(null, XformBuilder.ATTRIBUTE_UUID, relationship.getUuid());
String personUuid;
String relative;
if (getPersonId(patient).equals(relationship.getPersonA().getPersonId())) {
relative = relationship.getPersonB().getPersonName() + " - "
+ getPatientIdentifier(relationship.getPersonB());
personUuid = relationship.getPersonB().getUuid();
} else {
relative = relationship.getPersonA().getPersonName() + " - "
+ getPatientIdentifier(relationship.getPersonA());
personUuid = relationship.getPersonA().getUuid();
}
Element personNode = XformBuilder.getElement(relativeNode, NODE_PERSON);
personNode.setAttribute(null, "displayValue", relative);
personNode.setAttribute(null, "default", "false()");
XformBuilder.setNodeValue(personNode, personUuid);
Element relationshipNode = XformBuilder.getElement(relativeNode, NODE_RELATIONSHIP);
relationshipNode.setAttribute(null, "default", "false()");
XformBuilder.setNodeValue(relationshipNode, relationship.getRelationshipType().getRelationshipTypeId()
+ ((relationship.getPersonA().getPersonId().equals(patient.getPersonId())) ? "B" : "A"));
}
}
private static Integer getPersonId(Patient patient) throws Exception {
try {
return patient.getPersonId();
}
catch (NoSuchMethodError ex) {
Method method = patient.getClass().getMethod("getPerson", null);
return ((Person) method.invoke(patient, null)).getPersonId();
}
}
private static String getPatientIdentifier(Person person) throws Exception {
try {
Patient patient = Context.getPatientService().getPatient(person.getPersonId());
if (getPersonId(patient) == person.getPersonId()) {
return patient.getPatientIdentifier().getIdentifier();
}
}
catch(Exception ex) {
log.error(ex.getMessage(), ex);
}
return "";
}
}