blob: df59974cdaddd418afe0e058ce7c92faebaea489 [file] [log] [blame]
/**
* Copyright: NEHTA 2014-2015
* Author: Joerg Kiegeland, Distributed Models Pty Ltd
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
using System;
using System.Collections.Generic;
using System.Text;
using Nehta.HL7.CDA;
using System.Reflection;
namespace facade
{
/// <summary>
/// This helper class is mainly used by facades to evaluate the .NET equivalents of the MDHT OCL expressions
/// </summary>
abstract public class FacadeBase
{
/// <summary>
/// Enumeration for the data element level (that a constraint operates on)
/// </summary>
public enum DataElementLevel
{
/// "1A"
DEL_CDA_HEADER,
/// "2"
DEL_CDA_BODY_LEVEL_2,
/// "3A"
DEL_CDA_BODY_LEVEL_3,
/// unknown
NA
};
/// Stores for every CDA element the container element
public Dictionary<Object, Object> eContainer = new Dictionary<Object, Object>();
/// returns the CDA element
abstract public Object getModelElement();
/// Returns for the given CDA element the container element
public Object getContainer(Object child)
{
if (eContainer.Count == 0)
{
getAllContents(getModelElement(), null);
}
if (eContainer.ContainsKey(child))
{
return eContainer[child];
}
return null;
}
/// For a singleton set, returns the one and only element
static public T One<T>(T item)
{
return item;
}
/// For a singleton set, returns the one and only element
static public T One<T>(List<T> list)
{
if (list.Count == 0)
return default(T);
if (list.Count == 1)
return list[0];
throw new Exception("Expected not more than 1 element in list");
}
/// Makes an element or elements available as set
static public List<T> Set<T>(T item)
{
var result = new List<T>();
if (item != null)
result.Add(item);
return result;
}
/// Makes an element or elements available as set
static public List<byte[]> Set(byte[] item)
{
var result = new List<byte[]>();
if (item != null)
result.Add(item);
return result;
}
/// Makes an element or elements available as set
static public List<T> Set<T>(List<T> list)
{
return list;
}
/// Makes an element or elements available as set
static public List<T> Set<T>(T[] list)
{
if (list == null)
return new List<T>();
return Flatten(new List<T>(list));
}
/// Flattens nested set structures
static public List<T> Flatten<T>(List<T[]> list)
{
var result = new List<T>();
list.ForEach(i => { if (i != null) result.AddRange(i); });
return result;
}
/// Flattens nested set structures
public List<T> Flatten<T>(List<List<T>> list)
{
var result = new List<T>();
list.ForEach(i => { result.AddRange(i); });
return result;
}
/// Flattens nested set structures
static public List<T> Flatten<T>(List<T> list)
{
while (list.Remove(default(T))) ;
return list;
}
/// MDHT operation: returns the clinical document
public POCD_MT000040ClinicalDocument getClinicalDocument(Object o)
{
while (o != null && !(o is POCD_MT000040ClinicalDocument))
{
o = getContainer(o);
}
return (POCD_MT000040ClinicalDocument)o;
}
/// MDHT operation: returns the containing section
public POCD_MT000040Section getSection(Object o)
{
while (o != null && !(o is POCD_MT000040Section))
{
o = getContainer(o);
}
return (POCD_MT000040Section)o;
}
/// MDHT operation: returns all sections
public List<POCD_MT000040Section> getAllSections(POCD_MT000040ClinicalDocument clinicalDocument)
{
List<POCD_MT000040Section> allSections = new List<POCD_MT000040Section>();
POCD_MT000040Component2 component2 = clinicalDocument.component;
if (component2 != null)
{
POCD_MT000040StructuredBody structuredBody = component2.structuredBody;
if (structuredBody != null)
{
foreach (POCD_MT000040Component3 component3 in structuredBody.component)
{
POCD_MT000040Section section = component3.section;
if (section != null)
{
allSections.AddRange(getSections(section));
}
}
}
}
return allSections;
}
/// MDHT operation: returns sub-sections
private List<POCD_MT000040Section> getSections(POCD_MT000040Section section)
{
List<POCD_MT000040Section> sections = new List<POCD_MT000040Section>();
sections.Add(section);
if (section.component != null)
foreach (POCD_MT000040Component5 component in section.component)
{ // process successors
POCD_MT000040Section child = component.section;
if (child != null)
{
sections.AddRange(getSections(child));
}
}
return sections;
}
/// MDHT operation: TBD
public bool validateTargetOfEntryRelationship(POCD_MT000040Observation statusObservation)
{
if (getContainer(statusObservation) is POCD_MT000040EntryRelationship)
{
POCD_MT000040EntryRelationship entryRelationship = (POCD_MT000040EntryRelationship)getContainer(statusObservation);
return x_ActRelationshipEntryRelationship.REFR == entryRelationship.typeCode;
}
return false;
}
/// MDHT operation: asks whether the content has actual content (except for the nullFlavor attribute)
public bool hasContent(ANY o)
{
foreach (PropertyInfo field in o.GetType().GetProperties())
{
Object value = field.GetValue(o, null);
if (value != null && field.Name != "nullFlavor")
return true;
}
return false;
}
/// MDHT operation: asks whether the object is defined on the given feature
/// <param name="o">The CDA element</param>
/// <param name="featureName">The field name</param>
public bool isDefined(Object o, String featureName)
{
return IsSpecified(o, featureName);
try
{
PropertyInfo field = o.GetType().GetProperty(featureName);
if (field == null)
return false;
object x = field.GetValue(o, null);
object d = GetDefaultValue(field.PropertyType);
if (x != null)
{
return true;
}
else
{
return x != d;
}
}
catch (Exception)
{
return false;
}
}
/// MDHT operation: asks whether the string-valued feature of the given object matches the given regular expression
public bool matches(ANY o, String featureName, String regularExpression)
{
try
{
PropertyInfo field = o.GetType().GetProperty(featureName);
if (field == null)
return false;
object x = field.GetValue(o, null);
if (x is String)
{
String s = (String)x;
bool result = System.Text.RegularExpressions.Regex.IsMatch(s, "^" + regularExpression + "$");
return result;
}
return false;
}
catch (Exception)
{
return false;
}
}
/// MDHT operation: returns the contained item dependent on the given choice
public T getTime<T>(IVL_TS time, ItemsChoiceType3 t) where T : QTY
{
for (int i = 0; i < time.Items.Length; i++)
if (time.ItemsElementName[i] == t)
return (T)time.Items[i];
return default(T);
}
/// MDHT operation: returns the clinical statement of the given entryRelationship
public Object getClinicalStatement(POCD_MT000040EntryRelationship entryRelationship)
{
if (entryRelationship.act != null)
{
return entryRelationship.act;
}
if (entryRelationship.encounter != null)
{
return entryRelationship.encounter;
}
if (entryRelationship.observation != null)
{
return entryRelationship.observation;
}
if (entryRelationship.observationMedia != null)
{
return entryRelationship.observationMedia;
}
if (entryRelationship.organizer != null)
{
return entryRelationship.organizer;
}
if (entryRelationship.procedure != null)
{
return entryRelationship.procedure;
}
if (entryRelationship.regionOfInterest != null)
{
return entryRelationship.regionOfInterest;
}
if (entryRelationship.substanceAdministration != null)
{
return entryRelationship.substanceAdministration;
}
if (entryRelationship.supply != null)
{
return entryRelationship.supply;
}
return null;
}
/// MDHT operation: returns the clinical statement of the given entry
public Object getClinicalStatement(POCD_MT000040Entry entry)
{
if (entry.act != null)
{
return entry.act;
}
if (entry.encounter != null)
{
return entry.encounter;
}
if (entry.observation != null)
{
return entry.observation;
}
if (entry.observationMedia != null)
{
return entry.observationMedia;
}
if (entry.organizer != null)
{
return entry.organizer;
}
if (entry.procedure != null)
{
return entry.procedure;
}
if (entry.regionOfInterest != null)
{
return entry.regionOfInterest;
}
if (entry.substanceAdministration != null)
{
return entry.substanceAdministration;
}
if (entry.supply != null)
{
return entry.supply;
}
return null;
}
/// MDHT operation: returns the substance administrations of the given section
protected List<POCD_MT000040SubstanceAdministration> getSubstanceAdministrations(POCD_MT000040Section section)
{
return Flatten(Set(section.entry).ConvertAll(i => i.substanceAdministration));
}
/// MDHT operation: returns the supplies of the given section
protected List<POCD_MT000040Supply> getSupplies(POCD_MT000040Section section)
{
return Flatten(Set(section.entry).ConvertAll(i => i.supply));
}
/// MDHT operation: returns the text of the given ST instance
public string getText(ST st)
{
return string.Join("", st.Text);
}
/// populates the eContainer mapping
private void getAllContents(Object o, Object parent)
{
if (o == null || o.GetType().Namespace != "Nehta.HL7.CDA" || o.GetType().IsEnum || eContainer.ContainsKey(o))
{
return;
}
eContainer.Add(o, parent);
foreach (PropertyInfo field in o.GetType().GetProperties())
{
Object value = field.GetValue(o, null);
if (value is Array)
{
foreach (Object val in (Array)value)
{
getAllContents(val, o);
}
}
else
{
getAllContents(value, o);
}
}
}
/// returns the default value for the given type
private static object GetDefaultValue(Type t)
{
if (!t.IsValueType || Nullable.GetUnderlyingType(t) != null)
return null;
return Activator.CreateInstance(t);
}
/// Adds the element to the array
public T[] SetOrAdd<T>(T[] array, T element)
{
var list = array != null ? new List<T>(array) : new List<T>();
list.Add(element);
return list.ToArray();
}
/// For non-array fields, just return the element
public T SetOrAdd<T>(T array, T element)
{
return element;
}
/// <summary>
/// Mark properties for serialization by e.g. setting "contextControlCodeSpecified" to true for the "contextControlCode" property
/// </summary>
/// <param name="o">The CDA element</param>
/// <param name="featureName">The field name</param>
public void MarkSpecified(Object o, String featureName)
{
try
{
PropertyInfo field = o.GetType().GetProperty(featureName + "Specified");
if (field == null)
return;
field.SetValue(o, true, null);
}
catch (Exception)
{
}
}
/// <summary>
/// Asks if a property is specified, e.g. for the "contextControlCode" property, returns the value for "contextControlCodeSpecified"
/// </summary>
/// <param name="o">The CDA element</param>
/// <param name="featureName">The field name</param>
/// <returns>The value of the Specified field, or "false" if that does not exist for the field</returns>
public bool IsSpecified(Object o, String featureName)
{
try
{
PropertyInfo field = o.GetType().GetProperty(featureName + "Specified");
if (field == null)
return false;
object x = field.GetValue(o, null);
return x is bool ? (bool)x : false;
}
catch (Exception)
{
return false;
}
}
}
}