001/*******************************************************************************
002 * Crown Copyright (c) 2006 - 2014, Copyright (c) 2006 - 2014 Kestral Computing P/L.
003 * All rights reserved. This program and the accompanying materials
004 * are made available under the terms of the Eclipse Public License v1.0
005 * which accompanies this distribution, and is available at
006 * http://www.eclipse.org/legal/epl-v10.html
007 * 
008 * Contributors:
009 *    Kestral Computing P/L - initial implementation
010 *******************************************************************************/
011
012package org.hl7.fhir.utilities.ucum;
013
014import java.util.ArrayList;
015import java.util.List;
016
017import org.hl7.fhir.utilities.ucum.special.Registry;
018
019
020public class UcumValidator {
021
022        private UcumModel model;
023        private List<String> result;
024        private Registry handlers;
025
026        public UcumValidator(UcumModel model, Registry handlers) {
027                super();
028                this.model = model;
029                this.handlers = handlers;
030        }
031
032        public List<String> validate() {
033                result = new ArrayList<String>();
034                checkCodes();
035                checkUnits();
036                return result;
037        }
038
039        private void checkCodes() {
040                for (Unit unit : model.getBaseUnits()) {
041                        checkUnitCode(unit.getCode(), true);
042                }
043                for (Unit unit : model.getDefinedUnits()) {
044                        checkUnitCode(unit.getCode(), true);
045                }               
046        }
047
048        private void checkUnits() {
049                for (DefinedUnit unit : model.getDefinedUnits()) {
050                        if (!unit.isSpecial())
051                                checkUnitCode(unit.getValue().getUnit(), false);
052                        else if (!handlers.exists(unit.getCode()))
053                                result.add("No Handler for "+unit.getCode().toString());
054                }
055        }
056
057        private void checkUnitCode(String code, boolean primary) {
058                try {
059                        Term term = new ExpressionParser(model).parse(code);
060                        String c = new ExpressionComposer().compose(term);
061                        if (!c.equals(code))
062                                result.add("Round trip failed: "+code+" -> "+c);
063                        new Converter(model, handlers).convert(term);                   
064                } catch (Exception e) {
065                        result.add(code+": "+e.getMessage());
066                }
067                if (primary)
068                        try {
069                                // there can't be any codes that have digits in them that aren't inside []
070                                boolean inBrack = false;
071                                boolean nonDigits = false;
072                                for (int i = 0; i < code.length(); i++) {
073                                        char ch = code.charAt(i);
074                                        if (ch == '[')
075                                                if (inBrack)
076                                                        throw new Exception("nested [");
077                                                else 
078                                                        inBrack = true;
079                                        if (ch == ']')
080                                                if (!inBrack)
081                                                        throw new Exception("] without [");
082                                                else 
083                                                        inBrack = false;
084                                        nonDigits = nonDigits || !(ch >= '0' && ch <= '9');
085                                        if (ch >= '0' && ch <= '9' && !inBrack && nonDigits) {
086                                                throw new Exception("code "+code+" is ambiguous because  it has digits outside []");
087                                        }
088                                }
089                        } catch (Exception e) {
090                                result.add(e.getMessage());
091                        }
092
093        }
094
095}