<commit_before>//@@author A0139925U
package seedu.tache.logic.commands;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

import seedu.tache.commons.core.EventsCenter;
import seedu.tache.commons.core.Messages;
import seedu.tache.commons.events.ui.JumpToListRequestEvent;
import seedu.tache.commons.exceptions.IllegalValueException;
import seedu.tache.commons.util.CollectionUtil;
import seedu.tache.logic.commands.exceptions.CommandException;
import seedu.tache.model.tag.UniqueTagList;
import seedu.tache.model.task.DateTime;
import seedu.tache.model.task.Name;
import seedu.tache.model.task.ReadOnlyTask;
import seedu.tache.model.task.Task;
import seedu.tache.model.task.Task.RecurInterval;
import seedu.tache.model.task.UniqueTaskList;
import seedu.tache.model.task.UniqueTaskList.DuplicateTaskException;

/**
 * Edits the details of an existing task in the task manager.
 */
public class EditCommand extends Command implements Undoable {

    public static final String COMMAND_WORD = "edit";
    public static final String SHORT_COMMAND_WORD = "e";

    public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the task identified "
            + "by the index number used in the last tasks listing. "
            + "Existing values will be overwritten by the input values.\n"
            + "Parameters: INDEX (must be a positive integer); <parameter1> <new_value1>;"
            + "<parameter2> <new_value2>...\n"
            + "Example: " + COMMAND_WORD + " 1; start_date 10/11/2017; start_time 3.30pm;"
            + "Or alternatively you can use the following format\n"
            + "Parameters: INDEX (must be a positive integer) change <parameter1> to <new_value1> and "
            + "<parameter2> to <new_value2>...\n"
            + "Example: " + COMMAND_WORD + " 1 change startdate to 10/11/2017 and change starttime to 3.30pm;";

    public static final String MESSAGE_EDIT_TASK_SUCCESS = "Edited Task: %1$s";
    public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
    public static final String MESSAGE_DUPLICATE_TASK = "This task already exists in the task manager.";
    public static final String MESSAGE_INVALID_DATE_RANGE = "Start date can not be before end date";
    public static final String MESSAGE_PART_OF_RECURRING_TASK =
                        "This task is part of a recurring task and cannot be edited.";

    private final int filteredTaskListIndex;
    private final EditTaskDescriptor editTaskDescriptor;

    private boolean commandSuccess;
    private ReadOnlyTask taskToEdit;
    private ReadOnlyTask originalTask;

    /**
     * @param filteredTaskListIndex the index of the task in the filtered task list to edit
     * @param editTaskDescriptor details to edit the task with
     */
    public EditCommand(int filteredTaskListIndex, EditTaskDescriptor editTaskDescriptor) {
        assert filteredTaskListIndex > 0;
        assert editTaskDescriptor != null;

        // converts filteredTaskListIndex from one-based to zero-based.
        this.filteredTaskListIndex = filteredTaskListIndex - 1;

        this.editTaskDescriptor = new EditTaskDescriptor(editTaskDescriptor);
        commandSuccess = false;
    }

    @Override
    public CommandResult execute() throws CommandException {
        List<ReadOnlyTask> lastShownList = model.getFilteredTaskList();

        if (filteredTaskListIndex >= lastShownList.size()) {
            throw new CommandException(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX);
        }

        taskToEdit = lastShownList.get(filteredTaskListIndex);
        cloneOriginalTask(taskToEdit);
        Task editedTask;
        try {
            checkPartOfRecurringTask(taskToEdit);
            editedTask = createEditedTask(taskToEdit, editTaskDescriptor);
            try {
                model.updateTask(taskToEdit, editedTask);
            } catch (UniqueTaskList.DuplicateTaskException dpe) {
                throw new CommandException(MESSAGE_DUPLICATE_TASK);
            }
            model.updateCurrentFilteredList();
            commandSuccess = true;
            undoHistory.push(this);
            EventsCenter.getInstance().post(new JumpToListRequestEvent(model.getFilteredTaskListIndex(taskToEdit)));
            return new CommandResult(String.format(MESSAGE_EDIT_TASK_SUCCESS, taskToEdit));
        } catch (IllegalValueException e) {
            return new IncorrectCommand(e.getMessage()).execute();
        }
    }

