001package ezvcard.property;
002
003import java.util.LinkedHashMap;
004import java.util.List;
005import java.util.Map;
006import java.util.Objects;
007
008import ezvcard.SupportedVersions;
009import ezvcard.VCard;
010import ezvcard.VCardVersion;
011import ezvcard.ValidationWarning;
012import ezvcard.parameter.Pid;
013import ezvcard.parameter.RelatedType;
014import ezvcard.util.TelUri;
015
016/*
017 Copyright (c) 2012-2026, Michael Angstadt
018 All rights reserved.
019
020 Redistribution and use in source and binary forms, with or without
021 modification, are permitted provided that the following conditions are met: 
022
023 1. Redistributions of source code must retain the above copyright notice, this
024 list of conditions and the following disclaimer. 
025 2. Redistributions in binary form must reproduce the above copyright notice,
026 this list of conditions and the following disclaimer in the documentation
027 and/or other materials provided with the distribution. 
028
029 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
030 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
031 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
032 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
033 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
034 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
035 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
036 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
037 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
038 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
039
040 The views and conclusions contained in the software and documentation are those
041 of the authors and should not be interpreted as representing official policies, 
042 either expressed or implied, of the FreeBSD Project.
043 */
044
045/**
046 * <p>
047 * Defines someone that the person is related to.
048 * </p>
049 * 
050 * <p>
051 * <b>Code sample</b>
052 * </p>
053 * 
054 * <pre class="brush:java">
055 * VCard vcard = new VCard();
056 * 
057 * //static factory methods
058 * Related related = Related.email("bob.smith@example.com");
059 * related.getTypes().add(RelatedType.CO_WORKER);
060 * related.getTypes().add(RelatedType.FRIEND);
061 * vcard.addRelated(related);
062 * 
063 * //free-form text
064 * related = new Related();
065 * related.setText("Edna Smith");
066 * related.getTypes().add(RelatedType.SPOUSE);
067 * vcard.addRelated(related);
068 * 
069 * //reference another vCard by putting its UID property here
070 * related = new Related("urn:uuid:03a0e51f-d1aa-4385-8a53-e29025acd8af");
071 * related.getTypes().add(RelatedType.SIBLING);
072 * vcard.addRelated(related);
073 * </pre>
074 * 
075 * <p>
076 * <b>Property name:</b> {@code RELATED}
077 * </p>
078 * <p>
079 * <b>Supported versions:</b> {@code 4.0}
080 * </p>
081 * @author Michael Angstadt
082 * @see <a href="http://tools.ietf.org/html/rfc6350#page-42">RFC 6350 p.42</a>
083 */
084@SupportedVersions(VCardVersion.V4_0)
085public class Related extends VCardProperty implements HasAltId {
086        private String uri;
087        private String text;
088
089        /**
090         * Creates a related property
091         */
092        public Related() {
093                //empty
094        }
095
096        /**
097         * Creates a related property.
098         * @param uri the URI representing the person
099         */
100        public Related(String uri) {
101                setUri(uri);
102        }
103
104        /**
105         * Copy constructor.
106         * @param original the property to make a copy of
107         */
108        public Related(Related original) {
109                super(original);
110                uri = original.uri;
111                text = original.text;
112        }
113
114        /**
115         * Creates a related property whose value is an email address.
116         * @param email the email address
117         * @return the property
118         */
119        public static Related email(String email) {
120                return new Related("mailto:" + email);
121        }
122
123        /**
124         * Creates a related property whose value is an instant messenger handle.
125         * @param protocol the instant messenger protocol (e.g. "aim")
126         * @param handle the instant messenger handle (e.g. "johndoe")
127         * @return the property
128         */
129        public static Related im(String protocol, String handle) {
130                return new Related(protocol + ":" + handle);
131        }
132
133        /**
134         * Creates a related property whose value is a telephone number.
135         * @param telUri the telephone number
136         * @return the property
137         */
138        public static Related telephone(TelUri telUri) {
139                return new Related(telUri.toString());
140        }
141
142        /**
143         * Gets the URI value.
144         * @return the URI value or null if no URI value is set
145         */
146        public String getUri() {
147                return uri;
148        }
149
150        /**
151         * Sets the URI.
152         * @param uri the URI
153         */
154        public void setUri(String uri) {
155                this.uri = uri;
156                text = null;
157        }
158
159        /**
160         * Gets the text value.
161         * @return the text value or null if no text value is set
162         */
163        public String getText() {
164                return text;
165        }
166
167        /**
168         * Sets the value to free-form text instead of a URI.
169         * @param text the text
170         */
171        public void setText(String text) {
172                this.text = text;
173                uri = null;
174        }
175
176        /**
177         * Gets the list that stores this property's relationship types (TYPE
178         * parameters).
179         * @return the relationship types (e.g. "child", "co-worker") (this list is
180         * mutable)
181         */
182        public List<RelatedType> getTypes() {
183                return parameters.new TypeParameterList<RelatedType>() {
184                        @Override
185                        protected RelatedType _asObject(String value) {
186                                return RelatedType.get(value);
187                        }
188                };
189        }
190
191        @Override
192        public List<Pid> getPids() {
193                return super.getPids();
194        }
195
196        @Override
197        public Integer getPref() {
198                return super.getPref();
199        }
200
201        @Override
202        public void setPref(Integer pref) {
203                super.setPref(pref);
204        }
205
206        //@Override
207        public String getAltId() {
208                return parameters.getAltId();
209        }
210
211        //@Override
212        public void setAltId(String altId) {
213                parameters.setAltId(altId);
214        }
215
216        @Override
217        protected void _validate(List<ValidationWarning> warnings, VCardVersion version, VCard vcard) {
218                if (uri == null && text == null) {
219                        warnings.add(new ValidationWarning(8));
220                }
221        }
222
223        @Override
224        protected Map<String, Object> toStringValues() {
225                Map<String, Object> values = new LinkedHashMap<>();
226                values.put("uri", uri);
227                values.put("text", text);
228                return values;
229        }
230
231        @Override
232        public Related copy() {
233                return new Related(this);
234        }
235
236        @Override
237        public int hashCode() {
238                final int prime = 31;
239                int result = super.hashCode();
240                result = prime * result + Objects.hash(text, uri);
241                return result;
242        }
243
244        @Override
245        public boolean equals(Object obj) {
246                if (this == obj) return true;
247                if (!super.equals(obj)) return false;
248                if (getClass() != obj.getClass()) return false;
249                Related other = (Related) obj;
250                return Objects.equals(text, other.text) && Objects.equals(uri, other.uri);
251        }
252}