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