+ public List<Field> getFields() {
+ return new ArrayList<Field>(fields);
+ }
+
+ public boolean hasField(Field field) {
+ return fields.contains(field);
+ }
+
+ public Optional<Field> getFieldById(String fieldId) {
+ checkNotNull(fieldId, "fieldId must not be null");
+ for (Field field : fields) {
+ if (field.getId().equals(fieldId)) {
+ return of(field);
+ }
+ }
+ return absent();
+ }
+
+ public Optional<Field> getFieldByName(String fieldName) {
+ for (Field field : fields) {
+ if (field.getName().equals(fieldName)) {
+ return of(field);
+ }
+ }
+ return absent();
+ }
+
+ public Field addField(String fieldName) throws IllegalArgumentException {
+ checkNotNull(fieldName, "fieldName must not be null");
+ checkArgument(fieldName.length() > 0, "fieldName must not be empty");
+ checkArgument(!getFieldByName(fieldName).isPresent(), "fieldName must be unique");
+ @SuppressWarnings("synthetic-access")
+ Field field = new Field(fieldName);
+ fields.add(field);
+ return field;
+ }
+
+ public void renameField(Field field, String newName) {
+ int indexOfField = getFieldIndex(field);
+ if (indexOfField == -1) {
+ return;
+ }
+ fields.set(indexOfField, new Field(field.getId(), newName, field.getValue()));
+ }
+
+ public void setField(Field field, String newValue) {
+ int indexOfField = getFieldIndex(field);
+ if (indexOfField == -1) {
+ return;
+ }
+ fields.set(indexOfField, new Field(field.getId(), field.getName(), newValue));
+ }
+
+ public void moveFieldUp(Field field) {
+ checkNotNull(field, "field must not be null");
+ checkArgument(hasField(field), "field must belong to this profile");
+ int fieldIndex = getFieldIndex(field);
+ fields.remove(field);
+ fields.add(max(fieldIndex - 1, 0), field);
+ }
+
+ public void moveFieldDown(Field field) {
+ checkNotNull(field, "field must not be null");
+ checkArgument(hasField(field), "field must belong to this profile");
+ int fieldIndex = getFieldIndex(field);
+ fields.remove(field);
+ fields.add(min(fieldIndex + 1, fields.size()), field);
+ }
+
+ public void removeField(Field field) {
+ checkNotNull(field, "field must not be null");
+ 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();
+
+ }
+
+ //
+ // PRIVATE METHODS
+ //
+