001package org.hl7.fhir.utilities.ucum; 002 003/******************************************************************************* 004 * Crown Copyright (c) 2006 - 2014, Copyright (c) 2006 - 2014 Kestral Computing P/L. 005 * All rights reserved. This program and the accompanying materials 006 * are made available under the terms of the Eclipse Public License v1.0 007 * which accompanies this distribution, and is available at 008 * http://www.eclipse.org/legal/epl-v10.html 009 * 010 * Contributors: 011 * Kestral Computing P/L - initial implementation 012 *******************************************************************************/ 013 014import java.util.Collections; 015import java.util.Comparator; 016 017import org.hl7.fhir.exceptions.UcumException; 018import org.hl7.fhir.utilities.ucum.Canonical.CanonicalUnit; 019import org.hl7.fhir.utilities.ucum.special.Registry; 020 021public class Converter { 022 023 private UcumModel model; 024 private Registry handlers; 025 026 /** 027 * @param model 028 */ 029 public Converter(UcumModel model, Registry handlers) { 030 super(); 031 this.model = model; 032 this.handlers = handlers; 033 } 034 035 036 public Canonical convert(Term term) throws UcumException { 037 return normalise(" ", term); 038 } 039 040 private Canonical normalise(String indent, Term term) throws UcumException { 041 Canonical result = new Canonical(new Decimal(1)); 042 043 debug(indent, "canonicalise", term); 044 boolean div = false; 045 Term t = term; 046 while (t != null) { 047 if (t.getComp() instanceof Term) { 048 Canonical temp = normalise(indent+" ", (Term) t.getComp()); 049 if (div) { 050 result.divideValue(temp.getValue()); 051 for (CanonicalUnit c : temp.getUnits()) 052 c.setExponent(0-c.getExponent()); 053 } else { 054 result.multiplyValue(temp.getValue()); 055 } 056 result.getUnits().addAll(temp.getUnits()); 057 } else if (t.getComp() instanceof Factor) { 058 if (div) 059 result.divideValue(((Factor) t.getComp()).getValue()); 060 else 061 result.multiplyValue(((Factor) t.getComp()).getValue()); 062 } else if (t.getComp() instanceof Symbol) { 063 Symbol o = (Symbol) t.getComp(); 064 Canonical temp = normalise(indent, o); 065 if (div) { 066 result.divideValue(temp.getValue()); 067 for (CanonicalUnit c : temp.getUnits()) 068 c.setExponent(0-c.getExponent()); 069 } else { 070 result.multiplyValue(temp.getValue()); 071 } 072 result.getUnits().addAll(temp.getUnits()); 073 } 074 div = t.getOp() == Operator.DIVISION; 075 t = t.getTerm(); 076 } 077 078 debug(indent, "collate", result); 079 080 for (int i = result.getUnits().size()-1; i >= 0; i--) { 081 CanonicalUnit sf = result.getUnits().get(i); 082 for (int j = i-1; j >=0; j--) { 083 CanonicalUnit st = result.getUnits().get(j); 084 if (st.getBase() == sf.getBase()) { 085 st.setExponent(sf.getExponent()+st.getExponent()); 086 result.getUnits().remove(i); 087 break; 088 } 089 } 090 } 091 for (int i = result.getUnits().size()-1; i >= 0; i--) { 092 CanonicalUnit sf = result.getUnits().get(i); 093 if (sf.getExponent() == 0) 094 result.getUnits().remove(i); 095 } 096 097 debug(indent, "sort", result); 098 Collections.sort(result.getUnits(), new Comparator<CanonicalUnit>(){ 099 @Override 100 public int compare(final CanonicalUnit lhs, CanonicalUnit rhs) { 101 return lhs.getBase().getCode().compareTo(rhs.getBase().getCode()); 102 } 103 }); 104 debug(indent, "done", result); 105 return result; 106 } 107 108 private Canonical normalise(String indent, Symbol sym) throws UcumException { 109 Canonical result = new Canonical(new Decimal(1)); 110 111 if (sym.getUnit() instanceof BaseUnit) { 112 result.getUnits().add(new CanonicalUnit((BaseUnit) sym.getUnit(), sym.getExponent())); 113 } else { 114 Canonical can = expandDefinedUnit(indent, (DefinedUnit) sym.getUnit()); 115 for (CanonicalUnit c : can.getUnits()) { 116 c.setExponent(c.getExponent() * sym.getExponent()); 117 } 118 result.getUnits().addAll(can.getUnits()); 119 if (sym.getExponent() > 0) 120 for (int i = 0; i < sym.getExponent(); i++) 121 result.multiplyValue(can.getValue()); 122 else 123 for (int i = 0; i > sym.getExponent(); i--) 124 result.divideValue(can.getValue()); 125 } 126 if (sym.getPrefix() != null) { 127 if (sym.getExponent() > 0) 128 for (int i = 0; i < sym.getExponent(); i++) 129 result.multiplyValue(sym.getPrefix().getValue()); 130 else 131 for (int i = 0; i > sym.getExponent(); i--) 132 result.divideValue(sym.getPrefix().getValue()); 133 } 134 return result; 135 } 136 137 private Canonical expandDefinedUnit(String indent, DefinedUnit unit) throws UcumException { 138 String u = unit.getValue().getUnit(); 139 if (unit.isSpecial()) { 140 if (!handlers.exists(unit.getCode())) 141 throw new UcumException("Not handled yet (special unit)"); 142 else 143 u = handlers.get(unit.getCode()).getUnits(); 144 } 145 146 Term t = new ExpressionParser(model).parse(u); 147 debug(indent, "now handle", t); 148 Canonical result = normalise(indent+" ", t); 149 result.multiplyValue(unit.getValue().getValue()); 150 return result; 151 } 152 153 154 private void debug(String indent, String state, Term unit) { 155// System.out.println(indent+state+": "+new ExpressionComposer().compose(unit)); 156 } 157 158 159 private void debug(String indent, String state, Canonical can) { 160// System.out.println(indent+state+": "+new ExpressionComposer().compose(can)); 161 } 162 163 164 165}