+ public Integer getBirthMonth() {
+ return birthDate.getMonth().orNull();
+ }
+
+ /**
+ * Returns the year of the birth date.
+ *
+ * @return The year of the birth date
+ */
+ public Integer getBirthYear() {
+ return birthDate.getYear().orNull();
+ }
+
+ /**
+ * Returns the ID of the currently selected avatar image.
+ *
+ * @return The ID of the currently selected avatar image, or {@code null} if
+ * no avatar is selected.
+ */
+ public String getAvatar() {
+ return avatar;
+ }
+
+ /**
+ * Sets the avatar image.
+ *
+ * @param avatar
+ * The new avatar image, or {@code null} to not select an avatar
+ * image.
+ * @return This Sone
+ */
+ public Profile setAvatar(Image avatar) {
+ if (avatar == null) {
+ this.avatar = null;
+ return this;
+ }
+ checkArgument(avatar.getSone().equals(sone), "avatar must belong to Sone");
+ this.avatar = avatar.getId();
+ return this;
+ }
+
+ /**
+ * Returns the fields of this profile.
+ *
+ * @return The fields of this profile
+ */
+ public List<Field> getFields() {
+ return new ArrayList<Field>(fields);
+ }
+
+ /**
+ * Returns whether this profile contains the given field.
+ *
+ * @param field
+ * The field to check for
+ * @return {@code true} if this profile contains the field, false otherwise
+ */
+ public boolean hasField(Field field) {
+ return fields.contains(field);
+ }
+
+ /**
+ * Returns the field with the given ID.
+ *
+ * @param fieldId
+ * The ID of the field to get
+ * @return The field, or {@code null} if this profile does not contain a
+ * field with the given ID
+ */
+ public Field getFieldById(String fieldId) {
+ checkNotNull(fieldId, "fieldId must not be null");
+ for (Field field : fields) {
+ if (field.getId().equals(fieldId)) {
+ return field;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the field with the given name.
+ *
+ * @param fieldName
+ * The name of the field to get
+ * @return The field, or {@code null} if this profile does not contain a
+ * field with the given name
+ */
+ public Field getFieldByName(String fieldName) {
+ for (Field field : fields) {
+ if (field.getName().equals(fieldName)) {
+ return field;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Appends a new field to the list of fields.
+ *
+ * @param fieldName
+ * The name of the new field
+ * @return The new field
+ * @throws IllegalArgumentException
+ * if the name is not valid
+ */
+ public Field addField(String fieldName) throws IllegalArgumentException {
+ checkNotNull(fieldName, "fieldName must not be null");
+ checkArgument(fieldName.length() > 0, "fieldName must not be empty");
+ checkState(getFieldByName(fieldName) == null, "fieldName must be unique");
+ @SuppressWarnings("synthetic-access")
+ Field field = new Field().setName(fieldName);
+ fields.add(field);
+ return field;
+ }
+
+ /**
+ * Moves the given field up one position in the field list. The index of the
+ * field to move must be greater than {@code 0} (because you obviously can
+ * not move the first field further up).
+ *
+ * @param field
+ * The field to move up
+ */
+ public void moveFieldUp(Field field) {
+ checkNotNull(field, "field must not be null");
+ checkArgument(hasField(field), "field must belong to this profile");
+ checkArgument(getFieldIndex(field) > 0, "field index must be > 0");
+ int fieldIndex = getFieldIndex(field);
+ fields.remove(field);
+ fields.add(fieldIndex - 1, field);
+ }
+
+ /**
+ * Moves the given field down one position in the field list. The index of
+ * the field to move must be less than the index of the last field (because
+ * you obviously can not move the last field further down).
+ *
+ * @param field
+ * The field to move down
+ */
+ public void moveFieldDown(Field field) {
+ checkNotNull(field, "field must not be null");
+ checkArgument(hasField(field), "field must belong to this profile");
+ checkArgument(getFieldIndex(field) < fields.size() - 1, "field index must be < " + (fields.size() - 1));
+ int fieldIndex = getFieldIndex(field);
+ fields.remove(field);
+ fields.add(fieldIndex + 1, field);
+ }
+
+ /**
+ * Removes the given field.
+ *
+ * @param field
+ * The field to remove
+ */
+ public void removeField(Field field) {
+ checkNotNull(field, "field must not be null");
+ checkArgument(hasField(field), "field must belong to this profile");
+ fields.remove(field);
+ }
+
+ public Modifier modify() {
+ return new Modifier() {
+ private Optional<String> firstName = name.getFirst();
+ private Optional<String> middleName = name.getMiddle();
+ private Optional<String> lastName = name.getLast();
+ private Optional<Integer> birthYear = birthDate.getYear();
+ private Optional<Integer> birthMonth = birthDate.getMonth();
+ private Optional<Integer> birthDay = birthDate.getDay();
+
+ @Override
+ public Modifier setFirstName(String firstName) {
+ this.firstName = fromNullable(firstName);
+ return this;
+ }
+
+ @Override
+ public Modifier setMiddleName(String middleName) {
+ this.middleName = fromNullable(middleName);
+ return this;
+ }
+
+ @Override
+ public Modifier setLastName(String lastName) {
+ this.lastName = fromNullable(lastName);
+ return this;
+ }
+
+ @Override
+ public Modifier setBirthYear(Integer birthYear) {
+ this.birthYear = fromNullable(birthYear);
+ return this;
+ }
+
+ @Override
+ public Modifier setBirthMonth(Integer birthMonth) {
+ this.birthMonth = fromNullable(birthMonth);
+ return this;
+ }
+
+ @Override
+ public Modifier setBirthDay(Integer birthDay) {
+ this.birthDay = fromNullable(birthDay);
+ return this;
+ }
+
+ @Override
+ public Profile update() {
+ Profile.this.name = new Name(firstName, middleName, lastName);
+ Profile.this.birthDate = new BirthDate(birthYear, birthMonth, birthDay);
+ return Profile.this;
+ }
+ };
+ }
+
+ public interface Modifier {
+
+ Modifier setFirstName(String firstName);
+ Modifier setMiddleName(String middleName);
+ Modifier setLastName(String lastName);
+ Modifier setBirthYear(Integer birthYear);
+ Modifier setBirthMonth(Integer birthMonth);
+ Modifier setBirthDay(Integer birthDay);
+ Profile update();
+