/******************************************************************************* * Copyright (c) 2005-2010, G. Weirich and Elexis * 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 * * Contributors: * G. Weirich - initial implementation * *******************************************************************************/ package ch.elexis.data; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import ch.elexis.core.constants.StringConstants; import ch.elexis.core.constants.TextContainerConstants; import ch.elexis.core.data.interfaces.scripting.Interpreter; import ch.elexis.core.exceptions.ElexisException; import ch.elexis.core.model.ILabItem; import ch.elexis.core.model.ILabResult; import ch.elexis.core.types.LabItemTyp; import ch.rgw.tools.StringTool; import ch.rgw.tools.TimeTool; /** * Ein Laboritem, also ein anzeigbarer Laborwert. Jedes Laboritem hat einen Titel, ein Kürzel, ein * Labor, aus dem es stammt, einen Normbereich. Ausserdem gehört jedes Laboritem zu einer Itemgruppe * (Beispielsweise Hämatologie oder Vitamine) und hat eine Priorität innerhalb dieser Gruppe. Gruppe * und Priorität beeinflussen die Darstellungsreihenfolge und Gruppierung auf dem Laborblatt. * * @author Gerry * */ public class LabItem extends PersistentObject implements Comparable<LabItem>, ILabItem { public static final String REF_MALE = "RefMann"; //$NON-NLS-1$ public static final String REF_FEMALE_OR_TEXT = "RefFrauOrTx"; //$NON-NLS-1$ public static final String PRIO = "prio"; //$NON-NLS-1$ public static final String GROUP = "Gruppe"; //$NON-NLS-1$ public static final String TYPE = "Typ"; //$NON-NLS-1$ public static final String UNIT = "Einheit"; //$NON-NLS-1$ public static final String LAB_ID = "LaborID"; //$NON-NLS-1$ public static final String TITLE = "titel"; //$NON-NLS-1$ public static final String SHORTNAME = "kuerzel"; //$NON-NLS-1$ public static final String EXPORT = "export"; //$NON-NLS-1$ public static final String FORMULA = "formula"; //$NON-NLS-1$ public static final String DIGITS = "digits"; //$NON-NLS-1$ public static final String VISIBLE = "visible"; //$NON-NLS-1$ public static final String BILLINGCODE = "billingcode"; //$NON-NLS-1$ public static final String LOINCCODE = "loinccode"; //$NON-NLS-1$ static final String LABITEMS = "LABORITEMS"; //$NON-NLS-1$ private static final Pattern varPattern = Pattern.compile(TextContainerConstants.MATCH_TEMPLATE); @Override protected String getTableName(){ return LABITEMS; } static { addMapping(LABITEMS, SHORTNAME, TITLE, LAB_ID, REF_MALE, REF_FEMALE_OR_TEXT, UNIT, TYPE, GROUP, PRIO, EXPORT, FORMULA, DIGITS, VISIBLE, BILLINGCODE, LOINCCODE); } /** * Erstellt ein neues LaborItem. * * @param k * Testkuerzel (e.g. BILI) * @param t * Testname (e.g. Bilirubin gesamt) * @param labor * Labor-Identitaet (e.g. Eigenlabor) * @param RefMann * Referenzwerte Mann (e.g. 0.0-1.2) * @param RefFrau * Referenzwerte Frau (e.g. 0.0-1.2) * @param Unit * Masseinheit (e.g. mg/dl) * @param type * NUMERIC, ABSOLUTE or DOCUMENT * @param grp * Gruppenzugehoerigkeit * @param seq * Sequenz-Nummer */ public LabItem(String k, String t, Kontakt labor, String RefMann, String RefFrau, String Unit, LabItemTyp type, String grp, String seq){ this(k, t, (labor != null) ? labor.getId() : null, RefMann, RefFrau, Unit, type, grp, seq); } /** * @since 3.2 */ public LabItem(String k, String t, String laborId, String RefMann, String RefFrau, String Unit, LabItemTyp type, String grp, String seq){ String tp = "1"; //$NON-NLS-1$ if (type == LabItemTyp.NUMERIC) { tp = "0"; //$NON-NLS-1$ } else if (type == LabItemTyp.ABSOLUTE) { tp = "2"; //$NON-NLS-1$ } else if (type == LabItemTyp.FORMULA) { tp = "3"; //$NON-NLS-1$ } else if (type == LabItemTyp.DOCUMENT) { tp = "4"; //$NON-NLS-1$ } create(null); if (StringTool.isNothing(seq)) { seq = t.substring(0, 1); } if (StringTool.isNothing(grp)) { grp = Messages.LabItem_defaultGroup; } if (laborId == null) { Query<Kontakt> qbe = new Query<Kontakt>(Kontakt.class); String labid = qbe.findSingle(Kontakt.FLD_IS_LAB, Query.EQUALS, StringConstants.ONE); if (labid == null) { laborId = new Labor(Messages.LabItem_shortOwnLab, Messages.LabItem_longOwnLab).getId(); } } set(new String[] { SHORTNAME, TITLE, LAB_ID, REF_MALE, REF_FEMALE_OR_TEXT, UNIT, TYPE, GROUP, PRIO }, k, t, laborId, RefMann, RefFrau, Unit, tp, grp, seq); } protected LabItem(){/* leer */ } protected LabItem(String id){ super(id); } public static LabItem load(String id){ return new LabItem(id); } /** * This is the value that will be used for a LabResult if there is no other unit value * available. The effective unit value is moved to the LabResult. */ public String getEinheit(){ return checkNull(get(UNIT)); } /** * This is the value that will be used for a LabResult if there is no other unit value * available. The effective unit value is moved to the LabResult. */ public void setEinheit(String unit){ set(UNIT, unit); } public String getGroup(){ return checkNull(get(GROUP)); } public void setGroup(String group){ set(GROUP, group); } public String getPrio(){ return checkNull(get(PRIO)); } public void setPrio(String prio){ set(PRIO, prio); } public String getKuerzel(){ return checkNull(get(SHORTNAME)); } public void setKuerzel(String shortname){ set(SHORTNAME, shortname); } public String getName(){ return checkNull(get(TITLE)); } public void setName(String title){ set(TITLE, title); } /** * @deprecated The labor has been moved to the LabOrder. */ public Labor getLabor(){ return Labor.load(get(LAB_ID)); } public String getExport(){ return checkNull(get(EXPORT)); } public void setExport(String export){ set(EXPORT, export); } public void setTyp(LabItemTyp typ){ set(TYPE, Integer.toString(typ.getType())); } public LabItemTyp getTyp(){ LabItemTyp type = LabItemTyp.fromType(get(TYPE)); if (type != null) { return type; } return LabItemTyp.TEXT; } public String evaluateNew(Patient pat, TimeTool date, List<ILabResult> results){ String formel = getFormula(); formel = formel.substring(Script.SCRIPT_MARKER.length()); results = sortResultsDescending(results); for (ILabResult result : results) { String var = ((LabItem) result.getItem()).makeVarName(); if (formel.indexOf(var) != -1) { formel = formel.replaceAll(var, result.getResult()); } } try { return Script.executeScript(formel, pat).toString(); } catch (ElexisException e) { return "?formel?"; //$NON-NLS-1$ } } public String evaluate(Patient pat, List<ILabResult> results) throws ElexisException{ if (!getTyp().equals(LabItemTyp.FORMULA)) { return null; } String formel = getFormula(); if (formel.startsWith(Script.SCRIPT_MARKER)) { return evaluateNew(pat, null, results); } boolean bMatched = false; results = sortResultsDescending(results); for (ILabResult result : results) { String var = ((LabItem) result.getItem()).makeVarName(); if (formel.indexOf(var) != -1) { if (result.getResult() != null && !result.getResult().isEmpty() && !result.getResult().equals("?")) { //$NON-NLS-1$ formel = formel.replaceAll(var, result.getResult()); bMatched = true; } } } Matcher matcher = varPattern.matcher(formel); // Suche Variablen der Form [Patient.Alter] StringBuffer sb = new StringBuffer(); while (matcher.find()) { String var = matcher.group(); String[] fields = var.split("\\."); //$NON-NLS-1$ if (fields.length > 1) { String repl = "\"" + pat.get(fields[1].replaceFirst("\\]", StringTool.leer)) + "\""; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ // formel=matcher.replaceFirst(repl); matcher.appendReplacement(sb, repl); bMatched = true; } } matcher.appendTail(sb); if (!bMatched) { return null; } Interpreter scripter = Script.getInterpreterFor(formel); try { String result = scripter.run(sb.toString(), false).toString(); return result; } catch (ElexisException e) { return "?formel?"; //$NON-NLS-1$ } } private List<ILabResult> sortResultsDescending(List<ILabResult> results){ Collections.sort(results, new Comparator<ILabResult>() { @Override public int compare(ILabResult lr1, ILabResult lr2){ int var1Length = ((LabItem) lr1.getItem()).makeVarName().length(); int var2Length = ((LabItem) lr2.getItem()).makeVarName().length(); if (var1Length < var2Length) { return 1; } else if (var1Length > var2Length) { return -1; } return 0; } }); return results; } /** * Evaluate a formula-based LabItem for a given Patient at a given date. It will try to retrieve * all LabValues it depends on of that Patient and date and then calculate the result. If there * are not all necessare values given, it will return "?formula?". The formula can be a * beanshell-script by itself (for compatibility with previous versions), or the name of a * script prefixed with SCRIPT:, e.g. SCRIPT:mdrd($krea=c_10). Variable names are the group and * priority values of a lab item separated with an underscore. * * @param date * The date to consider for calculating * @return the result or "?formel?" if no result could be calculated. */ public String evaluate(Patient pat, TimeTool date) throws ElexisException{ if (!getTyp().equals(LabItemTyp.FORMULA)) { return null; } Query<ILabResult> qbe = new Query<ILabResult>(LabResult.class); qbe.add(LabResult.PATIENT_ID, Query.EQUALS, pat.getId()); qbe.add(LabResult.DATE, Query.EQUALS, date.toString(TimeTool.DATE_COMPACT)); List<ILabResult> results = qbe.execute(); return evaluate(pat, results); } /** * Return the variable Name that identifies this item (in a script) * * @return a name that is made of the group and the priority values. */ public String makeVarName(){ String[] group = getGroup().split(StringTool.space, 2); String num = getPrio().trim(); return group[0] + "_" + num; //$NON-NLS-1$ } public int getDigits(){ String digits = checkNull(get(DIGITS)); if (digits.isEmpty()) { return 0; } else { return Integer.parseInt(digits); } } public void setDigits(int digits){ set(DIGITS, Integer.toString(digits)); } public boolean isVisible(){ String visible = get(VISIBLE); // not set defaults to true if (visible == null || visible.isEmpty()) { setVisible(true); return true; } return visible.equals("1"); //$NON-NLS-1$ } public void setVisible(boolean visible){ if (visible) { set(VISIBLE, "1"); //$NON-NLS-1$ } else { set(VISIBLE, "0"); //$NON-NLS-1$ } } /** * This is the value that will be used for a LabResult if there is no other Ref value available. * The effective Ref value is moved to the LabResult. */ public String getRefW(){ String ret = checkNull(get(REF_FEMALE_OR_TEXT)).split("##")[0]; //$NON-NLS-1$ return ret; } /** * This is the value that will be used for a LabResult if there is no other Ref value available. * The effective Ref value is moved to the LabResult. */ public String getRefM(){ return checkNull(get(REF_MALE)); } /** * This is the value that will be used for a LabResult if there is no other Ref value available. * The effective Ref value is moved to the LabResult. */ public void setRefW(String r){ set(REF_FEMALE_OR_TEXT, r); } /** * This is the value that will be used for a LabResult if there is no other Ref value available. * The effective Ref value is moved to the LabResult. */ public void setRefM(String r){ set(REF_MALE, r); } public void setFormula(String f){ set(FORMULA, f); } public String getFormula(){ String formula = get(FORMULA); if (formula == null || formula.isEmpty()) { String[] refWEntry = get(REF_FEMALE_OR_TEXT).split("##"); formula = refWEntry.length > 1 ? refWEntry[1] : ""; if (formula != null && !formula.isEmpty()) { setFormula(formula); } } return formula; } public String getLoincCode(){ return checkNull(get(LOINCCODE)); } public void setLoincCode(String code){ set(LOINCCODE, code); } public String getBillingCode(){ return checkNull(get(BILLINGCODE)); } public void setBillingCode(String code){ set(BILLINGCODE, code); } @Override public String getLabel(){ StringBuilder sb = new StringBuilder(); String[] fields = { SHORTNAME, TITLE, REF_MALE, REF_FEMALE_OR_TEXT, UNIT, TYPE, GROUP, PRIO }; String[] vals = new String[fields.length]; get(fields, vals); sb.append(vals[0]).append(", ").append(vals[1]); //$NON-NLS-1$ if (StringConstants.ZERO.equals(vals[5])) { sb.append(" (").append(vals[2]).append("/").append(getRefW()).append(StringTool.space) //$NON-NLS-1$ //$NON-NLS-2$ .append(vals[4]).append(")"); //$NON-NLS-1$ } else { sb.append(" (").append(getRefW()).append(")"); //$NON-NLS-1$ //$NON-NLS-2$ } sb.append("[").append(vals[6]).append(", ").append(vals[7]).append("]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ return sb.toString(); } public String getShortLabel(){ StringBuilder sb = new StringBuilder(); String[] fields = { TITLE, UNIT, LAB_ID }; String[] vals = new String[fields.length]; get(fields, vals); Labor lab = Labor.load(vals[2]); String labName = "Labor?"; //$NON-NLS-1$ if (lab != null) { labName = lab.get("Bezeichnung1"); //$NON-NLS-1$ } sb.append(vals[0]).append(" (").append(vals[1]).append("; ").append(labName).append(")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ return sb.toString(); } public int compareTo(LabItem other){ // check for null; put null values at the end if (other == null) { return -1; } // first, compare the groups String mineGroup = getGroup(); String otherGroup = other.getGroup(); if (!mineGroup.equals(otherGroup)) { // groups differ, just compare groups return mineGroup.compareTo(otherGroup); } // compare item priorities String mine = getPrio().trim(); String others = other.getPrio().trim(); if ((mine.matches("[0-9]+")) && (others.matches("[0-9]+"))) { //$NON-NLS-1$ //$NON-NLS-2$ Integer iMine = Integer.parseInt(mine); Integer iOthers = Integer.parseInt(others); return iMine.compareTo(iOthers); } return mine.compareTo(others); } /** * Get a List of all LabItems from the database * * @return List of {@link LabItem} */ public static List<LabItem> getLabItems(){ Query<LabItem> qbe = new Query<LabItem>(LabItem.class); return qbe.execute(); } /** * Get a List of LabItems matching the specified parameters in the database By specifying null * parameters the LabItem selection can be broadened. * * @param laborId * the Id of the lab the items belong to * @param shortDesc * the short description for the items * @param refM * the male reference value for the items * @param refW * the female reference value for the items * @param unit * the unit for the items * * @return List of {@link LabItem} */ public static List<LabItem> getLabItems(String laborId, String shortDesc, String refM, String refW, String unit){ Query<LabItem> qbe = new Query<LabItem>(LabItem.class); if (laborId != null && laborId.length() > 0) { qbe.add("LaborID", "=", laborId); //$NON-NLS-1$ //$NON-NLS-2$ } if (shortDesc != null && shortDesc.length() > 0) { // none case sensitive matching for kuerzel qbe.add("kuerzel", "=", shortDesc, true); //$NON-NLS-1$ //$NON-NLS-2$ } if (refM != null && refM.length() > 0) { // none case sensitive matching for ref male qbe.add("RefMann", "=", refM, true); //$NON-NLS-1$ //$NON-NLS-2$ } if (refW != null && refW.length() > 0) { // none case sensitive matching for ref female qbe.add("RefFrauOrTx", "=", refW, true); //$NON-NLS-1$ //$NON-NLS-2$ } if (unit != null && unit.length() > 0) { // none case sensitive matching for unit qbe.add("Einheit", "=", unit, true); //$NON-NLS-1$ //$NON-NLS-2$ } return qbe.execute(); } /** * Copies all LabResults from the source LabItem to this LabItem. ATTENTION this can not be * reverted. The properties (originId,refW,refM,unit) will be updated from the source LabItem to * the LabResult if not already set. * * @param source */ public void mergeWith(LabItem source){ Query<LabResult> qsr = new Query<LabResult>(LabResult.class); qsr.add(LabResult.ITEM_ID, Query.EQUALS, source.getId()); List<LabResult> sourceResults = qsr.execute(); for (LabResult labResult : sourceResults) { // update data from the LabItem to the LabResult if (labResult.getOrigin() == null) { labResult.setOrigin(source.getLabor()); } // test against values in db as getter will return value from LabItem String resultProp = labResult.get(LabResult.REFFEMALE); if (resultProp == null || resultProp.isEmpty()) { labResult.setRefFemale(source.getRefW()); } resultProp = labResult.get(LabResult.REFMALE); if (resultProp == null || resultProp.isEmpty()) { labResult.setRefMale(source.getRefM()); } resultProp = labResult.get(LabResult.UNIT); if (resultProp == null || resultProp.isEmpty()) { labResult.setUnit(source.get(LabItem.UNIT)); } // update the reference to the LabItem labResult.set(LabResult.ITEM_ID, getId()); } } @Override public String getReferenceMale(){ return getRefM(); } @Override public void setReferenceMale(String value){ setRefM(value); } @Override public String getReferenceFemale(){ return getRefW(); } @Override public void setReferenceFemale(String value){ setRefW(value); } @Override public String getPriority(){ return getPrio(); } @Override public void setPriority(String value){ setPrio(value); } @Override public String getUnit(){ return getEinheit(); } @Override public void setUnit(String value){ setEinheit(value); } }