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 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 first name.
97 * @return The first name
99 public String getFirstName() {
104 * Sets the first name.
107 * The first name to set
108 * @return This profile (for method chaining)
110 public Profile setFirstName(String firstName) {
111 this.firstName = firstName;
116 * Returns the middle name(s).
118 * @return The middle name
120 public String getMiddleName() {
125 * Sets the middle name.
128 * The middle name to set
129 * @return This profile (for method chaining)
131 public Profile setMiddleName(String middleName) {
132 this.middleName = middleName;
137 * Returns the last name.
139 * @return The last name
141 public String getLastName() {
146 * Sets the last name.
149 * The last name to set
150 * @return This profile (for method chaining)
152 public Profile setLastName(String lastName) {
153 this.lastName = lastName;
158 * Returns the day of the birth date.
160 * @return The day of the birth date (from 1 to 31)
162 public Integer getBirthDay() {
167 * Sets the day of the birth date.
170 * The day of the birth date (from 1 to 31)
171 * @return This profile (for method chaining)
173 public Profile setBirthDay(Integer birthDay) {
174 this.birthDay = birthDay;
179 * Returns the month of the birth date.
181 * @return The month of the birth date (from 1 to 12)
183 public Integer getBirthMonth() {
188 * Sets the month of the birth date.
191 * The month of the birth date (from 1 to 12)
192 * @return This profile (for method chaining)
194 public Profile setBirthMonth(Integer birthMonth) {
195 this.birthMonth = birthMonth;
200 * Returns the year of the birth date.
202 * @return The year of the birth date
204 public Integer getBirthYear() {
209 * Returns the ID of the currently selected avatar image.
211 * @return The ID of the currently selected avatar image, or {@code null} if
212 * no avatar is selected.
214 public String getAvatar() {
219 * Sets the avatar image.
222 * The new avatar image, or {@code null} to not select an avatar
226 public Profile setAvatar(Image avatar) {
227 if (avatar == null) {
231 Validation.begin().isEqual("Image Owner", avatar.getSone(), sone).check();
232 this.avatar = avatar.getId();
237 * Sets the year of the birth date.
240 * The year of the birth date
241 * @return This profile (for method chaining)
243 public Profile setBirthYear(Integer birthYear) {
244 this.birthYear = birthYear;
249 * Returns the fields of this profile.
251 * @return The fields of this profile
253 public List<Field> getFields() {
254 return new ArrayList<Field>(fields);
258 * Returns whether this profile contains the given field.
261 * The field to check for
262 * @return {@code true} if this profile contains the field, false otherwise
264 public boolean hasField(Field field) {
265 return fields.contains(field);
269 * Returns the field with the given ID.
272 * The ID of the field to get
273 * @return The field, or {@code null} if this profile does not contain a
274 * field with the given ID
276 public Field getFieldById(String fieldId) {
277 Validation.begin().isNotNull("Field ID", fieldId).check();
278 for (Field field : fields) {
279 if (field.getId().equals(fieldId)) {
287 * Returns the field with the given name.
290 * The name of the field to get
291 * @return The field, or {@code null} if this profile does not contain a
292 * field with the given name
294 public Field getFieldByName(String fieldName) {
295 for (Field field : fields) {
296 if (field.getName().equals(fieldName)) {
304 * Appends a new field to the list of fields.
307 * The name of the new field
308 * @return The new field
309 * @throws IllegalArgumentException
310 * if the name is not valid
312 public Field addField(String fieldName) throws IllegalArgumentException {
313 Validation.begin().isNotNull("Field Name", fieldName).check().isGreater("Field Name Length", fieldName.length(), 0).isNull("Field Name Unique", getFieldByName(fieldName)).check();
314 @SuppressWarnings("synthetic-access")
315 Field field = new Field().setName(fieldName);
321 * Moves the given field up one position in the field list. The index of the
322 * field to move must be greater than {@code 0} (because you obviously can
323 * not move the first field further up).
326 * The field to move up
328 public void moveFieldUp(Field field) {
329 Validation.begin().isNotNull("Field", field).check().is("Field Existing", hasField(field)).isGreater("Field Index", getFieldIndex(field), 0).check();
330 int fieldIndex = getFieldIndex(field);
331 fields.remove(field);
332 fields.add(fieldIndex - 1, field);
336 * Moves the given field down one position in the field list. The index of
337 * the field to move must be less than the index of the last field (because
338 * you obviously can not move the last field further down).
341 * The field to move down
343 public void moveFieldDown(Field field) {
344 Validation.begin().isNotNull("Field", field).check().is("Field Existing", hasField(field)).isLess("Field Index", getFieldIndex(field), fields.size() - 1).check();
345 int fieldIndex = getFieldIndex(field);
346 fields.remove(field);
347 fields.add(fieldIndex + 1, field);
351 * Removes the given field.
354 * The field to remove
356 public void removeField(Field field) {
357 Validation.begin().isNotNull("Field", field).check().is("Field Existing", hasField(field)).check();
358 fields.remove(field);
366 * Returns the index of the field with the given name.
369 * The name of the field
370 * @return The index of the field, or {@code -1} if there is no field with
373 private int getFieldIndex(Field field) {
374 return fields.indexOf(field);
378 // INTERFACE Fingerprintable
385 public String getFingerprint() {
386 StringBuilder fingerprint = new StringBuilder();
387 fingerprint.append("Profile(");
388 if (firstName != null) {
389 fingerprint.append("FirstName(").append(firstName).append(')');
391 if (middleName != null) {
392 fingerprint.append("MiddleName(").append(middleName).append(')');
394 if (lastName != null) {
395 fingerprint.append("LastName(").append(lastName).append(')');
397 if (birthDay != null) {
398 fingerprint.append("BirthDay(").append(birthDay).append(')');
400 if (birthMonth != null) {
401 fingerprint.append("BirthMonth(").append(birthMonth).append(')');
403 if (birthYear != null) {
404 fingerprint.append("BirthYear(").append(birthYear).append(')');
406 if (avatar != null) {
407 fingerprint.append("Avatar(").append(avatar).append(')');
409 fingerprint.append("ContactInformation(");
410 for (Field field : fields) {
411 fingerprint.append(field.getName()).append('(').append(field.getValue()).append(')');
413 fingerprint.append(")");
414 fingerprint.append(")");
416 return fingerprint.toString();
420 * Container for a profile field.
422 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
426 /** The ID of the field. */
427 private final String id;
429 /** The name of the field. */
432 /** The value of the field. */
433 private String value;
436 * Creates a new field with a random ID.
439 this(UUID.randomUUID().toString());
443 * Creates a new field with the given ID.
446 * The ID of the field
448 private Field(String id) {
449 Validation.begin().isNotNull("Field ID", id).check();
454 * Returns the ID of this field.
456 * @return The ID of this field
458 public String getId() {
463 * Returns the name of this field.
465 * @return The name of this field
467 public String getName() {
472 * Sets the name of this field. The name must not be {@code null} and
473 * must not match any other fields in this profile but my match the name
477 * The new name of this field
480 public Field setName(String name) {
481 Validation.begin().isNotNull("Field Name", name).check().is("Field Unique", (getFieldByName(name) == null) || equals(getFieldByName(name))).check();
487 * Returns the value of this field.
489 * @return The value of this field
491 public String getValue() {
496 * Sets the value of this field. While {@code null} is allowed, no
497 * guarantees are made that {@code null} values are correctly persisted
498 * across restarts of the plugin!
501 * The new value of this field
504 public Field setValue(String value) {
517 public boolean equals(Object object) {
518 if (!(object instanceof Field)) {
521 Field field = (Field) object;
522 return id.equals(field.id);
529 public int hashCode() {
530 return id.hashCode();