001package ca.uhn.fhir.model.api;
002
003/*
004 * #%L
005 * HAPI FHIR - Core Library
006 * %%
007 * Copyright (C) 2014 - 2016 University Health Network
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 java.io.Serializable;
024import java.util.ArrayList;
025import java.util.Collection;
026import java.util.Iterator;
027import java.util.LinkedHashSet;
028import java.util.List;
029import java.util.Set;
030
031import org.hl7.fhir.instance.model.api.IBase;
032
033/**
034 * A collection of tags present on a single resource. TagList is backed by a {@link LinkedHashSet}, so the order of
035 * added tags will be consistent, but duplicates will not be preserved.
036 * 
037 * <p>
038 * <b>Thread safety:</b> This class is not thread safe
039 * </p>
040 */
041public class TagList implements Set<Tag>, Serializable, IBase {
042
043        public static final String ATTR_CATEGORY = "category";
044        public static final String ELEMENT_NAME = "TagList";
045
046        public static final String ELEMENT_NAME_LC = ELEMENT_NAME.toLowerCase();
047        private static final long serialVersionUID = 1L;
048        private transient List<Tag> myOrderedTags;
049        private LinkedHashSet<Tag> myTagSet = new LinkedHashSet<Tag>();
050
051        /**
052         * Constructor
053         */
054        public TagList() {
055                super();
056        }
057
058        /**
059         * Copy constructor
060         */
061        public TagList(TagList theTags) {
062                if (theTags != null) {
063                        for (Tag next : theTags) {
064                                add(next);
065                        }
066                }
067        }
068
069        @Override
070        public String toString() {
071                StringBuilder b = new StringBuilder();
072                b.append("TagList[").append(size()).append(" tag(s)]");
073                for (Tag next : this) {
074                        b.append("\n * ").append(next.toString());
075                }
076                return b.toString();
077        }
078
079        @Override
080        public boolean add(Tag theE) {
081                myOrderedTags = null;
082                return myTagSet.add(theE);
083        }
084
085        @Override
086        public boolean addAll(Collection<? extends Tag> theC) {
087                myOrderedTags = null;
088                return myTagSet.addAll(theC);
089        }
090
091        /**
092         * @deprecated Tags wil become immutable in a future release of HAPI, so {@link #addTag(String, String, String)}
093         *             should be used instead
094         */
095        @Deprecated
096        public Tag addTag() {
097                myOrderedTags = null;
098                return addTag(null, null, null);
099        }
100
101        /**
102         * Add a new tag instance
103         * 
104         * @param theScheme
105         *           The tag scheme
106         * @param theTerm
107         *           The tag term
108         * @return Returns the newly created tag instance. Note that the tag is added to the list by this method, so you
109         *         generally do not need to interact directly with the added tag.
110         */
111        public Tag addTag(String theScheme, String theTerm) {
112                Tag retVal = new Tag(theScheme, theTerm);
113                add(retVal);
114                myOrderedTags = null;
115                return retVal;
116        }
117
118        /**
119         * Add a new tag instance
120         * 
121         * @param theScheme
122         *           The tag scheme
123         * @param theTerm
124         *           The tag term
125         * @param theLabel
126         *           The tag label
127         * @return Returns the newly created tag instance. Note that the tag is added to the list by this method, so you
128         *         generally do not need to interact directly with the added tag.
129         */
130        public Tag addTag(String theScheme, String theTerm, String theLabel) {
131                Tag retVal = new Tag(theScheme, theTerm, theLabel);
132                add(retVal);
133                myOrderedTags = null;
134                return retVal;
135        }
136
137        @Override
138        public void clear() {
139                myOrderedTags = null;
140                myTagSet.clear();
141        }
142
143        @Override
144        public boolean contains(Object theO) {
145                return myTagSet.contains(theO);
146        }
147
148        @Override
149        public boolean containsAll(Collection<?> theC) {
150                return myTagSet.containsAll(theC);
151        }
152
153        @Override
154        public boolean equals(Object obj) {
155                if (this == obj)
156                        return true;
157                if (obj == null)
158                        return false;
159                if (getClass() != obj.getClass())
160                        return false;
161                TagList other = (TagList) obj;
162                if (myTagSet == null) {
163                        if (other.myTagSet != null)
164                                return false;
165                } else if (!myTagSet.equals(other.myTagSet))
166                        return false;
167                return true;
168        }
169
170        /**
171         * Returns the tag at a given index - Note that the TagList is backed by a {@link LinkedHashSet}, so the order of
172         * added tags will be consistent, but duplicates will not be preserved.
173         */
174        public Tag get(int theIndex) {
175                if (myOrderedTags == null) {
176                        myOrderedTags = new ArrayList<Tag>();
177                        for (Tag next : myTagSet) {
178                                myOrderedTags.add(next);
179                        }
180                }
181                return myOrderedTags.get(theIndex);
182        }
183
184        public Tag getTag(String theScheme, String theTerm) {
185                for (Tag next : this) {
186                        if (theScheme.equals(next.getScheme()) && theTerm.equals(next.getTerm())) {
187                                return next;
188                        }
189                }
190                return null;
191        }
192
193        public List<Tag> getTagsWithScheme(String theScheme) {
194                ArrayList<Tag> retVal = new ArrayList<Tag>();
195                for (Tag next : this) {
196                        if (theScheme.equals(next.getScheme())) {
197                                retVal.add(next);
198                        }
199                }
200                return retVal;
201        }
202
203        @Override
204        public int hashCode() {
205                return myTagSet.hashCode();
206        }
207
208        @Override
209        public boolean isEmpty() {
210                for (Tag next : myTagSet) {
211                        if (next.isEmpty() == false) {
212                                return false;
213                        }
214                }
215                return true;
216        }
217
218        @Override
219        public Iterator<Tag> iterator() {
220                return myTagSet.iterator();
221        }
222
223        @Override
224        public boolean remove(Object theO) {
225                myOrderedTags = null;
226                return myTagSet.remove(theO);
227        }
228
229        @Override
230        public boolean removeAll(Collection<?> theC) {
231                myOrderedTags = null;
232                return myTagSet.removeAll(theC);
233        }
234
235        @Override
236        public boolean retainAll(Collection<?> theC) {
237                myOrderedTags = null;
238                return myTagSet.retainAll(theC);
239        }
240
241        @Override
242        public int size() {
243                return myTagSet.size();
244        }
245
246        @Override
247        public Object[] toArray() {
248                return myTagSet.toArray();
249        }
250
251        @Override
252        public <T> T[] toArray(T[] theA) {
253                return myTagSet.toArray(theA);
254        }
255
256}