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.fhir.ucum;
013
014import java.util.ArrayList;
015import java.util.List;
016
017import org.fhir.ucum.special.Registry;
018
019
020
021public class UcumValidator {
022
023        private UcumModel model;
024        private List<String> result;
025        private Registry handlers;
026
027        public UcumValidator(UcumModel model, Registry handlers) {
028                super();
029                this.model = model;
030                this.handlers = handlers;
031        }
032
033        public List<String> validate() {
034                result = new ArrayList<String>();
035                checkCodes();
036                checkUnits();
037                return result;
038        }
039
040        private void checkCodes() {
041                for (Unit unit : model.getBaseUnits()) {
042                        checkUnitCode(unit.getCode(), true);
043                }
044                for (Unit unit : model.getDefinedUnits()) {
045                        checkUnitCode(unit.getCode(), true);
046                }               
047        }
048
049        private void checkUnits() {
050                for (DefinedUnit unit : model.getDefinedUnits()) {
051                        if (!unit.isSpecial())
052                                checkUnitCode(unit.getValue().getUnit(), false);
053                        else if (!handlers.exists(unit.getCode()))
054                                result.add("No Handler for "+unit.getCode().toString());
055                }
056        }
057
058        private void checkUnitCode(String code, boolean primary) {
059                try {
060                        Term term = new ExpressionParser(model).parse(code);
061                        String c = new ExpressionComposer().compose(term);
062                        if (!c.equals(code))
063                                result.add("Round trip failed: "+code+" -> "+c);
064                        new Converter(model, handlers).convert(term);                   
065                } catch (Exception e) {
066                        result.add(code+": "+e.getMessage());
067                }
068                if (primary)
069                        try {
070                                // there can't be any codes that have digits in them that aren't inside []
071                                boolean inBrack = false;
072                                boolean nonDigits = false;
073                                for (int i = 0; i < code.length(); i++) {
074                                        char ch = code.charAt(i);
075                                        if (ch == '[')
076                                                if (inBrack)
077                                                        throw new Exception("nested [");
078                                                else 
079                                                        inBrack = true;
080                                        if (ch == ']')
081                                                if (!inBrack)
082                                                        throw new Exception("] without [");
083                                                else 
084                                                        inBrack = false;
085                                        nonDigits = nonDigits || !(ch >= '0' && ch <= '9');
086                                        if (ch >= '0' && ch <= '9' && !inBrack && nonDigits) {
087                                                throw new Exception("code "+code+" is ambiguous because  it has digits outside []");
088                                        }
089                                }
090                        } catch (Exception e) {
091                                result.add(e.getMessage());
092                        }
093
094        }
095
096}