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 the person's sex.
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 * Gender gender = Gender.male();
055 * vcard.setGender(gender);
056 * </pre>
057 * 
058 * <p>
059 * <b>Code sample (retrieving)</b>
060 * </p>
061 * 
062 * <pre class="brush:java">
063 * VCard vcard = ...
064 * Gender gender = vcard.getGender();
065 * if (gender.isMale()) {
066 *   //gender is male
067 * } else if (gender.isFemale()) {
068 *   //gender is female
069 * }
070 * //etc
071 * </pre>
072 * 
073 * <p>
074 * <b>Property name:</b> {@code GENDER}
075 * </p>
076 * <p>
077 * <b>Supported versions:</b> {@code 4.0}
078 * </p>
079 * @author Michael Angstadt
080 * @see <a href="http://tools.ietf.org/html/rfc6350#page-32">RFC 6350 p.32</a>
081 */
082@SupportedVersions(VCardVersion.V4_0)
083public class Gender extends VCardProperty {
084        public static final String MALE = "M";
085        public static final String FEMALE = "F";
086        public static final String OTHER = "O";
087        public static final String NONE = "N";
088        public static final String UNKNOWN = "U";
089
090        private String genderCode;
091        private String text;
092
093        /**
094         * Creates a gender property. Use of this constructor is discouraged. Please
095         * use one of the static factory methods to create a new GENDER property.
096         * @param genderCode the gender value (e.g. "F")
097         */
098        public Gender(String genderCode) {
099                this.genderCode = genderCode;
100        }
101
102        /**
103         * Copy constructor.
104         * @param original the property to make a copy of
105         */
106        public Gender(Gender original) {
107                super(original);
108                genderCode = original.genderCode;
109                text = original.text;
110        }
111
112        /**
113         * Gets the additional text associated with this property.
114         * @return the additional text or null if there is no text
115         */
116        public String getText() {
117                return text;
118        }
119
120        /**
121         * Sets the additional text associated with this property.
122         * @param text additional text or null to remove
123         */
124        public void setText(String text) {
125                this.text = text;
126        }
127
128        /**
129         * Gets the gender value.
130         * @return the gender value (see static strings for the possible values)
131         */
132        public String getGender() {
133                return genderCode;
134        }
135
136        /**
137         * Sets the gender value.
138         * @param genderCode the gender value (see static strings for the possible
139         * values)
140         */
141        public void setGender(String genderCode) {
142                this.genderCode = genderCode;
143        }
144
145        /**
146         * Determines if the gender is "male" or not.
147         * @return true if the gender is "male", false if not
148         */
149        public boolean isMale() {
150                return MALE.equals(genderCode);
151        }
152
153        /**
154         * Determines if the gender is "female" or not.
155         * @return true if the gender is "female", false if not
156         */
157        public boolean isFemale() {
158                return FEMALE.equals(genderCode);
159        }
160
161        /**
162         * Determines if the gender is "other" or not.
163         * @return true if the gender is "other", false if not
164         */
165        public boolean isOther() {
166                return OTHER.equals(genderCode);
167        }
168
169        /**
170         * Determines if the gender is "none" or not. A group, organization, or
171         * location may have this gender property.
172         * @return true if the gender is "none", false if not
173         */
174        public boolean isNone() {
175                return NONE.equals(genderCode);
176        }
177
178        /**
179         * Determines if the gender is "unknown" or not.
180         * @return true if the gender is "unknown", false if not
181         */
182        public boolean isUnknown() {
183                return UNKNOWN.equals(genderCode);
184        }
185
186        /**
187         * Creates a gender property whose value is set to "male".
188         * @return a "male" gender property
189         */
190        public static Gender male() {
191                return new Gender(MALE);
192        }
193
194        /**
195         * Creates a gender property whose value is set to "female".
196         * @return a "female" gender property
197         */
198        public static Gender female() {
199                return new Gender(FEMALE);
200        }
201
202        /**
203         * Creates a gender property whose value is set to "other".
204         * @return an "other" gender property
205         */
206        public static Gender other() {
207                return new Gender(OTHER);
208        }
209
210        /**
211         * Creates a gender property whose value is set to "none". Groups,
212         * organizations, and locations should be given this gender property.
213         * @return a "none" gender property
214         */
215        public static Gender none() {
216                return new Gender(NONE);
217        }
218
219        /**
220         * Creates a gender property whose value is set to "unknown".
221         * @return a "unknown" gender property
222         */
223        public static Gender unknown() {
224                return new Gender(UNKNOWN);
225        }
226
227        @Override
228        protected void _validate(List<ValidationWarning> warnings, VCardVersion version, VCard vcard) {
229                if (genderCode == null) {
230                        warnings.add(new ValidationWarning(8));
231                }
232        }
233
234        @Override
235        protected Map<String, Object> toStringValues() {
236                Map<String, Object> values = new LinkedHashMap<>();
237                values.put("genderCode", genderCode);
238                values.put("text", text);
239                return values;
240        }
241
242        @Override
243        public Gender copy() {
244                return new Gender(this);
245        }
246
247        @Override
248        public int hashCode() {
249                final int prime = 31;
250                int result = super.hashCode();
251                result = prime * result + Objects.hash(genderCode, text);
252                return result;
253        }
254
255        @Override
256        public boolean equals(Object obj) {
257                if (this == obj) return true;
258                if (!super.equals(obj)) return false;
259                if (getClass() != obj.getClass()) return false;
260                Gender other = (Gender) obj;
261                return Objects.equals(genderCode, other.genderCode) && Objects.equals(text, other.text);
262        }
263}