    /**
     * Creates and returns a {@code Task} with the details of {@code taskToEdit}
     * edited with {@code editTaskDescriptor}.
     * @throws IllegalValueException if date or time could not be parsed
     */
    private static Task createEditedTask(ReadOnlyTask taskToEdit,
                                             EditTaskDescriptor editTaskDescriptor) throws IllegalValueException {
        assert taskToEdit != null;

        Name updatedName = editTaskDescriptor.getName().orElseGet(taskToEdit::getName);
        Optional<DateTime> updatedStartDateTime;
        Optional<DateTime> updatedEndDateTime;
        if (taskToEdit.getStartDateTime().isPresent()) {
            updatedStartDateTime = Optional.of(new DateTime(taskToEdit.getStartDateTime().get()));
        } else {
            updatedStartDateTime = Optional.empty();
        }
        if (taskToEdit.getEndDateTime().isPresent()) {
            updatedEndDateTime = Optional.of(new DateTime(taskToEdit.getEndDateTime().get()));
        } else {
            updatedEndDateTime = Optional.empty();
        }
        if (editTaskDescriptor.getStartDate().isPresent()) {
            if (updatedStartDateTime.isPresent()) {
                updatedStartDateTime.get().setDateOnly(editTaskDescriptor.getStartDate().get());
            } else {
                updatedStartDateTime = Optional.of(new DateTime(editTaskDescriptor.getStartDate().get()));
                updatedStartDateTime.get().setDefaultTime();
            }
            if (!updatedEndDateTime.isPresent() && !editTaskDescriptor.getEndDate().isPresent()) {
                //Floating Task to Non-Floating, do not allow start date only
                updatedEndDateTime = Optional.of(new DateTime(editTaskDescriptor.getStartDate().get()));
                updatedEndDateTime.get().setDefaultTime();
            }
        }
        if (editTaskDescriptor.getEndDate().isPresent()) {
            if (updatedEndDateTime.isPresent()) {
                updatedEndDateTime.get().setDateOnly(editTaskDescriptor.getEndDate().get());
            } else {
                updatedEndDateTime = Optional.of(new DateTime(editTaskDescriptor.getEndDate().get()));
                updatedEndDateTime.get().setDefaultTime();
            }
        }
        if (editTaskDescriptor.getStartTime().isPresent()) {
            if (updatedStartDateTime.isPresent()) {
                updatedStartDateTime.get().setTimeOnly(editTaskDescriptor.getStartTime().get());
            } else {
                updatedStartDateTime = Optional.of(new DateTime(editTaskDescriptor.getStartTime().get()));
            }
        }
        if (editTaskDescriptor.getEndTime().isPresent()) {
            if (updatedEndDateTime.isPresent()) {
                updatedEndDateTime.get().setTimeOnly(editTaskDescriptor.getEndTime().get());
            } else {
                updatedEndDateTime = Optional.of(new DateTime(editTaskDescriptor.getEndTime().get()));
            }
        }
        boolean isTimed;
        if (updatedStartDateTime.isPresent() || updatedEndDateTime.isPresent()) {
            isTimed = true;
        } else {
            isTimed = false;
        }
        UniqueTagList updatedTags = editTaskDescriptor.getTags().orElseGet(taskToEdit::getTags);
        if (updatedStartDateTime.isPresent() && updatedEndDateTime.isPresent()) {
            if (updatedStartDateTime.get().compareTo(updatedEndDateTime.get()) == 1) {
                throw new IllegalValueException(MESSAGE_INVALID_DATE_RANGE);
            }
        }
        return new Task(updatedName, updatedStartDateTime, updatedEndDateTime,
                            updatedTags, isTimed, true, false, RecurInterval.NONE, new ArrayList<Date>());

    }

    /**
     * Stores the details to edit the task with. Each non-empty field value will replace the
     * corresponding field value of the task.
     */
    public static class EditTaskDescriptor {
        private Optional<Name> name = Optional.empty();
        private Optional<String> startDate = Optional.empty();
        private Optional<String> endDate = Optional.empty();
        private Optional<String> startTime = Optional.empty();
        private Optional<String> endTime = Optional.empty();
        private Optional<UniqueTagList> tags = Optional.empty();

        public EditTaskDescriptor() {}

