package se.cambio.cds.util.export;
import org.openehr.rm.datatypes.basic.DataValue;
import org.openehr.rm.datatypes.basic.DvBoolean;
import org.openehr.rm.datatypes.quantity.*;
import org.openehr.rm.datatypes.quantity.datetime.DvDate;
import org.openehr.rm.datatypes.quantity.datetime.DvDateTime;
import org.openehr.rm.datatypes.quantity.datetime.DvDuration;
import org.openehr.rm.datatypes.quantity.datetime.DvTime;
import org.openehr.rm.datatypes.text.CodePhrase;
import org.openehr.rm.datatypes.text.DvCodedText;
import org.openehr.rm.datatypes.text.DvText;
import se.cambio.cds.gdl.model.Term;
import se.cambio.cds.gdl.model.TermDefinition;
import se.cambio.cds.util.DVUtil;
import se.cambio.openehr.controller.session.data.ArchetypeManager;
import se.cambio.openehr.controller.session.data.CodedTexts;
import se.cambio.openehr.controller.session.data.Ordinals;
import se.cambio.cm.model.archetype.vo.CodedTextVO;
import se.cambio.openehr.util.*;
import se.cambio.openehr.util.exceptions.InternalErrorException;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DVDefSerializer {
public static String VARTOKEN = "$";
private static Pattern clonePattern = Pattern.compile("\\.createDV\\([\\s]*\\$([^\\,\"]+),");
private static Pattern setLinePattern = Pattern.compile("\\.createDV\\([^\\,]+,[\\s]*\"(.*)\"\\)$");
private static Pattern assignationLinePattern = Pattern.compile("([^\\Q+-*/=\\E]+)([\\Q+-*/\\E]?)\\=\"\\+\\((.*)\\)\\+\"$");
public static Pattern dvReferencePattern = Pattern.compile("\\$([\\w]+)+\\Q.getDataValue()).get\\E([\\w]+)\\(\\)");
public static Pattern dvDefinitionPatternWithOutQuotes = Pattern.compile("new [a-zA-Z]+\\((.*)\\)$");
public static Pattern dvDefinitionPatternWithQuotes = Pattern.compile("new [a-zA-Z]+\\(\"(.*)\"\\)$");
public static Pattern dvDefinitionPattern = Pattern.compile("(new [a-zA-Z]+\\(.*\\))");
public static String commaSplitPatternOutsideParenthesis = ",(?![^(]*\\))";
public static String getDVInstantiation(DataValue dataValue){
if (dataValue instanceof DvQuantity){
StringBuilder sb = new StringBuilder();
sb.append("\"");
sb.append(((DvQuantity)dataValue).getUnits());
sb.append("\"");
sb.append(",");
sb.append(((DvQuantity)dataValue).getMagnitude());
sb.append(",");
sb.append(((DvQuantity)dataValue).getPrecision());
return getDVInstantiationWithoutQuotes(DvQuantity.class.getSimpleName(), sb.toString());
}if (dataValue instanceof DvDuration){
return getDVInstantiation(DvDuration.class.getSimpleName(), ((DvDuration)dataValue).getValue());
}if (dataValue instanceof DvDateTime){
DvDateTime dvDateTime = (DvDateTime)dataValue;
return getDVInstantiation(DvDateTime.class.getSimpleName(), dvDateTime.toString());
}if (dataValue instanceof DvDate){
DvDate dvDate = (DvDate)dataValue;
return getDVInstantiation(DvDate.class.getSimpleName(), dvDate.toString());
}if (dataValue instanceof DvTime){
DvTime dvTime = (DvTime)dataValue;
return getDVInstantiation(DvTime.class.getSimpleName(), dvTime.toString());
}if (dataValue instanceof DvOrdinal){
DvOrdinal dvOrdinal = (DvOrdinal)dataValue;
DvCodedText dvCodedText = dvOrdinal.getSymbol();
StringBuilder sb = new StringBuilder();
sb.append(dvOrdinal.getValue());
sb.append(",\"");
sb.append(dvCodedText.getValue());
sb.append("\",\"");
sb.append(dvCodedText.getDefiningCode().getTerminologyId().getValue());
sb.append("\",\"");
sb.append(dvCodedText.getDefiningCode().getCodeString());
sb.append("\"");
return getDVInstantiationWithoutQuotes(DvOrdinal.class.getSimpleName(), sb.toString());
}if (dataValue instanceof DvCodedText){
DvCodedText dvCodedText = (DvCodedText)dataValue;
StringBuilder sb = new StringBuilder();
sb.append("\"");
sb.append(dvCodedText.getValue());
sb.append("\",\"");
sb.append(dvCodedText.getDefiningCode().getTerminologyId().getValue());
sb.append("\",\"");
sb.append(dvCodedText.getDefiningCode().getCodeString());
sb.append("\"");
return getDVInstantiationWithoutQuotes(DvCodedText.class.getSimpleName(), sb.toString());
}if (dataValue instanceof DvCount){
StringBuilder sb = new StringBuilder();
sb.append(((DvCount)dataValue).getMagnitude());
return getDVInstantiationWithoutQuotes(DvCount.class.getSimpleName(), sb.toString());
}if (dataValue instanceof DvText){
return getDVInstantiation(DvText.class.getSimpleName(), ((DvText)dataValue).getValue());
}if (dataValue instanceof DvBoolean){
StringBuilder sb = new StringBuilder();
sb.append(((DvBoolean) dataValue).getValue());
return getDVInstantiationWithoutQuotes(DvBoolean.class.getSimpleName(), sb.toString());
}if (dataValue instanceof DvProportion){
DvProportion dvProportion = (DvProportion) dataValue;
StringBuilder sb = new StringBuilder();
sb.append(DVUtil.round(dvProportion.getNumerator(), dvProportion.getPrecision()));
sb.append(",");
sb.append(DVUtil.round(dvProportion.getDenominator(), dvProportion.getPrecision()));
sb.append(",");
sb.append(ProportionTypesConst.getInstance().getInstanceID(dvProportion.getType()));
sb.append(",");
sb.append(dvProportion.getPrecision());
return getDVInstantiationWithoutQuotes(DvProportion.class.getSimpleName(), sb.toString());
}if (dataValue instanceof DvList){
Collection<DataValue> dataValues = ((DvList)dataValue).getDataValues();
StringBuffer sb = new StringBuffer();
String prefix = "";
for (DataValue dataValueAux : dataValues) {
sb.append(prefix);
sb.append(getDVInstantiation(dataValueAux));
prefix = ", ";
}
return sb.toString();
}else{
throw new IllegalArgumentException("Unknow data value '"+dataValue.getClass().getSimpleName()+"'");
}
}
public static String getDVInstantiation(String dvClassName, String dvDefinition){
if (dvDefinition.startsWith("'")){
dvDefinition = dvDefinition.substring(1, dvDefinition.length()-1);
}
return "new "+dvClassName+"(\""+dvDefinition+"\")";
}
public static String getDVInstantiationWithoutQuotes(String dvClassName, String dvDefinition){
return "new "+dvClassName+"("+dvDefinition+")";
}
public static String getDVDefinitionWithOutQuotes(String dvInstantiation){
if (dvInstantiation!=null){
Matcher m = dvDefinitionPatternWithOutQuotes.matcher(dvInstantiation.trim());
if(m.find()){
return m.group(1);
}else{
return null;
}
}else{
return null;
}
}
public static String getDVDefinition(String dvInstantiation){
if (dvInstantiation!=null){
Matcher m = dvDefinitionPatternWithQuotes.matcher(dvInstantiation.trim());
if(m.find()){
return m.group(1);
}else{
return null;
}
}else{
return null;
}
}
public static String getDVCloneInstanceName(String expression){
if (expression!=null){
Matcher m = clonePattern.matcher(expression.trim());
if(m.find()){
return m.group(1);
}else{
return null;
}
}else{
return null;
}
}
public static boolean isDVExpression(String expression){
if (expression!=null){
Matcher m = setLinePattern.matcher(expression.trim());
if(m.find()){
return true;
}else{
return false;
}
}else{
return false;
}
}
public static Calendar getCalendarFromDVDataTimeDef(String dvDefinition){
dvDefinition = dvDefinition.replace(":", "");
DvDateTime dv = new DvDateTime(dvDefinition);
Calendar cal = Calendar.getInstance();
cal.set(
dv.getYear(),
dv.getMonth()-1,
dv.getDay(),
dv.getHour(),
dv.getMinute(),
dv.getSecond());
//TODO TIMEZONE
return cal;
}
public static ArrayList<String[]> getDVAssignationsFromExpression(String expression) throws InternalErrorException{
Matcher m = setLinePattern.matcher(expression.trim());
if(m.find()){
return getDVAssignationsFromSetLine(m.group(1));
}else{
throw new InternalErrorException(new IllegalArgumentException("Could not parse: "+expression));
}
}
public static ArrayList<String[]> getDVAssignationsFromSetLine(String setLine) throws InternalErrorException{
ArrayList<String[]> setLines = new ArrayList<String[]>();
if(!setLine.trim().isEmpty()){
setLine = setLine.trim().substring(1, setLine.length());
String[] assignationLines = setLine.split(",[\\s]*@");
for (String assignationLine : assignationLines) {
Matcher m = assignationLinePattern.matcher(assignationLine);
if(m.find()){
setLines.add(new String[]{m.group(1), m.group(2), m.group(3)});
}else{
throw new InternalErrorException(new IllegalArgumentException("Could not parse: "+assignationLine));
}
}
}
return setLines;
}
public static String getReadableExpression(String expression) {
try{
ArrayList<String[]> assignations = getDVAssignationsFromExpression(expression);
String instanceName = getDVCloneInstanceName(expression);
if (assignations.isEmpty()){
return instanceName;
}else{
for (String[] assignation : assignations) {
if ("magnitude".equals(assignation[0])){
StringBuffer resulStr = new StringBuffer();
if (assignation[1]!=null&&!assignation[1].isEmpty()){
resulStr.append(instanceName+assignation[1]);
}
resulStr.append(getExpressionWithReadableReferences(assignation[2]));
return resulStr.toString();
}
}
}
}catch(InternalErrorException e){
ExceptionHandler.handle(e);
}
return OpenEHRLanguageManager.getMessage("Expression");
}
private static String getExpressionWithReadableReferences(String stringWithReferences){
Pattern regex = Pattern.compile("\\$([\\w]+)+\\Q.getDataValue()).get\\E([\\w]+)\\(\\)");
Matcher m = regex.matcher(stringWithReferences);
while (m.find()){
String handle = m.group(1);
String field = m.group(2);
String ref = "\\(\\([\\w]+\\)\\Q$"+handle+".getDataValue()).get"+field+"()\\E";
stringWithReferences = stringWithReferences.replaceAll(ref, handle);
}
return stringWithReferences;
}
public static String getReadableDefinition(String idTemplate, String idElement, String rmName, String dvInstantiation, ArchetypeManager archetypeManager){
if (OpenEHRDataValues.DV_CODED_TEXT.equals(rmName)){
String codedTextName = getCodedTextNameFromDVInstantiation(idTemplate, idElement, dvInstantiation, archetypeManager.getCodedTexts());
if (codedTextName!=null){
return codedTextName;
}
}else if (OpenEHRDataValues.DV_ORDINAL.equals(rmName)){
String ordinalName = getOrdinalNameFromDVInstantiation(idTemplate, idElement, dvInstantiation, archetypeManager.getOrdinals());
if (ordinalName!=null){
return ordinalName;
}
}else if (OpenEHRDataValues.DV_COUNT.equals(rmName) ||
OpenEHRDataValues.DV_BOOLEAN.equals(rmName)){
String dvDefinition = getDVDefinitionWithOutQuotes(dvInstantiation);
if (dvDefinition!=null){
return dvDefinition;
}
}else if(OpenEHRDataValues.DV_QUANTITY.equals(rmName)){
String dvDefinition = getDVDefinitionWithOutQuotes(dvInstantiation);
if (dvDefinition!=null){
String[] splitDef = dvDefinition.split("\\,");
if (splitDef.length>2){
return roundToStr(Double.parseDouble(splitDef[1]), Integer.parseInt(splitDef[2]))+" "+splitDef[0].replace("\"", "");
}else{
return dvDefinition;
}
}
}else if(OpenEHRDataValues.DV_PROPORTION.equals(rmName)){
String dvDefinition = getDVDefinitionWithOutQuotes(dvInstantiation);
if (dvDefinition!=null){
String[] splitDef = dvDefinition.split("\\,");
if (splitDef.length>3){
//TODO Display changes depending on proportion kind (slitDef[2])
return roundToStr(Double.parseDouble(splitDef[0]), Integer.parseInt(splitDef[3]))+
"/"+
roundToStr(Double.parseDouble(splitDef[1]), Integer.parseInt(splitDef[3]));
}else{
return dvDefinition;
}
}
}else if (OpenEHRDataValues.DV_DATE.equals(rmName)){
return getDVDefinition(dvInstantiation);
}else if (OpenEHRDataValues.DV_TIME.equals(rmName)){
String dvDefinition = getDVDefinition(dvInstantiation);
String[] defSplit = dvDefinition.split("\\+");
if (defSplit.length>1){
return defSplit[0];
}else{
return dvDefinition;
}
}else if(OpenEHRDataValues.DV_DATE_TIME.equals(rmName)){
String dvDefinition = getDVDefinition(dvInstantiation);
String[] defSplit = dvDefinition.split("\\+");
if (defSplit.length>1){
dvDefinition = defSplit[0];
}
defSplit = dvDefinition.split("T");
String dateDefinition = null;
String hourDefinition = null;
if (defSplit.length>1){
dateDefinition = defSplit[0];
hourDefinition = defSplit[1];
}else{
dateDefinition = dvDefinition;
}
String result = "";
if (dateDefinition!=null && !dateDefinition.isEmpty()){
dateDefinition = dateDefinition.replaceAll("-", "");
String year = dateDefinition.substring(0,4);
int monthInt = (Integer.parseInt(dateDefinition.substring(4,6)));
String month = (monthInt>9?"":"0")+monthInt;
int dayInt = (Integer.parseInt(dateDefinition.substring(6,8)));
String day = (dayInt>9?"":"0")+dayInt;
result = result+day+"/"+month+"/"+year;
}
if (hourDefinition!=null){
result = result+" "+hourDefinition;
}
return result;
}
String dvDefinition = getDVDefinitionWithOutQuotes(dvInstantiation);
if (dvDefinition!=null){
return dvDefinition;
}else{
return dvInstantiation;
}
}
public static String getOrdinalNameFromDVInstantiation(String idTemplate, String idParentArchetypeNode, String dvInstantiation, Ordinals ordinals){
return ordinals.getText(idTemplate, idParentArchetypeNode, Integer.parseInt(getValueFromDVInstantiation(dvInstantiation)), UserConfigurationManager.getLanguage());
}
public static String getValueFromDVInstantiation(String dvInstantiation){
String dvDefinition = DVDefSerializer.getDVDefinitionWithOutQuotes(dvInstantiation);
if (dvDefinition!=null && dvDefinition.contains(",")){
dvDefinition = dvDefinition.split(",")[0];
return dvDefinition;
}else{
return null;
}
}
public static String getCodedTextNameFromDVInstantiation(String idTemplate, String idParentArchetypeNode, String dvInstantiation, CodedTexts codedTexts){
CodedTextVO codedTexTVO = codedTexts.getCodedTextVO(idTemplate, idParentArchetypeNode, getCodeFromDVInstantiation(dvInstantiation));
if (codedTexTVO!=null){
String name = codedTexts.getText(codedTexTVO, UserConfigurationManager.getLanguage());
return name;
}else{
return getCodeFromDVInstantiation(dvInstantiation);
}
}
public static String getCodeFromDVInstantiation(String dvInstantiation){
String dvDefinition = DVDefSerializer.getDVDefinitionWithOutQuotes(dvInstantiation);
if (dvDefinition!=null && dvDefinition.contains(",")){
String[] splittedDVDefinition = dvDefinition.split(",");
dvDefinition = splittedDVDefinition[splittedDVDefinition.length-1];
dvDefinition = dvDefinition.replace("\"", "");
return dvDefinition;
}else{
return null;
}
}
public static Collection<String> getCodesFromDVInstantiation(String dvInstantiation){
if (dvInstantiation!=null){
Collection<String> codes = new ArrayList<String>();
String[] dvStrings = dvInstantiation.split(commaSplitPatternOutsideParenthesis);
for (String dvInstantiationAux : dvStrings) {
codes.add(getCodeFromDVInstantiation(dvInstantiationAux));
}
return codes;
}else{
return null;
}
}
public static String roundToStr(double unrounded, int precision){
StringBuffer roundSB= new StringBuffer();
roundSB.append(unrounded);
String origStr = roundSB.toString();
if (origStr.contains(".")){
int numDecimals = origStr.length()-origStr.indexOf(".")-1;
if (numDecimals!=precision){
if (numDecimals>precision){
if (precision>0){
roundSB = new StringBuffer(origStr.substring(0, origStr.indexOf(".")+precision+1));
}else{
roundSB = new StringBuffer(origStr.substring(0, origStr.indexOf(".")));
}
}else {
appendZeros(roundSB, precision-numDecimals);
}
}
}else{
if (precision>0){
roundSB.append(".");
appendZeros(roundSB, precision);
}
}
return roundSB.toString();
}
private static void appendZeros(StringBuffer roundSB, int precision){
for (int i =0; i<precision;i++) {
roundSB.append("0");
}
}
public static String getDVClassName(String rmName){
return getDummyDV(rmName).getClass().getSimpleName();
}
public static DataValue getDummyDV(String rmName){
DataValue dv = dataValueMap.get(rmName);
if(dv == null) {
throw new IllegalArgumentException("unsupported RM class[" + rmName + "]");
}else{
return dv;
}
}
public static String getReadableValue(DataValue dv, TermDefinition termDefinition){
if (dv instanceof DvCodedText){
CodePhrase cp = ((DvCodedText)dv).getDefiningCode();
Term term = getTerm(termDefinition, cp);
if (term!=null){
return term.getText();
}
return ((DvCodedText)dv).getValue();
}else if (dv instanceof DvOrdinal){
CodePhrase cp = ((DvOrdinal)dv).getSymbol().getDefiningCode();
Term term = getTerm(termDefinition, cp);
if (term!=null){
return term.getText();
}else{
return ((DvOrdinal)dv).getSymbol().getValue();
}
}else if (dv instanceof DvQuantity){
DvQuantity dvQuantity = ((DvQuantity)dv);
DecimalFormat format = getDecimalFormat(dvQuantity.getPrecision());
return format.format(dvQuantity.getMagnitude())+" "+dvQuantity.getUnits();
}else if (dv instanceof DvProportion){
DvProportion dvProportion = ((DvProportion)dv);
DecimalFormat format = getDecimalFormat(dvProportion.getPrecision());
return format.format(dvProportion.getNumerator())+"/"+format.format(dvProportion.getDenominator());
}else if (dv instanceof DvDateTime){
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
Date date = ((DvDateTime)dv).getDateTime().toDate();
return df.format(date);
}else if (dv instanceof DvDate){
DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
Date date = ((DvDate)dv).getDateTime().toDate();
return df.format(date);
}else if (dv instanceof DvTime){
DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT);
Date date = ((DvTime)dv).getDateTime().toDate();
return df.format(date);
}else if (dv instanceof DvText){
return "\""+dv.toString()+"\"";
}else if (dv!=null){
return dv.toString();
}else{
return null;
}
}
private static Term getTerm( TermDefinition termDefinition, CodePhrase cp){
if (cp.getTerminologyId().getValue().equals(OpenEHRConst.LOCAL)){
if (termDefinition!=null){
return termDefinition.getTerms().get(cp.getCodeString());
}
}
return null;
}
private static DecimalFormat getDecimalFormat(int precision){
return OpenEHRNumberFormat.getDecimalFormat(precision);
}
private final static Map<String, DataValue> dataValueMap;
/*
* Initiate the mapping between ReferenceModelName and concrete dataValue
*/
static {
dataValueMap = new HashMap<String, DataValue>();
dataValueMap.put(OpenEHRDataValues.DV_COUNT, new DvCount(0));
dataValueMap.put(OpenEHRDataValues.DV_QUANTITY, new DvQuantity(10));
dataValueMap.put(OpenEHRDataValues.DV_TEXT, new DvText("text"));
dataValueMap.put(OpenEHRDataValues.DV_CODED_TEXT, new DvCodedText("text", new CodePhrase("tm", "cd")));
dataValueMap.put(OpenEHRDataValues.DV_ORDINAL, new DvOrdinal(0, new DvCodedText("text", new CodePhrase("tm", "cd"))));
dataValueMap.put(OpenEHRDataValues.DV_DATE_TIME, new DvDateTime("2001-02-11T00"));
dataValueMap.put(OpenEHRDataValues.DV_DATE, new DvDate("2001-02-11"));
dataValueMap.put(OpenEHRDataValues.DV_TIME, new DvTime("12:00:00"));
dataValueMap.put(OpenEHRDataValues.DV_DURATION, new DvDuration("P10D"));
dataValueMap.put(OpenEHRDataValues.DV_BOOLEAN, new DvBoolean(Boolean.FALSE));
dataValueMap.put(OpenEHRDataValues.DV_PROPORTION, new DvProportion(1,1,ProportionKind.UNITARY,0));
}
}
/*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 2.0/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 2.0 (the 'License'); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an 'AS IS' basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
*
* The Initial Developers of the Original Code are Iago Corbal and Rong Chen.
* Portions created by the Initial Developer are Copyright (C) 2012-2013
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Software distributed under the License is distributed on an 'AS IS' basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* ***** END LICENSE BLOCK *****
*/