001/*
002 * Copyright 2018 Leibniz-Institut für Analytische Wissenschaften – ISAS – e.V..
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package de.isas.mztab2.validation.handlers;
017
018import de.isas.mztab2.cvmapping.CvMappingUtils;
019import static de.isas.mztab2.cvmapping.CvMappingUtils.toErrorLevel;
020import de.isas.mztab2.cvmapping.RuleEvaluationResult;
021import de.isas.mztab2.io.serialization.ParameterConverter;
022import de.isas.mztab2.model.ValidationMessage;
023import de.isas.mztab2.validation.CvTermValidationHandler;
024import info.psidev.cvmapping.CvMappingRule;
025import java.util.ArrayList;
026import java.util.Arrays;
027import java.util.HashSet;
028import java.util.List;
029import java.util.Set;
030import java.util.stream.Collectors;
031import uk.ac.ebi.pride.jmztab2.utils.errors.CrossCheckErrorType;
032import uk.ac.ebi.pride.jmztab2.utils.errors.MZTabError;
033import uk.ac.ebi.pride.jmztab2.utils.errors.MZTabErrorType;
034
035/**
036 * Implements 'XOR' logic, meaning mutually exclusive alternative possible terms or term roots for
037 * an object are allowed.
038 * @author nilshoffmann
039 */
040public class XorValidationHandler implements CvTermValidationHandler {
041
042    @Override
043    public List<ValidationMessage> handleParameters(RuleEvaluationResult result,
044        boolean errorOnTermNotInRule) {
045        // xor logic means, if one of the defined terms or its children is set, none of the others is allowed
046        final List<ValidationMessage> messages = new ArrayList<>();
047        // all defined terms or children thereof need to appear
048        Set<String> matchedParameters = new HashSet<>();
049        matchedParameters.addAll(result.getAllowedParameters().
050            keySet());
051        matchedParameters.retainAll(result.getFoundParameters().
052            keySet());
053        if (matchedParameters.isEmpty()) {
054            for (String s : result.getAllowedParameters().
055                keySet()) {
056                MZTabErrorType errorType = null;
057                switch (result.getRule().
058                    getRequirementLevel()) {
059                    case MAY:
060                        errorType = CrossCheckErrorType.CvTermOptional;
061                        break;
062                    case SHOULD:
063                        errorType = CrossCheckErrorType.CvTermRecommended;
064                        break;
065                    case MUST:
066                        errorType = CrossCheckErrorType.CvTermRequired;
067                        break;
068                    default:
069                        throw new IllegalArgumentException(
070                            "Unknown requirement level value: " + result.
071                                getRule().
072                                getRequirementLevel() + "! Supported are: " + Arrays.
073                                toString(CvMappingRule.RequirementLevel.
074                                    values()));
075                }
076                MZTabError error = new MZTabError(errorType, -1,
077                    new ParameterConverter().convert(result.
078                        getAllowedParameters().
079                        get(
080                            s)), result.getRule().
081                        getCvElementPath(), CvMappingUtils.
082                        niceToString(
083                            result.getRule()));
084                messages.add(error.toValidationMessage());
085            }
086        } else if (matchedParameters.size() > 1) {
087            //Only one of the provided cv terms for "{1}" {0} be reported. You defined terms "{2}". Allowed terms are defined in rule "{3}".
088            String definedParameters = matchedParameters.stream().
089                collect(Collectors.joining(", "));
090            MZTabErrorType xorErrorType = MZTabErrorType.forLevel(
091                MZTabErrorType.Category.CrossCheck,
092                toErrorLevel(result.getRule().
093                    getRequirementLevel()), "CvTermXor");
094            MZTabError error = new MZTabError(xorErrorType, -1,
095                result.getRule().
096                    getRequirementLevel().
097                    value(), result.getRule().
098                    getCvElementPath(), definedParameters,
099                CvMappingUtils.niceToString(result.getRule()));
100            messages.add(error.toValidationMessage());
101        }
102        return messages;
103    }
104}