        public EditTaskDescriptor(EditTaskDescriptor toCopy) {
            this.name = toCopy.getName();<commit_msg>Code cleanup + resolve issue #202<commit_after>//@@author A0139925U
package seedu.tache.logic.commands;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

import seedu.tache.commons.core.EventsCenter;
import seedu.tache.commons.core.Messages;
import seedu.tache.commons.events.ui.JumpToListRequestEvent;
import seedu.tache.commons.exceptions.IllegalValueException;
import seedu.tache.commons.util.CollectionUtil;
import seedu.tache.logic.commands.exceptions.CommandException;
import seedu.tache.model.tag.UniqueTagList;
import seedu.tache.model.task.DateTime;
import seedu.tache.model.task.Name;
import seedu.tache.model.task.ReadOnlyTask;
import seedu.tache.model.task.Task;
import seedu.tache.model.task.Task.RecurInterval;
import seedu.tache.model.task.UniqueTaskList;
import seedu.tache.model.task.UniqueTaskList.DuplicateTaskException;

/**
 * Edits the details of an existing task in the task manager.
 */
public class EditCommand extends Command implements Undoable {

    public static final String COMMAND_WORD = "edit";
    public static final String SHORT_COMMAND_WORD = "e";

    public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the task identified "
            + "by the index number used in the last tasks listing. "
            + "Existing values will be overwritten by the input values.\n"
            + "Parameters: INDEX (must be a positive integer); <parameter1> <new_value1>;"
            + "<parameter2> <new_value2>...\n"
            + "Example: " + COMMAND_WORD + " 1; start_date 10/11/2017; start_time 3.30pm;"
            + "Or alternatively you can use the following format\n"
            + "Parameters: INDEX (must be a positive integer) change <parameter1> to <new_value1> and "
            + "<parameter2> to <new_value2>...\n"
            + "Example: " + COMMAND_WORD + " 1 change startdate to 10/11/2017 and change starttime to 3.30pm;";

    public static final String MESSAGE_EDIT_TASK_SUCCESS = "Edited Task: %1$s";
    public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
    public static final String MESSAGE_DUPLICATE_TASK = "This task already exists in the task manager.";
    public static final String MESSAGE_INVALID_DATE_RANGE = "Start date can not be before end date";
    public static final String MESSAGE_PART_OF_RECURRING_TASK =
                        "This task is part of a recurring task and cannot be edited.";

    public static final String SPECIAL_CASE_TIME_STRING = "23:59:59";

    private final int filteredTaskListIndex;
    private final EditTaskDescriptor editTaskDescriptor;

    private boolean commandSuccess;
    private ReadOnlyTask taskToEdit;
    private ReadOnlyTask originalTask;

    /**
     * @param filteredTaskListIndex the index of the task in the filtered task list to edit
     * @param editTaskDescriptor details to edit the task with
     */
    public EditCommand(int filteredTaskListIndex, EditTaskDescriptor editTaskDescriptor) {
        assert filteredTaskListIndex > 0;
        assert editTaskDescriptor != null;

        // converts filteredTaskListIndex from one-based to zero-based.
        this.filteredTaskListIndex = filteredTaskListIndex - 1;

        this.editTaskDescriptor = new EditTaskDescriptor(editTaskDescriptor);
        commandSuccess = false;
    }

    @Override
    public CommandResult execute() throws CommandException {
        List<ReadOnlyTask> lastShownList = model.getFilteredTaskList();

        if (filteredTaskListIndex >= lastShownList.size()) {
            throw new CommandException(Messages.MESSAGE_INVALID_TASK_DISPLAYED_INDEX);
        }

        taskToEdit = lastShownList.get(filteredTaskListIndex);
        cloneOriginalTask(taskToEdit);
        Task editedTask;
        try {
            checkPartOfRecurringTask(taskToEdit);
            editedTask = createEditedTask(taskToEdit, editTaskDescriptor);
            try {
                model.updateTask(taskToEdit, editedTask);
            } catch (UniqueTaskList.DuplicateTaskException dpe) {
                throw new CommandException(MESSAGE_DUPLICATE_TASK);
            }
            model.updateCurrentFilteredList();
            commandSuccess = true;
            undoHistory.push(this);
            EventsCenter.getInstance().post(new JumpToListRequestEvent(model.getFilteredTaskListIndex(taskToEdit)));
            return new CommandResult(String.format(MESSAGE_EDIT_TASK_SUCCESS, taskToEdit));
        } catch (IllegalValueException e) {
            return new IncorrectCommand(e.getMessage()).execute();
        }
    }

    /**
     * Creates and returns a {@code Task} with the details of {@code taskToEdit}
     * edited with {@code editTaskDescriptor}.
     * @throws IllegalValueException if date or time could not be parsed
     */
    private static Task createEditedTask(ReadOnlyTask taskToEdit,
                                             EditTaskDescriptor editTaskDescriptor) throws IllegalValueException {
        assert taskToEdit != null;

        Name updatedName = editTaskDescriptor.getName().orElseGet(taskToEdit::getName);
        Optional<DateTime> updatedStartDateTime;
        Optional<DateTime> updatedEndDateTime;
        if (taskToEdit.getStartDateTime().isPresent()) {
            updatedStartDateTime = Optional.of(new DateTime(taskToEdit.getStartDateTime().get()));
        } else {
            updatedStartDateTime = Optional.empty();
        }
        if (taskToEdit.getEndDateTime().isPresent()) {
            updatedEndDateTime = Optional.of(new DateTime(taskToEdit.getEndDateTime().get()));
        } else {
            updatedEndDateTime = Optional.empty();
        }
        if (editTaskDescriptor.getStartDate().isPresent()) {
            if (updatedStartDateTime.isPresent()) {
                updatedStartDateTime.get().setDateOnly(editTaskDescriptor.getStartDate().get());
            } else {
                updatedStartDateTime = Optional.of(new DateTime(editTaskDescriptor.getStartDate().get()));
                updatedStartDateTime.get().setDefaultTime();
            }
            if (!updatedEndDateTime.isPresent() && !editTaskDescriptor.getEndDate().isPresent()) {
                //Floating Task to Non-Floating, do not allow start date only
                updatedEndDateTime = Optional.of(new DateTime(editTaskDescriptor.getStartDate().get()));
                updatedEndDateTime.get().setDefaultTime();
            }
        }
        if (editTaskDescriptor.getEndDate().isPresent()) {
            if (updatedEndDateTime.isPresent()) {
                updatedEndDateTime.get().setDateOnly(editTaskDescriptor.getEndDate().get());
            } else {
                updatedEndDateTime = Optional.of(new DateTime(editTaskDescriptor.getEndDate().get()));
                updatedEndDateTime.get().setDefaultTime();
            }
        }
        if (editTaskDescriptor.getStartTime().isPresent()) {
            if (updatedStartDateTime.isPresent()) {
                updatedStartDateTime.get().setTimeOnly(editTaskDescriptor.getStartTime().get());
            } else {
                updatedStartDateTime = Optional.of(new DateTime(editTaskDescriptor.getStartTime().get()));
            }
        }
        if (editTaskDescriptor.getEndTime().isPresent()) {
            if (updatedEndDateTime.isPresent()) {
                updatedEndDateTime.get().setTimeOnly(editTaskDescriptor.getEndTime().get());
            } else {
                updatedEndDateTime = Optional.of(new DateTime(editTaskDescriptor.getEndTime().get()));
            }
        }
        boolean isTimed;
        if (updatedStartDateTime.isPresent() || updatedEndDateTime.isPresent()) {
            isTimed = true;
        } else {
            isTimed = false;
        }
        UniqueTagList updatedTags = editTaskDescriptor.getTags().orElseGet(taskToEdit::getTags);

        checkValidDateRange(updatedStartDateTime, updatedEndDateTime);
        checkSpecialCase(editTaskDescriptor, updatedEndDateTime);

        return new Task(updatedName, updatedStartDateTime, updatedEndDateTime,
                            updatedTags, isTimed, true, false, RecurInterval.NONE, new ArrayList<Date>());

    }

    private static void checkValidDateRange(Optional<DateTime> updatedStartDateTime,
                                                Optional<DateTime> updatedEndDateTime) throws IllegalValueException {
        if (updatedStartDateTime.isPresent() && updatedEndDateTime.isPresent()) {
            if (updatedStartDateTime.get().compareTo(updatedEndDateTime.get()) == 1) {
                throw new IllegalValueException(MESSAGE_INVALID_DATE_RANGE);
            }
        }
    }

    private static void checkSpecialCase(EditTaskDescriptor editTaskDescriptor,
                            Optional<DateTime> updatedEndDateTime) throws IllegalValueException {
        //Special case End Date -> Today will result in a default timing of 2359 instead of 0000
        if (editTaskDescriptor.getEndDate().isPresent() && updatedEndDateTime.isPresent()
                && !editTaskDescriptor.getEndTime().isPresent()) {
            if ((new DateTime(editTaskDescriptor.getEndDate().get()).isToday())
                        && updatedEndDateTime.get().getDate().before(new Date())) {
                updatedEndDateTime.get().setTimeOnly(SPECIAL_CASE_TIME_STRING);
            }
        }
    }

    /**
     * Stores the details to edit the task with. Each non-empty field value will replace the
     * corresponding field value of the task.
     */
    public static class EditTaskDescriptor {
        private Optional<Name> name = Optional.empty();
        private Optional<String> startDate = Optional.empty();
        private Optional<String> endDate = Optional.empty();
        private Optional<String> startTime = Optional.empty();
        private Optional<String> endTime = Optional.empty();
        private Optional<UniqueTagList> tags = Optional.empty();

        public EditTaskDescriptor() {}

        public EditTaskDescriptor(EditTaskDescriptor toCopy) {
            this.name = toCopy.getName();
{'fraction_non_alphanumeric': 0.09373202990224266, 'fraction_numerical': 0.0053844947461968735, 'mean_word_length': 2.83213141025641, 'pattern_counts': {'":': 2, '<': 42, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2493414', 'n_tokens_mistral': 4978, 'n_tokens_neox': 4805, 'n_words': 1139}