package com.openMap1.mapper.fhir;
import java.net.URI;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EcorePackage;
import org.hl7.fhir.instance.model.DateAndTime;
import org.hl7.fhir.instance.model.Factory;
import org.hl7.fhir.instance.model.Type;
import org.hl7.fhir.instance.model.Instant;
import com.openMap1.mapper.core.MapperException;
import com.openMap1.mapper.util.GenUtil;
import com.openMap1.mapper.util.ModelUtil;
/**
* Class to define the relationships between:
*
* (a) FHIR Primitive types
* (b) values assigned to them in the Java reference implementation
* (c) EMF Ecore EAttribute types
* (b) String values in the XML
*
* @author Robert
*
*/
public class PrimitiveTypes {
private static boolean tracing = false;
// primitive types for leaves of data type and resource trees, and a type for their superclass
public static String[] PRIMITIVETYPES =
{"decimal","integer","boolean",
"instant","element","date",
"base64Binary","string","uri","dateTime",
"id","code","oid","uuid","Type"};
/**
* equivalences between primitive types, values types in the Java reference implementation,
* and EMF Ecore attribute types
*/
private static String[][] TYPE_EQUIVALENCE =
{{"decimal","java.math.BigDecimal","EBigDecimal"},
{"integer","java.lang.Integer","EInt"},
{"boolean","java.lang.Boolean","EBoolean"},
{"instant","java.util.Calendar","EString"},
{"element","java.lang.String","EString"},
{"date","java.lang.String","EString"},
{"base64Binary","byte[]","EString"},
{"string","java.lang.String","EString"},
{"uri","java.net.URI","EString"},
{"dateTime","java.lang.String","EString"},
{"id","java.lang.String","EString"},
{"code","org.hl7.fhir.instance.model.Enumeration","EString"},
{"oid","java.lang.String","EString"},
{"uuid","java.lang.String","EString"},
{"Type","java.lang.String","EString"}
};
/**
*
* @param type
* @return
*/
public static boolean isPrimitiveType(String type) {return GenUtil.inArray(type, PRIMITIVETYPES);}
/**
*
* @param type
* @throws MapperException
*/
public static void checkPrimitiveType(String type) throws MapperException
{
if (type == null) throw new MapperException("Null type");
if (!GenUtil.inArray(type, PRIMITIVETYPES))
throw new MapperException("Type '" + type + "' is not a FHIR primitive type");
}
/**
*
* @param type
* @return
* @throws MapperException
*/
public static String referenceClassResultType(String type) throws MapperException
{
checkPrimitiveType(type);
String refClass = "";
for (int i = 0; i < TYPE_EQUIVALENCE.length; i++)
{
String[] equiv = TYPE_EQUIVALENCE[i];
if (type.equals(equiv[0])) refClass = equiv[1];
}
return refClass;
}
/**
*
* @param type
* @return
* @throws MapperException
*/
public static String referenceClassName(String type) throws MapperException
{
checkPrimitiveType(type);
String className = GenUtil.initialUpperCase(type);
if (className.equals("String")) className = "String_";
return className;
}
/**
*
* @param type
* @return
* @throws MapperException
*/
public static String EMFTypeName(String type) throws MapperException
{
checkPrimitiveType(type);
String elfType = "";
for (int i = 0; i < TYPE_EQUIVALENCE.length; i++)
{
String[] equiv = TYPE_EQUIVALENCE[i];
if (type.equals(equiv[0])) elfType = equiv[2];
}
return elfType;
}
public static EDataType attributeType(String type) throws MapperException
{
checkPrimitiveType(type);
EDataType dType = null;
String emfType = EMFTypeName(type);
if (emfType.equals("EString")) dType = EcorePackage.eINSTANCE.getEString();
else if (emfType.equals("EFloat")) dType = EcorePackage.eINSTANCE.getEFloat();
else if (emfType.equals("EBigDecimal")) dType = EcorePackage.eINSTANCE.getEBigDecimal();
else if (emfType.equals("EInt")) dType = EcorePackage.eINSTANCE.getEInt();
else if (emfType.equals("EBoolean")) dType = EcorePackage.eINSTANCE.getEBoolean();
else throw new MapperException("Ecore data type '" + emfType + "' not yet supported");
return dType;
}
public static Type typeValue(Object value, String primitiveType) throws MapperException
{
Type result = null;
checkPrimitiveType(primitiveType);
try
{
if (primitiveType.equals("boolean")) result = Factory.newBoolean(((Boolean)value).booleanValue()) ;
else if (primitiveType.equals("code")) result = Factory.newCode((String)value) ;
else if (primitiveType.equals("date")) result = Factory.newDate((String)value) ;
else if (primitiveType.equals("dateTime")) result = Factory.newDateTime((String)value) ;
else if (primitiveType.equals("id")) result = Factory.newId((String)value) ;
else if (primitiveType.equals("decimal")) result = Factory.newInteger((Integer)value) ;
else if (primitiveType.equals("uri")) result = Factory.newUri((String)value) ;
else if (primitiveType.equals("string")) result = Factory.newString_(value.toString()) ;
else if (primitiveType.equals("integer")) result = Factory.newInteger((Integer)value) ;
else if (primitiveType.equals("instant"))
{
if (value instanceof String) try
{
result = new Instant();
Calendar cal = xmlToDate((String)value);
((Instant)result).setValue(new DateAndTime(cal));
//((Instant)result).setValue(cal);
}
catch (Exception ex)
{
ex.printStackTrace();
throw new MapperException("Error in Primitive data type 'instant': " + ex.getMessage());
}
else throw new MapperException("Value for instant is not a string, but is " + value.getClass().getName());
}
}
catch (Exception ex)
{
ex.printStackTrace();
throw new MapperException("Exception applying reference model class for " + primitiveType + "; " + ex.getMessage());
}
// need to use Class.forName() here...
if (result == null) throw new MapperException("Primitive type " + primitiveType + " not yet handled by Factory");
return result;
}
// code lifted from the FHIR java reference implementation, class XMLBase
static String dateToXml(java.util.Calendar date) {
return javax.xml.bind.DatatypeConverter.printDateTime(date);
}
// code lifted from the FHIR java reference implementation, class XMLBase
static java.util.Calendar xmlToDate(String date) throws ParseException {
return javax.xml.bind.DatatypeConverter.parseDateTime(date);
}
/**
*
* @param result
* @param feat
* @param valObj
*/
public static void setEcoreFeature(EObject result, EAttribute feat, Object valObj) throws MapperException
{
String primitiveType = ModelUtil.getMIFAnnotation(feat, "PrimitiveType");
if (primitiveType == null) throw new MapperException("Null primitive type of feature " + feat.getName());
checkPrimitiveType(primitiveType);
/* for many of the primitive types, the java class delivered by the reference model class
* is the same class as consumed by the eSet. Exceptions are handled below */
if (primitiveType.equals("base64Binary"))
{
// convert byte[] to String
throw new MapperException("Type " + primitiveType + " not handled yet");
}
else if (primitiveType.equals("instant"))
{
// convert Calendar to String
if (valObj instanceof Calendar)
{
String instant = javax.xml.bind.DatatypeConverter.printDateTime((Calendar)valObj);
result.eSet(feat, instant);
}
else throw new MapperException("Value of primitive type 'instant' is not java.util.Calendar");
}
else if (primitiveType.equals("uri"))
{
// convert URI to string if needed
if (valObj instanceof java.net.URI)
{
URI uriVal = (URI)valObj;
result.eSet(feat, uriVal.toString());
}
else if (valObj instanceof java.lang.String)
{
result.eSet(feat, valObj);
}
else throw new MapperException("uri value is not a URI or String, but is a " + valObj.getClass().getName());
}
// other cases include primitive type 'code' where a string value has been delivered
else try
{
trace("Primitive type " + primitiveType + " has a value of class " + valObj.getClass().getName());
result.eSet(feat, valObj);
}
catch (Exception ex)
{throw new MapperException("Failed to set reference model data type "
+ primitiveType + " to value " + valObj + "; " + ex.getMessage());}
}
/**
*
* @param theClass
* @return
*/
public static boolean isPrimitiveDataTypeClass(Class<?> theClass)
{
boolean isPrimitive = false;
String className = theClass.getName();
if (className.startsWith("org.hl7.fhir.instance.model."))
{
String bareClassName = className.substring("org.hl7.fhir.instance.model.".length());
isPrimitive = GenUtil.inArray(GenUtil.initialLowerCase(bareClassName), PRIMITIVETYPES);
if (bareClassName.equals("String_")) isPrimitive = true;
}
return isPrimitive;
}
private static void message(String s) {System.out.println(s);}
private static void trace(String s) {if (tracing) message(s);}
}