package seedu.task.model.task;

import java.util.Iterator;
import java.util.List;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.SortedList;

import seedu.task.commons.core.UnmodifiableObservableList;
import seedu.task.commons.exceptions.DuplicateDataException;
import seedu.task.commons.util.CollectionUtil;

/**
 * A list of tasks that enforces uniqueness between its elements and does not allow nulls.
 *
 * Supports a minimal set of list operations.
 *
 * @see Task#equals(Object)
 * @see CollectionUtil#elementsAreUnique(Collection)
 */
public class UniqueTaskList implements Iterable<Task> {

    private final SortedList<Task> internalList = new SortedList<Task>(FXCollections.observableArrayList(), Task.TaskComparator);

    /**
     * Returns true if the list contains an equivalent task as the given argument.
     */
    public boolean contains(ReadOnlyTask toCheck) {
        assert toCheck != null;
        return internalList.contains(toCheck);
    }

    /**
     * Adds a task to the list.
     *
     * @throws DuplicateTaskException if the task to add is a duplicate of an existing task in the list.
     */
    public void add(Task toAdd) throws DuplicateTaskException {
        assert toAdd != null;
        if (contains(toAdd)) {
            throw new DuplicateTaskException();
        }
        internalList.add(toAdd);
    }

    /**
     * Updates the task in the list at position {@code index} with {@code editedPerson}.
     *
     * @throws DuplicateTaskException if updating the task's details causes the task to be equivalent to
     *      another existing task in the list.
     * @throws IndexOutOfBoundsException if {@code index} < 0 or >= the size of the list.
     */
    public void updateTask(int index, ReadOnlyTask editedTask) throws DuplicateTaskException {
        assert editedTask != null;

        Task taskToUpdate = internalList.get(index);
        if (!taskToUpdate.equals(editedTask) && internalList.contains(editedTask)) {
            throw new DuplicateTaskException();
        }

        taskToUpdate.resetData(editedTask);
        // TODO: The code below is just a workaround to notify observers of the updated task.
        // The right way is to implement observable properties in the Task class.
        // Then, PersonCard should then bind its text labels to those observable properties.
        internalList.set(index, taskToUpdate);
    }

    /**
     * Removes the equivalent task from the list.
     *
     * @throws TaskNotFoundException if no such task could be found in the list.
     */
    public boolean remove(ReadOnlyTask toRemove) throws TaskNotFoundException {
        assert toRemove != null;
        final boolean taskFoundAndDeleted = internalList.remove(toRemove);
        if (!taskFoundAndDeleted) {
            throw new TaskNotFoundException();
        }
        return taskFoundAndDeleted;
    }

    public void setTasks(UniqueTaskList replacement) {
        this.internalList.setAll(replacement.internalList);
    }

    public void setTasks(List<? extends ReadOnlyTask> tasks) throws DuplicateTaskException {
        final UniqueTaskList replacement = new UniqueTaskList();
        for (final ReadOnlyTask task : tasks) {
            replacement.add(new Task(task));
        }
        setTasks(replacement);
    }

    public UnmodifiableObservableList<Task> asObservableList() {
        return new UnmodifiableObservableList<>(internalList);
    }

    @Override
    public Iterator<Task> iterator() {
        return internalList.iterator();
    }

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

    @Override
    public int hashCode() {
        return internalList.hashCode();
    }

    /**
     * Signals that an operation would have violated the 'no duplicates' property of the list.
     */
    public static class DuplicateTaskException extends DuplicateDataException {
        protected DuplicateTaskException() {
            super("Operation would result in duplicate tasks");
        }
    }

    /**
     * Signals that an operation targeting a specified task in the list would fail because
     * there is no such matching task in the list.
     */
    public static class TaskNotFoundException extends Exception {}



}

@@ -25,16 +25,45 @@
 .task;%0A%0A
+import java.util.Collection;%0A
 import j
@@ -192,62 +192,8 @@
 st;%0A
-import javafx.collections.transformation.SortedList;%0A%0A
 impo
@@ -437,16 +437,19 @@
 does not
+%0A *
  allow n
@@ -651,16 +651,19 @@
 %3E %7B%0A%0A   
+ //
  private
@@ -704,16 +704,23 @@
 st = new
+%0A    //
  SortedL
@@ -765,16 +765,23 @@
 yList(),
+%0A    //
  Task.Ta
@@ -794,16 +794,107 @@
 arator);
+%0A    private final ObservableList%3CTask%3E internalList = FXCollections.observableArrayList();
 %0A%0A    /*
@@ -967,16 +967,23 @@
 he given
+%0A     *
  argumen
@@ -1211,24 +1211,43 @@
 askException
+%0A     *            
  if the task
@@ -1287,32 +1287,51 @@
 ting task in the
+%0A     *            
  list.%0A     */%0A 
@@ -1626,16 +1626,23 @@
 ex%7D with
+%0A     *
  %7B@code 
@@ -1696,24 +1696,43 @@
 askException
+%0A     *            
  if updating
@@ -1772,16 +1772,35 @@
 sk to be
+%0A     *            
  equival
@@ -1805,28 +1805,16 @@
 alent to
-%0A     *     
  another
@@ -1877,24 +1877,43 @@
 ndsException
+%0A     *            
  if %7B@code i
@@ -2409,16 +2409,27 @@
 s of the
+%0A        //
  updated
@@ -2509,16 +2509,27 @@
 the Task
+%0A        //
  class.%0A
@@ -2600,32 +2600,43 @@
 those observable
+%0A        //
  properties.%0A   
@@ -2787,16 +2787,35 @@
 xception
+%0A     *            
  if no s
@@ -4052,16 +4052,24 @@
         
+        
 && this.
@@ -4088,33 +4088,16 @@
 .equals(
-%0A                
 ((Unique
@@ -4305,16 +4305,23 @@
 licates'
+%0A     *
  propert
@@ -4634,16 +4634,23 @@
 st would
+%0A     *
  fail be
@@ -4654,23 +4654,16 @@
  because
-%0A     *
  there i
@@ -4772,15 +4772,18 @@
 eption %7B
-%7D%0A%0A
+%0A    %7D
 %0A%0A%7D%0A

stop using sorted list for now