2 * Sone - Profile.java - Copyright © 2010–2012 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 Sone this profile belongs to. */
36 private final Sone sone;
38 /** The first name. */
39 private volatile String firstName;
41 /** The middle name(s). */
42 private volatile String middleName;
45 private volatile String lastName;
47 /** The day of the birth date. */
48 private volatile Integer birthDay;
50 /** The month of the birth date. */
51 private volatile Integer birthMonth;
53 /** The year of the birth date. */
54 private volatile Integer birthYear;
56 /** The ID of the avatar image. */
57 private volatile String avatar;
59 /** Additional fields in the profile. */
60 private final List<Field> fields = Collections.synchronizedList(new ArrayList<Field>());
63 * Creates a new empty profile.
66 * The Sone this profile belongs to
68 public Profile(Sone sone) {
73 * Creates a copy of a profile.
78 public Profile(Profile profile) {
79 this.sone = profile.sone;
80 this.firstName = profile.firstName;
81 this.middleName = profile.middleName;
82 this.lastName = profile.lastName;
83 this.birthDay = profile.birthDay;
84 this.birthMonth = profile.birthMonth;
85 this.birthYear = profile.birthYear;
86 this.avatar = profile.avatar;
87 this.fields.addAll(profile.fields);
95 * Returns the Sone this profile belongs to.
97 * @return The Sone this profile belongs to
99 public Sone getSone() {
104 * Returns the first name.
106 * @return The first name
108 public String getFirstName() {
113 * Sets the first name.
116 * The first name to set
117 * @return This profile (for method chaining)
119 public Profile setFirstName(String firstName) {
120 this.firstName = firstName;
125 * Returns the middle name(s).
127 * @return The middle name
129 public String getMiddleName() {
134 * Sets the middle name.
137 * The middle name to set
138 * @return This profile (for method chaining)
140 public Profile setMiddleName(String middleName) {
141 this.middleName = middleName;
146 * Returns the last name.
148 * @return The last name
150 public String getLastName() {
155 * Sets the last name.
158 * The last name to set
159 * @return This profile (for method chaining)
161 public Profile setLastName(String lastName) {
162 this.lastName = lastName;
167 * Returns the day of the birth date.
169 * @return The day of the birth date (from 1 to 31)
171 public Integer getBirthDay() {
176 * Sets the day of the birth date.
179 * The day of the birth date (from 1 to 31)
180 * @return This profile (for method chaining)
182 public Profile setBirthDay(Integer birthDay) {
183 this.birthDay = birthDay;
188 * Returns the month of the birth date.
190 * @return The month of the birth date (from 1 to 12)
192 public Integer getBirthMonth() {
197 * Sets the month of the birth date.
200 * The month of the birth date (from 1 to 12)
201 * @return This profile (for method chaining)
203 public Profile setBirthMonth(Integer birthMonth) {
204 this.birthMonth = birthMonth;
209 * Returns the year of the birth date.
211 * @return The year of the birth date
213 public Integer getBirthYear() {
218 * Returns the ID of the currently selected avatar image.
220 * @return The ID of the currently selected avatar image, or {@code null} if
221 * no avatar is selected.
223 public String getAvatar() {
228 * Sets the avatar image.
231 * The new avatar image, or {@code null} to not select an avatar
235 public Profile setAvatar(Image avatar) {
236 if (avatar == null) {
240 Validation.begin().isEqual("Image Owner", avatar.getSone(), sone).check();
241 this.avatar = avatar.getId();
246 * Sets the year of the birth date.
249 * The year of the birth date
250 * @return This profile (for method chaining)
252 public Profile setBirthYear(Integer birthYear) {
253 this.birthYear = birthYear;
258 * Returns the fields of this profile.
260 * @return The fields of this profile
262 public List<Field> getFields() {
263 return new ArrayList<Field>(fields);
267 * Returns whether this profile contains the given field.
270 * The field to check for
271 * @return {@code true} if this profile contains the field, false otherwise
273 public boolean hasField(Field field) {
274 return fields.contains(field);
278 * Returns the field with the given ID.
281 * The ID of the field to get
282 * @return The field, or {@code null} if this profile does not contain a
283 * field with the given ID
285 public Field getFieldById(String fieldId) {
286 Validation.begin().isNotNull("Field ID", fieldId).check();
287 for (Field field : fields) {
288 if (field.getId().equals(fieldId)) {
296 * Returns the field with the given name.
299 * The name of the field to get
300 * @return The field, or {@code null} if this profile does not contain a
301 * field with the given name
303 public Field getFieldByName(String fieldName) {
304 for (Field field : fields) {
305 if (field.getName().equals(fieldName)) {
313 * Appends a new field to the list of fields.
316 * The name of the new field
317 * @return The new field
318 * @throws IllegalArgumentException
319 * if the name is not valid
321 public Field addField(String fieldName) throws IllegalArgumentException {
322 Validation.begin().isNotNull("Field Name", fieldName).check().isGreater("Field Name Length", fieldName.length(), 0).isNull("Field Name Unique", getFieldByName(fieldName)).check();
323 @SuppressWarnings("synthetic-access")
324 Field field = new Field().setName(fieldName);
330 * Moves the given field up one position in the field list. The index of the
331 * field to move must be greater than {@code 0} (because you obviously can
332 * not move the first field further up).
335 * The field to move up
337 public void moveFieldUp(Field field) {
338 Validation.begin().isNotNull("Field", field).check().is("Field Existing", hasField(field)).isGreater("Field Index", getFieldIndex(field), 0).check();
339 int fieldIndex = getFieldIndex(field);
340 fields.remove(field);
341 fields.add(fieldIndex - 1, field);
345 * Moves the given field down one position in the field list. The index of
346 * the field to move must be less than the index of the last field (because
347 * you obviously can not move the last field further down).
350 * The field to move down
352 public void moveFieldDown(Field field) {
353 Validation.begin().isNotNull("Field", field).check().is("Field Existing", hasField(field)).isLess("Field Index", getFieldIndex(field), fields.size() - 1).check();
354 int fieldIndex = getFieldIndex(field);
355 fields.remove(field);
356 fields.add(fieldIndex + 1, field);
360 * Removes the given field.
363 * The field to remove
365 public void removeField(Field field) {
366 Validation.begin().isNotNull("Field", field).check().is("Field Existing", hasField(field)).check();
367 fields.remove(field);
375 * Returns the index of the field with the given name.
378 * The name of the field
379 * @return The index of the field, or {@code -1} if there is no field with
382 private int getFieldIndex(Field field) {
383 return fields.indexOf(field);
387 // INTERFACE Fingerprintable
394 public String getFingerprint() {
395 StringBuilder fingerprint = new StringBuilder();
396 fingerprint.append("Profile(");
397 if (firstName != null) {
398 fingerprint.append("FirstName(").append(firstName).append(')');
400 if (middleName != null) {
401 fingerprint.append("MiddleName(").append(middleName).append(')');
403 if (lastName != null) {
404 fingerprint.append("LastName(").append(lastName).append(')');
406 if (birthDay != null) {
407 fingerprint.append("BirthDay(").append(birthDay).append(')');
409 if (birthMonth != null) {
410 fingerprint.append("BirthMonth(").append(birthMonth).append(')');
412 if (birthYear != null) {
413 fingerprint.append("BirthYear(").append(birthYear).append(')');
415 if (avatar != null) {
416 fingerprint.append("Avatar(").append(avatar).append(')');
418 fingerprint.append("ContactInformation(");
419 for (Field field : fields) {
420 fingerprint.append(field.getName()).append('(').append(field.getValue()).append(')');
422 fingerprint.append(")");
423 fingerprint.append(")");
425 return fingerprint.toString();
429 * Container for a profile field.
431 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
435 /** The ID of the field. */
436 private final String id;
438 /** The name of the field. */
441 /** The value of the field. */
442 private String value;
445 * Creates a new field with a random ID.
448 this(UUID.randomUUID().toString());
452 * Creates a new field with the given ID.
455 * The ID of the field
457 private Field(String id) {
458 Validation.begin().isNotNull("Field ID", id).check();
463 * Returns the ID of this field.
465 * @return The ID of this field
467 public String getId() {
472 * Returns the name of this field.
474 * @return The name of this field
476 public String getName() {
481 * Sets the name of this field. The name must not be {@code null} and
482 * must not match any other fields in this profile but my match the name
486 * The new name of this field
489 public Field setName(String name) {
490 Validation.begin().isNotNull("Field Name", name).check().is("Field Unique", (getFieldByName(name) == null) || equals(getFieldByName(name))).check();
496 * Returns the value of this field.
498 * @return The value of this field
500 public String getValue() {
505 * Sets the value of this field. While {@code null} is allowed, no
506 * guarantees are made that {@code null} values are correctly persisted
507 * across restarts of the plugin!
510 * The new value of this field
513 public Field setValue(String value) {
526 public boolean equals(Object object) {
527 if (!(object instanceof Field)) {
530 Field field = (Field) object;
531 return id.equals(field.id);
538 public int hashCode() {
539 return id.hashCode();