001package ca.uhn.fhir.mdm.rules.json;
002
003/*-
004 * #%L
005 * HAPI FHIR - Master Data Management
006 * %%
007 * Copyright (C) 2014 - 2022 Smile CDR, Inc.
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 *
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 *
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import ca.uhn.fhir.context.ConfigurationException;
024import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
025
026import javax.annotation.Nonnull;
027import java.util.HashMap;
028import java.util.HashSet;
029import java.util.Map;
030import java.util.Set;
031
032public class VectorMatchResultMap {
033        private final MdmRulesJson myMdmRulesJson;
034        private Map<Long, MdmMatchResultEnum> myVectorToMatchResultMap = new HashMap<>();
035        private Set<Long> myMatchVectors = new HashSet<>();
036        private Set<Long> myPossibleMatchVectors = new HashSet<>();
037        private Map<Long, String> myVectorToFieldMatchNamesMap = new HashMap<>();
038
039        VectorMatchResultMap(MdmRulesJson theMdmRulesJson) {
040                myMdmRulesJson = theMdmRulesJson;
041                // no reason to hold the entire mdmRulesJson here
042                initMap();
043        }
044
045        private void initMap() {
046                for (Map.Entry<String, MdmMatchResultEnum> entry : myMdmRulesJson.getMatchResultMap().entrySet()) {
047                        put(entry.getKey(), entry.getValue());
048                }
049        }
050
051        @Nonnull
052        public MdmMatchResultEnum get(Long theMatchVector) {
053                return myVectorToMatchResultMap.computeIfAbsent(theMatchVector, this::computeMatchResult);
054        }
055
056        private MdmMatchResultEnum computeMatchResult(Long theVector) {
057                if (myMatchVectors.stream().anyMatch(v -> (v & theVector) == v)) {
058                        return MdmMatchResultEnum.MATCH;
059                }
060                if (myPossibleMatchVectors.stream().anyMatch(v -> (v & theVector) == v)) {
061                        return MdmMatchResultEnum.POSSIBLE_MATCH;
062                }
063                return MdmMatchResultEnum.NO_MATCH;
064        }
065
066        private void put(String theFieldMatchNames, MdmMatchResultEnum theMatchResult) {
067                long vector = getVector(theFieldMatchNames);
068                myVectorToFieldMatchNamesMap.put(vector, theFieldMatchNames);
069                myVectorToMatchResultMap.put(vector, theMatchResult);
070                if (theMatchResult == MdmMatchResultEnum.MATCH) {
071                        myMatchVectors.add(vector);
072                } else if (theMatchResult == MdmMatchResultEnum.POSSIBLE_MATCH) {
073                        myPossibleMatchVectors.add(vector);
074                }
075        }
076
077        public long getVector(String theFieldMatchNames) {
078                long retval = 0;
079                for (String fieldMatchName : splitFieldMatchNames(theFieldMatchNames)) {
080                        int index = getFieldMatchIndex(fieldMatchName);
081                        if (index == -1) {
082                                throw new ConfigurationException("There is no matchField with name " + fieldMatchName);
083                        }
084                        retval |= (1 << index);
085                }
086                return retval;
087        }
088
089        @Nonnull
090        static String[] splitFieldMatchNames(String theFieldMatchNames) {
091                return theFieldMatchNames.split(",\\s*");
092        }
093
094        private int getFieldMatchIndex(final String theFieldMatchName) {
095                for (int i = 0; i < myMdmRulesJson.size(); ++i) {
096                        if (myMdmRulesJson.get(i).getName().equals(theFieldMatchName)) {
097                                return i;
098                        }
099                }
100                return -1;
101        }
102
103    public String getFieldMatchNames(long theVector) {
104                return myVectorToFieldMatchNamesMap.get(theVector);
105    }
106}