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.rest.param;
021
022import ca.uhn.fhir.context.FhirContext;
023import ca.uhn.fhir.i18n.Msg;
024import ca.uhn.fhir.model.api.IQueryParameterType;
025import ca.uhn.fhir.model.base.composite.BaseQuantityDt;
026import ca.uhn.fhir.model.primitive.DecimalDt;
027import ca.uhn.fhir.model.primitive.UriDt;
028import ca.uhn.fhir.util.CoverageIgnore;
029import org.apache.commons.lang3.StringUtils;
030import org.apache.commons.lang3.builder.ToStringBuilder;
031import org.apache.commons.lang3.builder.ToStringStyle;
032import org.hl7.fhir.instance.model.api.IPrimitiveType;
033
034import java.math.BigDecimal;
035import java.util.List;
036
037public class QuantityParam extends BaseParamWithPrefix<QuantityParam> implements IQueryParameterType {
038
039        private static final long serialVersionUID = 1L;
040        private BigDecimal myValue;
041        private String mySystem;
042        private String myUnits;
043
044        /**
045         * Constructor
046         */
047        public QuantityParam() {
048                super();
049        }
050
051        /**
052         * Constructor
053         *
054         * @param thePrefix
055         *           The comparator, or <code>null</code> for an equals comparator
056         * @param theValue
057         *           A quantity value
058         * @param theSystem
059         *           The unit system
060         * @param theUnits
061         *           The unit code
062         */
063        public QuantityParam(ParamPrefixEnum thePrefix, BigDecimal theValue, String theSystem, String theUnits) {
064                setPrefix(thePrefix);
065                setValue(theValue);
066                setSystem(theSystem);
067                setUnits(theUnits);
068        }
069
070        /**
071         * Constructor
072         *
073         * @param thePrefix
074         *           The comparator, or <code>null</code> for an equals comparator
075         * @param theValue
076         *           A quantity value
077         * @param theSystem
078         *           The unit system
079         * @param theUnits
080         *           The unit code
081         */
082        public QuantityParam(ParamPrefixEnum thePrefix, double theValue, String theSystem, String theUnits) {
083                setPrefix(thePrefix);
084                setValue(theValue);
085                setSystem(theSystem);
086                setUnits(theUnits);
087        }
088
089        /**
090         * Constructor
091         *
092         * @param thePrefix
093         *           The comparator, or <code>null</code> for an equals comparator
094         * @param theValue
095         *           A quantity value
096         * @param theSystem
097         *           The unit system
098         * @param theUnits
099         *           The unit code
100         */
101        public QuantityParam(ParamPrefixEnum thePrefix, long theValue, String theSystem, String theUnits) {
102                setPrefix(thePrefix);
103                setValue(theValue);
104                setSystem(theSystem);
105                setUnits(theUnits);
106        }
107
108        /**
109         * Constructor
110         *
111         * @param theQuantity
112         *           A quantity value (with no system or units), such as "100.0" or "gt4"
113         */
114        public QuantityParam(String theQuantity) {
115                setValueAsQueryToken(null, null, null, theQuantity);
116        }
117
118        /**
119         * Constructor
120         *
121         * @param theQuantity
122         *           A quantity value (with no system or units), such as <code>100</code>
123         */
124        public QuantityParam(long theQuantity) {
125                setValueAsQueryToken(null, null, null, Long.toString(theQuantity));
126        }
127
128        /**
129         * Constructor
130         *
131         * @param theQuantity
132         *           A quantity value (with no system or units), such as "100.0" or "&lt;=4"
133         * @param theSystem
134         *           The unit system
135         * @param theUnits
136         *           The unit code
137         */
138        public QuantityParam(String theQuantity, String theSystem, String theUnits) {
139                setValueAsQueryToken(null, null, null, theQuantity);
140                setSystem(theSystem);
141                setUnits(theUnits);
142        }
143
144        private void clear() {
145                setPrefix(null);
146                setSystem((String) null);
147                setUnits(null);
148                setValue((BigDecimal) null);
149        }
150
151        @Override
152        String doGetQueryParameterQualifier() {
153                return null;
154        }
155
156        @Override
157        String doGetValueAsQueryToken(FhirContext theContext) {
158                StringBuilder b = new StringBuilder();
159                if (getPrefix() != null) {
160                        b.append(ParameterUtil.escapeWithDefault(getPrefix().getValue()));
161                }
162
163                b.append(ParameterUtil.escapeWithDefault(getValueAsString()));
164                b.append('|');
165                b.append(ParameterUtil.escapeWithDefault(mySystem));
166                b.append('|');
167                b.append(ParameterUtil.escapeWithDefault(myUnits));
168
169                return b.toString();
170        }
171
172        public String getValueAsString() {
173                if (myValue != null) {
174                        return myValue.toPlainString();
175                }
176                return null;
177        }
178
179        @Override
180        void doSetValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theValue) {
181                clear();
182
183                if (theValue == null) {
184                        return;
185                }
186                List<String> parts = ParameterUtil.splitParameterString(theValue, '|', true);
187
188                if (parts.size() > 0 && StringUtils.isNotBlank(parts.get(0))) {
189                        String value = super.extractPrefixAndReturnRest(parts.get(0));
190                        setValue(value);
191                }
192                if (parts.size() > 1 && StringUtils.isNotBlank(parts.get(1))) {
193                        setSystem(parts.get(1));
194                }
195                if (parts.size() > 2 && StringUtils.isNotBlank(parts.get(2))) {
196                        setUnits(parts.get(2));
197                }
198        }
199
200        /**
201         * Returns the system, or null if none was provided
202         * <p>
203         * Note that prior to HAPI FHIR 1.5, this method returned a {@link UriDt}
204         * </p>
205         *
206         * @since 1.5
207         */
208        public String getSystem() {
209                return mySystem;
210        }
211
212        /**
213         * @deprecated Use {{@link #getSystem()}} instead
214         */
215        @Deprecated
216        @CoverageIgnore
217        public UriDt getSystemAsUriDt() {
218                return new UriDt(mySystem);
219        }
220
221        public String getUnits() {
222                return myUnits;
223        }
224
225        /**
226         * Returns the quantity/value, or null if none was provided
227         * <p>
228         * Note that prior to HAPI FHIR 1.5, this method returned a {@link DecimalDt}
229         * </p>
230         *
231         * @since 1.5
232         */
233        public BigDecimal getValue() {
234                return myValue;
235        }
236
237        public QuantityParam setSystem(String theSystem) {
238                mySystem = theSystem;
239                return this;
240        }
241
242        public QuantityParam setSystem(IPrimitiveType<String> theSystem) {
243                mySystem = null;
244                if (theSystem != null) {
245                        mySystem = theSystem.getValue();
246                }
247                return this;
248        }
249
250        public QuantityParam setUnits(String theUnits) {
251                myUnits = theUnits;
252                return this;
253        }
254
255        public QuantityParam setValue(BigDecimal theValue) {
256                myValue = theValue;
257                return this;
258        }
259
260        public QuantityParam setValue(IPrimitiveType<BigDecimal> theValue) {
261                myValue = null;
262                if (theValue != null) {
263                        myValue = theValue.getValue();
264                }
265                return this;
266        }
267
268        public QuantityParam setValue(String theValue) {
269                myValue = null;
270                if (theValue != null) {
271                        myValue = new BigDecimal(theValue);
272                }
273                return this;
274        }
275
276        public QuantityParam setValue(double theValue) {
277                // Use the valueOf here because the constructor gives crazy precision
278                // changes due to the floating point conversion
279                myValue = BigDecimal.valueOf(theValue);
280                return this;
281        }
282
283        public QuantityParam setValue(long theValue) {
284                // Use the valueOf here because the constructor gives crazy precision
285                // changes due to the floating point conversion
286                myValue = BigDecimal.valueOf(theValue);
287                return this;
288        }
289
290        @Override
291        public String toString() {
292                ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
293                b.append("prefix", getPrefix());
294                b.append("value", myValue);
295                b.append("system", mySystem);
296                b.append("units", myUnits);
297                if (getMissing() != null) {
298                        b.append("missing", getMissing());
299                }
300                return b.toString();
301        }
302
303        public static QuantityParam toQuantityParam(IQueryParameterType theParam) {
304                if (theParam instanceof BaseQuantityDt) {
305                        BaseQuantityDt param = (BaseQuantityDt) theParam;
306                        String systemValue = param.getSystemElement().getValueAsString();
307                        String unitsValue = param.getUnitsElement().getValueAsString();
308                        ParamPrefixEnum cmpValue =
309                                        ParamPrefixEnum.forValue(param.getComparatorElement().getValueAsString());
310                        BigDecimal valueValue = param.getValueElement().getValue();
311                        return new QuantityParam()
312                                        .setSystem(systemValue)
313                                        .setUnits(unitsValue)
314                                        .setPrefix(cmpValue)
315                                        .setValue(valueValue);
316                } else if (theParam instanceof QuantityParam) {
317                        return (QuantityParam) theParam;
318                } else {
319                        throw new IllegalArgumentException(Msg.code(1948) + "Invalid quantity type: " + theParam.getClass());
320                }
321        }
322}