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;
012
013/*
014 Copyright (c) 2012-2026, Michael Angstadt
015 All rights reserved.
016
017 Redistribution and use in source and binary forms, with or without
018 modification, are permitted provided that the following conditions are met: 
019
020 1. Redistributions of source code must retain the above copyright notice, this
021 list of conditions and the following disclaimer. 
022 2. Redistributions in binary form must reproduce the above copyright notice,
023 this list of conditions and the following disclaimer in the documentation
024 and/or other materials provided with the distribution. 
025
026 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
027 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
028 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
029 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
030 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
031 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
032 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
033 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
034 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
035 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
036
037 The views and conclusions contained in the software and documentation are those
038 of the authors and should not be interpreted as representing official policies, 
039 either expressed or implied, of the FreeBSD Project.
040 */
041
042/**
043 * <p>
044 * Defines information about the person's agent.
045 * </p>
046 * 
047 * <p>
048 * <b>Code sample (creating)</b>
049 * </p>
050 * 
051 * <pre class="brush:java">
052 * VCard vcard = new VCard();
053 * 
054 * //URL
055 * Agent agent = new Agent("http://www.linkedin.com/BobSmith");
056 * vcard.setAgent(agent);
057 * 
058 * //vCard
059 * VCard agentVCard = new VCard();
060 * agentVCard.setFormattedName("Bob Smith");
061 * agentVCard.addTelephoneNumber("(555) 123-4566");
062 * agentVCard.addUrl("http://www.linkedin.com/BobSmith");
063 * agent = new Agent(agentVCard);
064 * vcard.setAgent(agent);
065 * </pre>
066 * 
067 * <p>
068 * <b>Code sample (retrieving)</b>
069 * </p>
070 * 
071 * <pre class="brush:java">
072 * VCard vcard = ...
073 * Agent agent = vcard.getAgent();
074 * 
075 * String url = agent.getUrl();
076 * if (url != null) {
077 *   //property value is a URL
078 * }
079 * 
080 * VCard agentVCard = agent.getVCard();
081 * if (agentVCard != null) {
082 *   //property value is a vCard
083 * }
084 * </pre>
085 * 
086 * <p>
087 * <b>Property name:</b> {@code AGENT}
088 * </p>
089 * <p>
090 * <b>Supported versions:</b> {@code 2.1, 3.0}
091 * </p>
092 * 
093 * @author Michael Angstadt
094 * @see <a href="http://tools.ietf.org/html/rfc2426#page-19">RFC 2426 p.19</a>
095 * @see <a href="http://www.imc.org/pdi/vcard-21.doc">vCard 2.1 p.18</a>
096 */
097@SupportedVersions({ VCardVersion.V2_1, VCardVersion.V3_0 })
098public class Agent extends VCardProperty {
099        private String url;
100        private VCard vcard;
101
102        /**
103         * Creates an empty agent property.
104         */
105        public Agent() {
106                //empty
107        }
108
109        /**
110         * Creates an agent property.
111         * @param url a URL pointing to the agent's information
112         */
113        public Agent(String url) {
114                setUrl(url);
115        }
116
117        /**
118         * Creates an agent property.
119         * @param vcard a vCard containing the agent's information
120         */
121        public Agent(VCard vcard) {
122                setVCard(vcard);
123        }
124
125        /**
126         * Copy constructor.
127         * @param original the property to make a copy of
128         */
129        public Agent(Agent original) {
130                super(original);
131                url = original.url;
132                vcard = (original.vcard == null) ? null : new VCard(original.vcard);
133        }
134
135        /**
136         * Gets the URL to the agent's information.
137         * @return the URL or null if not set
138         */
139        public String getUrl() {
140                return url;
141        }
142
143        /**
144         * Sets the URL to the agent's information.
145         * @param url the URL
146         */
147        public void setUrl(String url) {
148                this.url = url;
149                vcard = null;
150        }
151
152        /**
153         * Gets an embedded vCard with the agent's information.
154         * @return the vCard or null if not set
155         */
156        public VCard getVCard() {
157                return vcard;
158        }
159
160        /**
161         * Sets an embedded vCard with the agent's information.
162         * @param vcard the vCard
163         */
164        public void setVCard(VCard vcard) {
165                this.vcard = vcard;
166                url = null;
167        }
168
169        @Override
170        protected void _validate(List<ValidationWarning> warnings, VCardVersion version, VCard vcard) {
171                if (url == null && this.vcard == null) {
172                        warnings.add(new ValidationWarning(8));
173                }
174
175                if (this.vcard != null) {
176                        validateAgentVCard(version, warnings);
177                }
178        }
179
180        private void validateAgentVCard(VCardVersion version, List<ValidationWarning> warnings) {
181                vcard.validate(version).stream().flatMap(entry -> {
182                        VCardProperty property = entry.getKey();
183                        List<ValidationWarning> propertyWarnings = entry.getValue();
184
185                        String className = (property == null) ? "" : property.getClass().getSimpleName();
186
187                        return propertyWarnings.stream().map(warning -> {
188                                String codeStr = warning.getCodeString();
189                                String message = warning.getMessage();
190                                return new ValidationWarning(10, className, codeStr, message);
191                        });
192                }).forEach(warnings::add);
193        }
194
195        @Override
196        protected Map<String, Object> toStringValues() {
197                Map<String, Object> values = new LinkedHashMap<>();
198                values.put("url", url);
199                values.put("vcard", vcard);
200                return values;
201        }
202
203        @Override
204        public Agent copy() {
205                return new Agent(this);
206        }
207
208        @Override
209        public int hashCode() {
210                final int prime = 31;
211                int result = super.hashCode();
212                result = prime * result + Objects.hash(url, vcard);
213                return result;
214        }
215
216        @Override
217        public boolean equals(Object obj) {
218                if (this == obj) return true;
219                if (!super.equals(obj)) return false;
220                if (getClass() != obj.getClass()) return false;
221                Agent other = (Agent) obj;
222                return Objects.equals(url, other.url) && Objects.equals(vcard, other.vcard);
223        }
224}