2 * Sone - Profile.java - Copyright © 2010 David Roden
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 package net.pterodactylus.sone.data;
20 import java.util.ArrayList;
21 import java.util.Collections;
22 import java.util.List;
23 import java.util.UUID;
25 import net.pterodactylus.util.validation.Validation;
28 * A profile stores personal information about a {@link Sone}. All information
29 * is optional and can be {@code null}.
31 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
33 public class Profile implements Fingerprintable {
35 /** The first name. */
36 private volatile String firstName;
38 /** The middle name(s). */
39 private volatile String middleName;
42 private volatile String lastName;
44 /** The day of the birth date. */
45 private volatile Integer birthDay;
47 /** The month of the birth date. */
48 private volatile Integer birthMonth;
50 /** The year of the birth date. */
51 private volatile Integer birthYear;
53 /** Additional fields in the profile. */
54 private final List<Field> fields = Collections.synchronizedList(new ArrayList<Field>());
57 * Creates a new empty profile.
64 * Creates a copy of a profile.
69 public Profile(Profile profile) {
70 if (profile == null) {
73 this.firstName = profile.firstName;
74 this.middleName = profile.middleName;
75 this.lastName = profile.lastName;
76 this.birthDay = profile.birthDay;
77 this.birthMonth = profile.birthMonth;
78 this.birthYear = profile.birthYear;
79 this.fields.addAll(profile.fields);
87 * Returns the first name.
89 * @return The first name
91 public String getFirstName() {
96 * Sets the first name.
99 * The first name to set
100 * @return This profile (for method chaining)
102 public Profile setFirstName(String firstName) {
103 this.firstName = firstName;
108 * Returns the middle name(s).
110 * @return The middle name
112 public String getMiddleName() {
117 * Sets the middle name.
120 * The middle name to set
121 * @return This profile (for method chaining)
123 public Profile setMiddleName(String middleName) {
124 this.middleName = middleName;
129 * Returns the last name.
131 * @return The last name
133 public String getLastName() {
138 * Sets the last name.
141 * The last name to set
142 * @return This profile (for method chaining)
144 public Profile setLastName(String lastName) {
145 this.lastName = lastName;
150 * Returns the day of the birth date.
152 * @return The day of the birth date (from 1 to 31)
154 public Integer getBirthDay() {
159 * Sets the day of the birth date.
162 * The day of the birth date (from 1 to 31)
163 * @return This profile (for method chaining)
165 public Profile setBirthDay(Integer birthDay) {
166 this.birthDay = birthDay;
171 * Returns the month of the birth date.
173 * @return The month of the birth date (from 1 to 12)
175 public Integer getBirthMonth() {
180 * Sets the month of the birth date.
183 * The month of the birth date (from 1 to 12)
184 * @return This profile (for method chaining)
186 public Profile setBirthMonth(Integer birthMonth) {
187 this.birthMonth = birthMonth;
192 * Returns the year of the birth date.
194 * @return The year of the birth date
196 public Integer getBirthYear() {
201 * Sets the year of the birth date.
204 * The year of the birth date
205 * @return This profile (for method chaining)
207 public Profile setBirthYear(Integer birthYear) {
208 this.birthYear = birthYear;
213 * Returns the fields of this profile.
215 * @return The fields of this profile
217 public List<Field> getFields() {
218 return new ArrayList<Field>(fields);
222 * Returns whether this profile contains the given field.
225 * The field to check for
226 * @return {@code true} if this profile contains the field, false otherwise
228 public boolean hasField(Field field) {
229 return fields.contains(field);
233 * Returns the field with the given ID.
236 * The ID of the field to get
237 * @return The field, or {@code null} if this profile does not contain a
238 * field with the given ID
240 public Field getFieldById(String fieldId) {
241 Validation.begin().isNotNull("Field ID", fieldId).check();
242 for (Field field : fields) {
243 if (field.getId().equals(fieldId)) {
251 * Returns the field with the given name.
254 * The name of the field to get
255 * @return The field, or {@code null} if this profile does not contain a
256 * field with the given name
258 public Field getFieldByName(String fieldName) {
259 for (Field field : fields) {
260 if (field.getName().equals(fieldName)) {
268 * Appends a new field to the list of fields.
271 * The name of the new field
272 * @return The new field
273 * @throws IllegalArgumentException
274 * if the name is not valid
276 public Field addField(String fieldName) throws IllegalArgumentException {
277 Validation.begin().isNotNull("Field Name", fieldName).check().isGreater("Field Name Length", fieldName.length(), 0).isNull("Field Name Unique", getFieldByName(fieldName)).check();
278 @SuppressWarnings("synthetic-access")
279 Field field = new Field().setName(fieldName);
285 * Moves the given field up one position in the field list. The index of the
286 * field to move must be greater than {@code 0} (because you obviously can
287 * not move the first field further up).
290 * The field to move up
292 public void moveFieldUp(Field field) {
293 Validation.begin().isNotNull("Field", field).check().is("Field Existing", hasField(field)).isGreater("Field Index", getFieldIndex(field), 0).check();
294 int fieldIndex = getFieldIndex(field);
295 fields.remove(field);
296 fields.add(fieldIndex - 1, field);
300 * Moves the given field down one position in the field list. The index of
301 * the field to move must be less than the index of the last field (because
302 * you obviously can not move the last field further down).
305 * The field to move down
307 public void moveFieldDown(Field field) {
308 Validation.begin().isNotNull("Field", field).check().is("Field Existing", hasField(field)).isLess("Field Index", getFieldIndex(field), fields.size() - 1).check();
309 int fieldIndex = getFieldIndex(field);
310 fields.remove(field);
311 fields.add(fieldIndex + 1, field);
315 * Removes the given field.
318 * The field to remove
320 public void removeField(Field field) {
321 Validation.begin().isNotNull("Field", field).check().is("Field Existing", hasField(field)).check();
322 fields.remove(field);
330 * Returns the index of the field with the given name.
333 * The name of the field
334 * @return The index of the field, or {@code -1} if there is no field with
337 private int getFieldIndex(Field field) {
338 return fields.indexOf(field);
342 // INTERFACE Fingerprintable
349 public String getFingerprint() {
350 StringBuilder fingerprint = new StringBuilder();
351 fingerprint.append("Profile(");
352 if (firstName != null) {
353 fingerprint.append("FirstName(").append(firstName).append(')');
355 if (middleName != null) {
356 fingerprint.append("MiddleName(").append(middleName).append(')');
358 if (lastName != null) {
359 fingerprint.append("LastName(").append(lastName).append(')');
361 if (birthDay != null) {
362 fingerprint.append("BirthDay(").append(birthDay).append(')');
364 if (birthMonth != null) {
365 fingerprint.append("BirthMonth(").append(birthMonth).append(')');
367 if (birthYear != null) {
368 fingerprint.append("BirthYear(").append(birthYear).append(')');
370 fingerprint.append("ContactInformation(");
371 for (Field field : fields) {
372 fingerprint.append(field.getName()).append('(').append(field.getValue()).append(')');
374 fingerprint.append(")");
375 fingerprint.append(")");
377 return fingerprint.toString();
381 * Container for a profile field.
383 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
387 /** The ID of the field. */
388 private final String id;
390 /** The name of the field. */
393 /** The value of the field. */
394 private String value;
397 * Creates a new field with a random ID.
400 this(UUID.randomUUID().toString());
404 * Creates a new field with the given ID.
407 * The ID of the field
409 private Field(String id) {
410 Validation.begin().isNotNull("Field ID", id).check();
415 * Returns the ID of this field.
417 * @return The ID of this field
419 public String getId() {
424 * Returns the name of this field.
426 * @return The name of this field
428 public String getName() {
433 * Sets the name of this field. The name must not be {@code null} and
434 * must not match any other fields in this profile but my match the name
438 * The new name of this field
441 public Field setName(String name) {
442 Validation.begin().isNotNull("Field Name", name).check().is("Field Unique", (getFieldByName(name) == null) || equals(getFieldByName(name))).check();
448 * Returns the value of this field.
450 * @return The value of this field
452 public String getValue() {
457 * Sets the value of this field. While {@code null} is allowed, no
458 * guarantees are made that {@code null} values are correctly persisted
459 * across restarts of the plugin!
462 * The new value of this field
465 public Field setValue(String value) {
478 public boolean equals(Object object) {
479 if (!(object instanceof Field)) {
482 Field field = (Field) object;
483 return id.equals(field.id);
490 public int hashCode() {
491 return id.hashCode();