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