001/*
002 * #%L
003 * HAPI FHIR - Core Library
004 * %%
005 * Copyright (C) 2014 - 2024 Smile CDR, Inc.
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package ca.uhn.fhir.model.base.composite;
021
022import ca.uhn.fhir.context.FhirContext;
023import ca.uhn.fhir.i18n.Msg;
024import ca.uhn.fhir.model.api.BaseIdentifiableElement;
025import ca.uhn.fhir.model.api.ICompositeDatatype;
026import ca.uhn.fhir.model.api.IQueryParameterType;
027import ca.uhn.fhir.model.primitive.BooleanDt;
028import ca.uhn.fhir.model.primitive.CodeDt;
029import ca.uhn.fhir.model.primitive.StringDt;
030import ca.uhn.fhir.model.primitive.UriDt;
031import ca.uhn.fhir.rest.param.ParameterUtil;
032import ca.uhn.fhir.rest.param.TokenParam;
033import org.apache.commons.lang3.StringUtils;
034
035public abstract class BaseCodingDt extends BaseIdentifiableElement implements ICompositeDatatype, IQueryParameterType {
036
037        private static final long serialVersionUID = 4425182816398730643L;
038
039        /**
040         * Gets the value(s) for <b>code</b> (Symbol in syntax defined by the system). creating it if it does not exist. Will not return <code>null</code>.
041         *
042         * <p>
043         * <b>Definition:</b> A symbol in syntax defined by the system. The symbol may be a predefined code or an expression in a syntax defined by the coding system (e.g. post-coordination)
044         * </p>
045         */
046        public abstract CodeDt getCodeElement();
047
048        @Override
049        public String getQueryParameterQualifier() {
050                return null;
051        }
052
053        /**
054         * Gets the value(s) for <b>system</b> (Identity of the terminology system). creating it if it does not exist. Will not return <code>null</code>.
055         *
056         * <p>
057         * <b>Definition:</b> The identification of the code system that defines the meaning of the symbol in the code.
058         * </p>
059         */
060        public abstract UriDt getSystemElement();
061
062        public abstract StringDt getVersionElement();
063
064        public abstract BooleanDt getUserSelectedElement();
065
066        /**
067         * Gets the value(s) for <b>display</b> (Representation defined by the system).
068         * creating it if it does
069         * not exist. Will not return <code>null</code>.
070         *
071         * <p>
072         * <b>Definition:</b>
073         * A representation of the meaning of the code in the system, following the rules of the system.
074         * </p>
075         */
076        public abstract StringDt getDisplayElement();
077
078        public abstract BaseCodingDt setDisplay(String theString);
079
080        /**
081         * {@inheritDoc}
082         */
083        @Override
084        public String getValueAsQueryToken(FhirContext theContext) {
085                if (getSystemElement().getValueAsString() != null) {
086                        return ParameterUtil.escape(
087                                                        StringUtils.defaultString(getSystemElement().getValueAsString()))
088                                        + '|'
089                                        + ParameterUtil.escape(getCodeElement().getValueAsString());
090                }
091                return ParameterUtil.escape(getCodeElement().getValueAsString());
092        }
093
094        /**
095         * {@inheritDoc}
096         */
097        @Override
098        public void setValueAsQueryToken(
099                        FhirContext theContext, String theParamName, String theQualifier, String theParameter) {
100                int barIndex = ParameterUtil.nonEscapedIndexOf(theParameter, '|');
101                if (barIndex != -1) {
102                        setSystem(theParameter.substring(0, barIndex));
103                        setCode(ParameterUtil.unescape(theParameter.substring(barIndex + 1)));
104                } else {
105                        setCode(ParameterUtil.unescape(theParameter));
106                }
107        }
108
109        /**
110         * Returns true if <code>this</code> Coding has the same {@link #getCodeElement() Code} and {@link #getSystemElement() system} (as compared by simple equals comparison). Does not compare other
111         * Codes (e.g. getUseElement()) or any extensions.
112         */
113        public boolean matchesSystemAndCode(BaseCodingDt theCoding) {
114                if (theCoding == null) {
115                        return false;
116                }
117                return getCodeElement().equals(theCoding.getCodeElement())
118                                && getSystemElement().equals(theCoding.getSystemElement());
119        }
120
121        /**
122         * returns true if <code>this</code> Coding matches a search for the coding specified by <code>theSearchParam</code>, according
123         * to the following:
124         * <ul>
125         *              <li>[parameter]=[namespace]|[code] matches a code/value in the given system namespace</li>
126         *              <li>[parameter]=[code] matches a code/value irrespective of it's system namespace</li>
127         *              <li>[parameter]=|[code] matches a code/value that has no system namespace</li>
128         * </ul>
129         * @param theSearchParam - coding to test <code>this</code> against
130         * @return true if the coding matches, false otherwise
131         */
132        public boolean matchesToken(BaseCodingDt theSearchParam) {
133                if (theSearchParam.isSystemPresent()) {
134                        if (theSearchParam.isSystemBlank()) {
135                                //  [parameter]=|[code] matches a code/value that has no system namespace
136                                if (isSystemPresent() && !isSystemBlank()) return false;
137                        } else {
138                                //  [parameter]=[namespace]|[code] matches a code/value in the given system namespace
139                                if (!isSystemPresent()) return false;
140                                if (!getSystemElement().equals(theSearchParam.getSystemElement())) return false;
141                        }
142                } else {
143                        //  [parameter]=[code] matches a code/value irrespective of it's system namespace
144                        // (nothing to do for system for this case)
145                }
146
147                return getCodeElement().equals(theSearchParam.getCodeElement());
148        }
149
150        private boolean isSystemPresent() {
151                return !getSystemElement().isEmpty();
152        }
153
154        private boolean isSystemBlank() {
155                return isSystemPresent() && getSystemElement().getValueAsString().equals("");
156        }
157
158        /**
159         * Sets the value for <b>code</b> (Symbol in syntax defined by the system)
160         *
161         * <p>
162         * <b>Definition:</b> A symbol in syntax defined by the system. The symbol may be a predefined code or an expression in a syntax defined by the coding system (e.g. post-coordination)
163         * </p>
164         */
165        public abstract BaseCodingDt setCode(String theCode);
166
167        /**
168         * Sets the value for <b>system</b> (Identity of the terminology system)
169         *
170         * <p>
171         * <b>Definition:</b> The identification of the code system that defines the meaning of the symbol in the code.
172         * </p>
173         */
174        public abstract BaseCodingDt setSystem(String theUri);
175
176        /**
177         * <b>Not supported!</b>
178         *
179         * @deprecated get/setMissing is not supported in StringDt. Use {@link TokenParam} instead if you
180         * need this functionality
181         */
182        @Deprecated(since = "6.0.0")
183        @Override
184        public Boolean getMissing() {
185                return null;
186        }
187
188        /**
189         * <b>Not supported!</b>
190         *
191         * @deprecated get/setMissing is not supported in StringDt. Use {@link TokenParam} instead if you
192         * need this functionality
193         */
194        @Deprecated(since = "6.0.0")
195        @Override
196        public IQueryParameterType setMissing(Boolean theMissing) {
197                throw new UnsupportedOperationException(
198                                Msg.code(1903)
199                                                + "get/setMissing is not supported in StringDt. Use {@link StringParam} instead if you need this functionality");
200        }
201}