diff --git a/src/main/java/seedu/address/logic/Messages.java b/src/main/java/seedu/address/logic/Messages.java index 8362ed9d16e..b6d5c202812 100644 --- a/src/main/java/seedu/address/logic/Messages.java +++ b/src/main/java/seedu/address/logic/Messages.java @@ -17,8 +17,10 @@ public class Messages { public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command"; public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s"; public static final String MESSAGE_INVALID_PERSON_DISPLAYED_INDEX = "The person index provided is invalid"; + public static final String MESSAGE_INVALID_DENTIST_DISPLAYED_INDEX = "The dentist index provided is invalid!"; public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!"; public static final String MESSAGE_DENTISTS_LISTED_OVERVIEW = "%1$d dentists listed!"; + public static final String MESSAGE_INVALID_PATIENT_DISPLAYED_INDEX = "The patient index provided is invalid"; public static final String MESSAGE_PATIENTS_LISTED_OVERVIEW = "%1$d patients listed!"; public static final String MESSAGE_DUPLICATE_FIELDS = diff --git a/src/main/java/seedu/address/logic/commands/DeleteDentistCommand.java b/src/main/java/seedu/address/logic/commands/DeleteDentistCommand.java index f741df592a1..7de2c8df5f7 100644 --- a/src/main/java/seedu/address/logic/commands/DeleteDentistCommand.java +++ b/src/main/java/seedu/address/logic/commands/DeleteDentistCommand.java @@ -45,7 +45,7 @@ public CommandResult execute(Model model) throws CommandException { } catch (Exception e) { throw new CommandException("An error occurred while deleting the dentist: " + e.getMessage() - + "Please use list-dentists or search-dentist to get the Dentist ID on the screen first."); + + " Please use list-dentists or search-dentist to get the Dentist ID on the screen first."); } } diff --git a/src/main/java/seedu/address/logic/commands/DeletePatientCommand.java b/src/main/java/seedu/address/logic/commands/DeletePatientCommand.java index e68bd45855b..4cde4649897 100644 --- a/src/main/java/seedu/address/logic/commands/DeletePatientCommand.java +++ b/src/main/java/seedu/address/logic/commands/DeletePatientCommand.java @@ -45,7 +45,7 @@ public CommandResult execute(Model model) throws CommandException { } catch (Exception e) { throw new CommandException("An error occurred while deleting the patient: " + e.getMessage() - + "Please use list-patients or search-patient to get the Patient ID on the screen first."); + + " Please use list-patients or search-patient to get intended Patient on the screen first."); } } diff --git a/src/main/java/seedu/address/logic/commands/EditDentistCommand.java b/src/main/java/seedu/address/logic/commands/EditDentistCommand.java new file mode 100644 index 00000000000..d964555b942 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/EditDentistCommand.java @@ -0,0 +1,291 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; +import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; +import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; +import static seedu.address.logic.parser.CliSyntax.PREFIX_SPECIALIZATION; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; +import static seedu.address.logic.parser.CliSyntax.PREFIX_YOE; +import static seedu.address.model.Model.PREDICATE_SHOW_ALL_DENTISTS; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; + +import seedu.address.commons.util.CollectionUtil; +import seedu.address.commons.util.ToStringBuilder; +import seedu.address.logic.Messages; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.person.Address; +import seedu.address.model.person.Email; +import seedu.address.model.person.Name; +import seedu.address.model.person.Phone; +import seedu.address.model.person.dentist.Dentist; +import seedu.address.model.person.dentist.Specialization; +import seedu.address.model.person.dentist.Yoe; +import seedu.address.model.tag.Tag; + +/** + * Edits the details of an existing person in the address book. + */ +public class EditDentistCommand extends Command { + + public static final String COMMAND_WORD = "edit-dentist"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the dentist identified " + + "by the index number used in the displayed dentist list. " + + "Existing values will be overwritten by the input values.\n" + + "Parameters: DENTIST_ID (must be a positive integer) " + + "[" + PREFIX_NAME + "NAME] " + + "[" + PREFIX_PHONE + "PHONE] " + + "[" + PREFIX_EMAIL + "EMAIL] " + + "[" + PREFIX_ADDRESS + "ADDRESS] " + + "[" + PREFIX_SPECIALIZATION + "SPECIALIZATION] " + + "[" + PREFIX_YOE + "YEARS OF EXPERIENCE] " + + "[" + PREFIX_TAG + "TAG]...\n" + + "Example: " + COMMAND_WORD + " 1 " + + PREFIX_PHONE + "91234567 " + + PREFIX_EMAIL + "johndoe@example.com" + + PREFIX_SPECIALIZATION + "Orthodontics"; + + public static final String MESSAGE_EDIT_DENTIST_SUCCESS = "Edited Dentist: %1$s"; + public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided."; + public static final String MESSAGE_DUPLICATE_DENTIST = "This dentist already exists in the address book."; + + private final long dentistId; + private final EditDentistDescriptor editDentistDescriptor; + + /** + * @param dentistId of the dentist in the filtered dentist list to edit + * @param editDentistDescriptor details to edit the dentist with + */ + public EditDentistCommand(long dentistId, EditDentistDescriptor editDentistDescriptor) { + requireNonNull(dentistId); + requireNonNull(editDentistDescriptor); + + this.dentistId = dentistId; + this.editDentistDescriptor = new EditDentistDescriptor(editDentistDescriptor); + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + + try { + Dentist dentistToEdit = model.getDentistById(dentistId); + + if (dentistToEdit == null) { + throw new CommandException(Messages.MESSAGE_INVALID_DENTIST_DISPLAYED_INDEX); + } + Dentist editedDentist = createEditedDentist(dentistToEdit, editDentistDescriptor); + + if (!dentistToEdit.isSamePerson(editedDentist) && model.hasPerson(editedDentist)) { + throw new CommandException(MESSAGE_DUPLICATE_DENTIST); + } + + model.setDentist(dentistToEdit, editedDentist); + model.updateFilteredDentistList(PREDICATE_SHOW_ALL_DENTISTS); + return new CommandResult(String.format(MESSAGE_EDIT_DENTIST_SUCCESS, Messages.format(editedDentist))); + + } catch (Exception e) { + throw new CommandException("An error occurred while editing the dentist: " + e.getMessage() + + " Please use list-dentists or search-dentist to get the intended Dentist on the screen first."); + } + + } + + /** + * Creates and returns a {@code Person} with the details of {@code personToEdit} + * edited with {@code editPersonDescriptor}. + */ + private static Dentist createEditedDentist(Dentist dentistToEdit, EditDentistDescriptor editDentistDescriptor) { + assert dentistToEdit != null; + + Name updatedName = editDentistDescriptor.getName().orElse(dentistToEdit.getName()); + Phone updatedPhone = editDentistDescriptor.getPhone().orElse(dentistToEdit.getPhone()); + Email updatedEmail = editDentistDescriptor.getEmail().orElse(dentistToEdit.getEmail()); + Address updatedAddress = editDentistDescriptor.getAddress().orElse(dentistToEdit.getAddress()); + Specialization updatedSpecialization = editDentistDescriptor.getSpecialization() + .orElse(dentistToEdit.getSpecialization()); + Yoe updatedYoe = editDentistDescriptor.getYoe().orElse(dentistToEdit.getYoe()); + long dentistIdRemains = dentistToEdit.getId(); //ID Must not change! + Set updatedTags = editDentistDescriptor.getTags().orElse(dentistToEdit.getTags()); + + return new Dentist(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedSpecialization, + updatedYoe, dentistIdRemains, updatedTags); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof EditDentistCommand)) { + return false; + } + + EditDentistCommand otherEditCommand = (EditDentistCommand) other; + return dentistId == (otherEditCommand.dentistId) + && editDentistDescriptor.equals(otherEditCommand.editDentistDescriptor); + } + + @Override + public String toString() { + return new ToStringBuilder(this) + .add("dentistId", dentistId) + .add("editDentistDescriptor", editDentistDescriptor) + .toString(); + } + + /** + * Stores the details to edit the person with. Each non-empty field value will replace the + * corresponding field value of the person. + */ + public static class EditDentistDescriptor { + private Name name; + private Phone phone; + private Email email; + private Address address; + private Specialization specialization; + private Yoe yoe; + private long dentistId; + private Set tags; + + public EditDentistDescriptor() {} + + /** + * Copy constructor. + * A defensive copy of {@code tags} is used internally. + */ + public EditDentistDescriptor(EditDentistDescriptor toCopy) { + setName(toCopy.name); + setPhone(toCopy.phone); + setEmail(toCopy.email); + setAddress(toCopy.address); + setSpecialization(toCopy.specialization); + setYoe(toCopy.yoe); + setDentistId(toCopy.dentistId); + setTags(toCopy.tags); + } + + /** + * Returns true if at least one field is edited. + */ + public boolean isAnyFieldEdited() { + return CollectionUtil.isAnyNonNull(name, phone, email, address, tags); + } + + public void setName(Name name) { + this.name = name; + } + + public Optional getName() { + return Optional.ofNullable(name); + } + + public void setPhone(Phone phone) { + this.phone = phone; + } + + public Optional getPhone() { + return Optional.ofNullable(phone); + } + + public void setEmail(Email email) { + this.email = email; + } + + public Optional getEmail() { + return Optional.ofNullable(email); + } + + public void setAddress(Address address) { + this.address = address; + } + + public Optional
getAddress() { + return Optional.ofNullable(address); + } + + public void setSpecialization(Specialization specialization) { + this.specialization = specialization; + } + + public Optional getSpecialization() { + return Optional.ofNullable(specialization); + } + + public void setYoe(Yoe yoe) { + this.yoe = yoe; + } + + public Optional getYoe() { + return Optional.ofNullable(yoe); + } + + public void setDentistId(long id) { + this.dentistId = id; + } + + public Optional getDentistId() { + return Optional.ofNullable(dentistId); + } + + /** + * Sets {@code tags} to this object's {@code tags}. + * A defensive copy of {@code tags} is used internally. + */ + public void setTags(Set tags) { + this.tags = (tags != null) ? new HashSet<>(tags) : null; + } + + /** + * Returns an unmodifiable tag set, which throws {@code UnsupportedOperationException} + * if modification is attempted. + * Returns {@code Optional#empty()} if {@code tags} is null. + */ + public Optional> getTags() { + return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty(); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + + // instanceof handles nulls + if (!(other instanceof EditDentistDescriptor)) { + return false; + } + + EditDentistDescriptor otherEditDentistDescriptor = (EditDentistDescriptor) other; + return Objects.equals(name, otherEditDentistDescriptor.getName()) + && Objects.equals(phone, otherEditDentistDescriptor.getPhone()) + && Objects.equals(email, otherEditDentistDescriptor.getEmail()) + && Objects.equals(address, otherEditDentistDescriptor.getAddress()) + && Objects.equals(specialization, otherEditDentistDescriptor.getSpecialization()) + && Objects.equals(yoe, otherEditDentistDescriptor.getYoe()) + && Objects.equals(dentistId, otherEditDentistDescriptor.getDentistId()) + && Objects.equals(tags, otherEditDentistDescriptor.tags); + } + + @Override + public String toString() { + return new ToStringBuilder(this) + .add("name", name) + .add("phone", phone) + .add("email", email) + .add("address", address) + .add("tags", tags) + .toString(); + } + } +} diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java index c65e1940a75..69c0711000b 100644 --- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java +++ b/src/main/java/seedu/address/logic/parser/AddressBookParser.java @@ -17,6 +17,7 @@ import seedu.address.logic.commands.DeleteDentistCommand; import seedu.address.logic.commands.DeletePatientCommand; import seedu.address.logic.commands.EditCommand; +import seedu.address.logic.commands.EditDentistCommand; import seedu.address.logic.commands.ExitCommand; import seedu.address.logic.commands.HelpCommand; import seedu.address.logic.commands.ListCommand; @@ -71,10 +72,11 @@ public Command parseCommand(String userInput) throws ParseException { case EditCommand.COMMAND_WORD: return new EditCommandParser().parse(arguments); + case EditDentistCommand.COMMAND_WORD: + return new EditDentistCommandParser().parse(arguments); case DeletePatientCommand.COMMAND_WORD: return new DeletePatientCommandParser().parse(arguments); - case DeleteDentistCommand.COMMAND_WORD: return new DeleteDentistCommandParser().parse(arguments); diff --git a/src/main/java/seedu/address/logic/parser/EditDentistCommandParser.java b/src/main/java/seedu/address/logic/parser/EditDentistCommandParser.java new file mode 100644 index 00000000000..29a8282fd93 --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/EditDentistCommandParser.java @@ -0,0 +1,111 @@ +package seedu.address.logic.parser; + +import static java.util.Objects.requireNonNull; +import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT; +import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS; +import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL; +import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; +import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE; +import static seedu.address.logic.parser.CliSyntax.PREFIX_SPECIALIZATION; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; +import static seedu.address.logic.parser.CliSyntax.PREFIX_YOE; + +import java.util.Collection; +import java.util.Collections; +import java.util.Optional; +import java.util.Set; + +import seedu.address.logic.commands.EditCommand; +import seedu.address.logic.commands.EditDentistCommand; +import seedu.address.logic.commands.EditDentistCommand.EditDentistDescriptor; +import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.tag.Tag; + +/** + * Parses input arguments and creates a new EditDentistCommand object + */ +public class EditDentistCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the EditDentistCommand + * and returns an EditDentistCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public EditDentistCommand parse(String args) throws ParseException { + requireNonNull(args); + try { + String[] argsArray = args.trim().split("\\s+"); + String firstArg = argsArray[0].trim(); + long dentistId = Long.parseLong(firstArg); + + ArgumentMultimap argMultimap = + ArgumentTokenizer.tokenize(args, + PREFIX_NAME, + PREFIX_PHONE, + PREFIX_EMAIL, + PREFIX_ADDRESS, + PREFIX_SPECIALIZATION, + PREFIX_YOE, + PREFIX_TAG); + + argMultimap.verifyNoDuplicatePrefixesFor( + PREFIX_NAME, + PREFIX_PHONE, + PREFIX_EMAIL, + PREFIX_ADDRESS, + PREFIX_SPECIALIZATION, + PREFIX_YOE, + PREFIX_TAG); + + EditDentistCommand.EditDentistDescriptor editDentistDescriptor = new EditDentistDescriptor(); + + if (argMultimap.getValue(PREFIX_NAME).isPresent()) { + editDentistDescriptor.setName(ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get())); + } + if (argMultimap.getValue(PREFIX_PHONE).isPresent()) { + editDentistDescriptor.setPhone(ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get())); + } + if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) { + editDentistDescriptor.setEmail(ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get())); + } + if (argMultimap.getValue(PREFIX_ADDRESS).isPresent()) { + editDentistDescriptor.setAddress(ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get())); + } + if (argMultimap.getValue(PREFIX_SPECIALIZATION).isPresent()) { + editDentistDescriptor.setSpecialization( + ParserUtil.parseSpecialization(argMultimap.getValue(PREFIX_SPECIALIZATION).get())); + } + if (argMultimap.getValue(PREFIX_YOE).isPresent()) { + editDentistDescriptor.setYoe(ParserUtil.parseYoe(argMultimap.getValue(PREFIX_YOE).get())); + } + parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editDentistDescriptor::setTags); + + if (!editDentistDescriptor.isAnyFieldEdited()) { + throw new ParseException(EditCommand.MESSAGE_NOT_EDITED); + } + + return new EditDentistCommand(dentistId, editDentistDescriptor); + } catch (NumberFormatException | NullPointerException e) { + throw new ParseException( + String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditDentistCommand.MESSAGE_USAGE), e); + } + + + } + + /** + * Parses {@code Collection tags} into a {@code Set} if {@code tags} is non-empty. + * If {@code tags} contain only one element which is an empty string, it will be parsed into a + * {@code Set} containing zero tags. + */ + private Optional> parseTagsForEdit(Collection tags) throws ParseException { + assert tags != null; + + if (tags.isEmpty()) { + return Optional.empty(); + } + Collection tagSet = tags.size() == 1 && tags.contains("") ? Collections.emptySet() : tags; + return Optional.of(ParserUtil.parseTags(tagSet)); + } + +} diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java index 149f1150e12..d5e19a6e2be 100644 --- a/src/main/java/seedu/address/model/Model.java +++ b/src/main/java/seedu/address/model/Model.java @@ -123,6 +123,14 @@ public interface Model { */ void setPerson(Person target, Person editedPerson); + /** + * Replaces the given dentist {@code target} with {@code editedDentist}. + * {@code target} must exist in the address book. + * The dentist identity of {@code editedDentist} must not be the same as + * another existing dentist in the address book. + */ + void setDentist(Dentist target, Dentist editedDentist); + /** * Returns an unmodifiable view of the filtered person list */ @@ -164,4 +172,5 @@ public interface Model { void updateFilteredDentistList(Predicate predicate); void updateFilteredDentistList(NameContainsKeywordsPredicate predicate); + } diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index 2e6fe2321a1..fd499324043 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -192,6 +192,13 @@ public void setPerson(Person target, Person editedPerson) { addressBook.setPerson(target, editedPerson); } + @Override + public void setDentist(Dentist target, Dentist editedDentist) { + requireAllNonNull(target, editedDentist); + + addressBook.setDentist(target, editedDentist); + } + //=========== Filtered Person List Accessors ============================================================= /** diff --git a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java b/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java index 54bcadd0a6f..40bde6a838e 100644 --- a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java +++ b/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java @@ -101,8 +101,8 @@ public AddressBook toModelType() throws IllegalValueException { addressBook.addAppointment(appointment); } + addressBook.setDentistId(Long.parseLong(dentistId)); addressBook.setPatientId(Long.parseLong(patientId)); - // addressBook.setDentistId(Long.parseLong(dentistId)); return addressBook; } diff --git a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json index 22f4f6adc49..4b12a4efb56 100644 --- a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json +++ b/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json @@ -43,5 +43,6 @@ "address" : "4th street", "tags" : [ ] } ], - "patientId" : "6" + "patientId" : "6", + "dentistId" : "6" } diff --git a/src/test/java/seedu/address/logic/commands/AddCommandTest.java b/src/test/java/seedu/address/logic/commands/AddCommandTest.java index a7b09a1d87e..f4b2331259b 100644 --- a/src/test/java/seedu/address/logic/commands/AddCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/AddCommandTest.java @@ -163,6 +163,11 @@ public void setPerson(Person target, Person editedPerson) { throw new AssertionError("This method should not be called."); } + @Override + public void setDentist(Dentist target, Dentist editedDentist) { + throw new AssertionError("This method should not be called."); + } + @Override public ObservableList getFilteredPersonList() { throw new AssertionError("This method should not be called.");