package seedu.manager.model;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import seedu.manager.model.task.ReadOnlyTask;
import seedu.manager.model.task.Task;
import seedu.manager.model.task.Tag;
import seedu.manager.model.task.UniqueTaskList;
import seedu.manager.model.tag.UniqueTagList;
import seedu.manager.model.tag.UniqueTagList.DuplicateTagException;
import seedu.manager.model.tag.UniqueTagList.TagNotRemovedException;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Wraps all data at the task-manager level
 * Duplicates are not allowed (by .equals comparison)
 */
public class TaskManager implements ReadOnlyTaskManager {

    private final UniqueTaskList tasks;
    private final UniqueTagList tags;

    {
        tasks = new UniqueTaskList();
        tags = new UniqueTagList();
    }

    public TaskManager() {}

    /**
     * Tasks are copied into this taskmanager
     */
    public TaskManager(ReadOnlyTaskManager toBeCopied) {
        this(toBeCopied.getUniqueTaskList());
    }

    /**
     * Tasks are copied into this taskmanager
     */
    public TaskManager(UniqueTaskList tasks) {
        resetData(tasks.getInternalList());
    }

    public static ReadOnlyTaskManager getEmptyTaskManager() {
        return new TaskManager();
    }

//// list overwrite operations

    public ObservableList<Task> getTasks() {
        return tasks.getInternalList();
    }
    
    // @@author A0148042M
    public ObservableList<Tag> getTags() {
        ObservableList<Tag> internalTagList = tags.getInternalList();
        ObservableList<Tag> tagListFromTaskList = getTagsFromTaskList(this.getTasks());

//        try {
//            tags.mergeFrom(new UniqueTagList(tagListFromTaskList));
//        } catch (DuplicateTagException e) {
//            e.printStackTrace();
//        }
        
        return combineTwoList(internalTagList, tagListFromTaskList);
    }
    
    public ObservableList<Tag> combineTwoList(ObservableList<Tag> internalTagList, 
            ObservableList<Tag> tagListFromTaskList) {
        ObservableList<Tag> combinedTagList = internalTagList;
        
        if(internalTagList.size() == 0) {
            for(int i = 0;i < tagListFromTaskList.size();i++) {
                if(!internalTagList.contains(tagListFromTaskList.get(i))) {
//                    internalTagList.add(tagListFromTaskList.get(i));
                    combinedTagList.add(tagListFromTaskList.get(i));
                }
            }
        } 
        
        return combinedTagList;
    }
    
    public ObservableList<Tag> getTagsFromTaskList(ObservableList<Task> taskList) {
        ObservableList<Tag> tagList = FXCollections.observableArrayList();
        for(int i = 0;i < taskList.size();i++) {
            if(taskList.get(i).getTag().isPresent()) {
                Tag tag = (Tag) taskList.get(i).getTag().get();
                if(!tagList.contains(tag)) {
                    tagList.add(tag);
                }
            }
        }
        return tagList;
    }

    // @@author
    public void setTasks(List<Task> tasks) {
        this.tasks.getInternalList().setAll(tasks);
    }

    public void resetData(Collection<? extends ReadOnlyTask> newTasks)  {
        setTasks(newTasks.stream().map(Task::new).collect(Collectors.toList()));
    }

    public void resetData(ReadOnlyTaskManager newData) {
        resetData(newData.getTaskList());
    }

//// task-level operations

    /**
     * Adds a task to the task manager.
     *
     * @throws UniqueTaskList.DuplicateTaskException if an equivalent task already exists.
     */
    public void addTask(Task p) throws UniqueTaskList.DuplicateTaskException {
        tasks.add(p);
    }
    
    /**
     * @@author A0148042M
     * Add a tag to the task manager.
     *
     * @throws UniqueTagList.DuplicateTagException if an equivalent tag already exists.
     */
    public void addTag(Tag tag) throws UniqueTagList.DuplicateTagException {
        tags.add(tag);
    }
    
    // @@author
    public boolean removeTask(ReadOnlyTask key) throws UniqueTaskList.TaskNotFoundException {
        if (tasks.remove(key)) {
            return true;
        } else {
            throw new UniqueTaskList.TaskNotFoundException();
        }
    }
    
    public void removeTag(Tag tag) {
//        int count = 0;
//        ObservableList<Task> taskList = tasks.getInternalList();
//        for(int i = 0;i < tasks.getSize();i++) {
//            if(taskList.get(i).getTag().isPresent()) {
//                if(((Tag) taskList.get(i).getTag().get()).equals(tag)) {
//                    count++;
//                }
//            }
//        }
//        
//        if(count == 1) {
//            tags.remove(tag);
//        }
        try {
            tags.remove(tag);
        } catch (TagNotRemovedException e) {
            e.printStackTrace();
        }
    }

//// util methods

    @Override
    public String toString() {
        return tasks.getInternalList().size() + " tasks";
        // TODO: refine later
    }

    @Override
    public List<ReadOnlyTask> getTaskList() {
        return Collections.unmodifiableList(tasks.getInternalList());
    }

    @Override
    public UniqueTaskList getUniqueTaskList() {
        return this.tasks;
    }


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

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

@@ -4315,26 +4315,24 @@
 (Tag tag) %7B%0A
-//
         int 
@@ -4342,18 +4342,16 @@
 nt = 0;%0A
-//
         
@@ -4403,26 +4403,24 @@
 rnalList();%0A
-//
         for(
@@ -4452,26 +4452,24 @@
 ze();i++) %7B%0A
-//
             
@@ -4507,26 +4507,24 @@
 resent()) %7B%0A
-//
             
@@ -4580,26 +4580,24 @@
 als(tag)) %7B%0A
-//
             
@@ -4613,18 +4613,16 @@
 ount++;%0A
-//
         
@@ -4623,34 +4623,32 @@
               %7D%0A
-//
             %7D%0A//
@@ -4637,34 +4637,32 @@
 %7D%0A            %7D%0A
-//
         %7D%0A//    
@@ -4655,18 +4655,16 @@
       %7D%0A
-//
         
@@ -4664,18 +4664,34 @@
        %0A
-//
+        try %7B%0A    
         
@@ -4706,15 +4706,15 @@
  == 
-1
+0
 ) %7B%0A
-//
+  
     
@@ -4713,32 +4713,34 @@
 %7B%0A              
+  
 tags.remove(tag)
@@ -4741,26 +4741,24 @@
 e(tag);%0A
-//
         
 %7D%0A      
@@ -4753,53 +4753,13 @@
     
-%7D%0A        try %7B%0A            tags.remove(tag);
+    %7D
 %0A   

fix the bug that the tag is deleted whenever a task is deleted.