package seedu.address.model.task;

import java.util.Objects;
import java.util.Optional;

import seedu.address.commons.util.CollectionUtil;
import seedu.address.model.tag.UniqueTagList;

/**
 * Represents a Task in the task list.
 * Guarantees: details are present and not null, field values are validated.
 */
public class Task implements ReadOnlyTask {

    private Name name;

    private UniqueTagList tags;

    private Optional<StartEndDateTime> startEndDateTime;

    private Optional<Deadline> deadline;

    /**
     * Every field must not be null except for the {@code Optional} fields.
     */
    public Task(Name name, Optional<Deadline> deadline, Optional<StartEndDateTime> startEndDateTime,
            UniqueTagList tags) {
        assert !CollectionUtil.isAnyNull(name, deadline, startEndDateTime, tags);
        this.name = name;
        this.deadline = deadline;
        this.startEndDateTime = startEndDateTime;
        this.tags = new UniqueTagList(tags); // protect internal tags from changes in the arg list
    }

    /**
     * Creates a copy of the given ReadOnlyTask.
     */
    public Task(ReadOnlyTask source) {
        this(source.getName(), source.getDeadline(), source.getStartEndDateTime(), source.getTags());
    }

    public void setName(Name name) {
        assert name != null;
        this.name = name;
    }

    @Override
    public Name getName() {
        return name;
    }

    @Override
    public Optional<Deadline> getDeadline() {
        return deadline;
    }

    /**
     * Only allow changing the {@link StartEndDateTime} if there is actually a value (not {@link Optional}).
     */
    public void setDeadline(Deadline dateTime) {
        assert dateTime != null;
        this.deadline = Optional.of(dateTime);
    }

    @Override
    public Optional<StartEndDateTime> getStartEndDateTime() {
        return startEndDateTime;
    }

    /**
     * Only allow changing the {@link StartEndDateTime} if there is actually a value (not {@link Optional}).
     */
    public void setStartEndDateTime(StartEndDateTime dateTime) {
        assert dateTime != null;
        this.startEndDateTime = Optional.of(dateTime);
    }

    @Override
    public UniqueTagList getTags() {
        return new UniqueTagList(tags);
    }

    /**
     * Replaces this task's tags with the tags in the argument tag list.
     */
    public void setTags(UniqueTagList replacement) {
        tags.setTags(replacement);
    }

    /**
     * Updates this task with the details of {@code replacement}.
     */
    public void resetData(ReadOnlyTask replacement) {
        assert replacement != null;

        this.setName(replacement.getName());
        // TODO to use or not to use a new Optional to wrap the Deadline
        // replacement Deadline is currently reused
        if (replacement.getDeadline().isPresent()) {
            this.deadline = Optional.of(replacement.getDeadline().get());
        } else {
            this.deadline = Optional.empty();
        }
        // TODO to use or not to use a new Optional to wrap the startEndDateTime
        // replacement startEndDateTime is currently reused
        if (replacement.getStartEndDateTime().isPresent()) {
            this.startEndDateTime = Optional.of(replacement.getStartEndDateTime().get());
        } else {
            this.startEndDateTime = Optional.empty();
        }
        this.setTags(replacement.getTags());
    }

    @Override
    public boolean equals(Object other) {
        return other == this // short circuit if same object
                || (other instanceof ReadOnlyTask // instanceof handles nulls
                && this.isSameStateAs((ReadOnlyTask) other));
    }

    @Override
    public int hashCode() {
        // use this method for custom fields hashing instead of implementing your own
        return Objects.hash(name, tags);
    }

    @Override
    public String toString() {
        return getAsText();
    }

}

@@ -1404,32 +1404,57 @@
 rn name;%0A    %7D%0A%0A
+    //@@author A0140023E%0A
     @Override%0A  
@@ -2183,32 +2183,47 @@
 teTime);%0A    %7D%0A%0A
+    //@@author%0A
     @Override%0A  
@@ -2480,32 +2480,57 @@
 cement);%0A    %7D%0A%0A
+    //@@author A0140023E%0A
     /**%0A     * U
@@ -2589,371 +2589,411 @@
 ent%7D
-.%0A     */%0A    public void resetData(ReadOnlyTask replacement) %7B%0A        assert replacement != null;%0A%0A        this.setName(replacement.getName());%0A        // TODO to use or not to use a new Optional to wrap the Deadline%0A        // replacement Deadline is currently reused%0A        if (replacement.getDeadline().isPresent()) %7B%0A            this.deadline = Optional.of
+ using a %22shallow copy%22 of the data. Refer to%0A     * %7B@link Object#clone()%7D for more information about shallow copy.%0A     */%0A    public void resetData(ReadOnlyTask replacement) %7B%0A        assert replacement != null;%0A%0A        // Note that we are shallow copying data replacement's data so replacement should not be%0A        // reused anymore. Otherwise modify this method to do a deep copy%0A%0A        setName
 (rep
@@ -3008,35 +3008,26 @@
 .get
-Deadline().get
+Name
 ());%0A
+%0A
         
 %7D el
@@ -3026,292 +3026,285 @@
     
-%7D else %7B%0A            this.deadline = Optional.empty();%0A        %7D%0A        // TODO to use or not to use a new Optional to wrap the startEndDateTime%0A        // replacement startEndDateTime is currently reused%0A        if (replacement.getStartEndDateTime().isPresent()) %7B%0A            this.
+// Note that we are reusing the same Optional from replacement directly%0A        // Hence we are not using the setter method which only accepts Deadline%0A        deadline = replacement.getDeadline();%0A        // Similarly for startEndDateTime we are reusing same Optional%0A        
 star
@@ -3318,28 +3318,16 @@
 eTime = 
-Optional.of(
 replacem
@@ -3355,111 +3355,19 @@
 me()
-.get());%0A        %7D else %7B%0A            this.startEndDateTime = Optional.empty();%0A        %7D%0A        this.
+;%0A%0A        
 setT
@@ -3393,32 +3393,47 @@
 Tags());%0A    %7D%0A%0A
+    //@@author%0A
     @Override%0A  

Make resetData a shallow copy in Task