package seedu.doist.model.task;

import static seedu.doist.commons.core.Messages.MESSAGE_INVALID_DATES;

import java.util.Date;
import java.util.List;
import java.util.Objects;

import com.joestelmach.natty.DateGroup;

import seedu.doist.commons.exceptions.IllegalValueException;

//@@author A0147620L
public class TaskDate {

    private Date startDate;
    private Date endDate;

    public TaskDate() {
        this.startDate = null;
        this.endDate = null;
    }

    public TaskDate (Date startDate, Date endDate) {
        this.startDate = startDate;
        this.endDate = endDate;
    }
    public Date getStartDate() {
        return startDate;
    }

    public void setStartDate(Date startDate) {
        this.startDate = startDate;
    }

    public Date getEndDate() {
        return endDate;
    }

    public void setEndDate(Date endDate) {
        this.endDate = endDate;
    }

    public boolean isPast() {
        if (this.getStartDate() != null && this.getEndDate() != null) {
            Date currentDate = new Date();
            return (this.getEndDate().compareTo(currentDate) < 0);
        } else {
            return false;
        }
    }

    public boolean isFloating() {
        return this.getStartDate() == null || this.getEndDate() == null;
    }

    public boolean isDeadline() {
        // Both not null
        if (!isFloating()) {
            return this.getStartDate().equals(this.getEndDate());
        } else {
            return false;
        }
    }

    public boolean isEvent() {
        return !isDeadline() && !isFloating();
    }

    /**
     * Function to check whether the date input is valid i.e, the Start date is before or equal to the End Date.
     * Also checks if the parsing of dates has been successful
     * @param startDate
     * @param endDate
     * @return
     * @throws IllegalValueException
     */
    public static boolean validateDate (Date startDate, Date endDate) throws IllegalValueException {
        if (startDate == null || endDate == null) {
            throw new IllegalValueException(MESSAGE_INVALID_DATES);
        } else {
            return (startDate.compareTo(endDate) <= 0) ? true : false;
        }
    }

    /**
     * Function to support natural language input for date and time, using a 3rd party library 'Natty'
     * @param date
     * @return extracted Date if parsing is successful, or null if it fails
     */
    public static Date parseDate (String date) {
        com.joestelmach.natty.Parser parser = new com.joestelmach.natty.Parser();
        List<DateGroup> groups = parser.parse(date);
        Date extractDate = null;
        boolean flag = false;
        for (DateGroup group:groups) {
            List<Date> dates = group.getDates();
            if (!dates.isEmpty()) {
                extractDate = dates.get(0);
                flag = true;
            }
        }
        return (flag ? extractDate : null);
    }

    @Override
    public String toString() {
        if (this.startDate != null && this.endDate != null) {
            return this.startDate.toString() + "--" + this.endDate.toString();
        } else {
            return "No dates";
        }
    }

    @Override
    public boolean equals(Object other) {
        return other == this // short circuit if same object
                || (other instanceof TaskDate // instanceof handles nulls
                && this.startDate == ((TaskDate) other).startDate // state check
                && this.endDate == ((TaskDate) other).endDate);
    }

    @Override
    public int hashCode() {
        return Objects.hash(startDate, endDate);
    }

    /**
     * Method that returns 1 if the parameter lies within this tasks dates,
     * or there is some overlap i.e, the task's startDate > parameter's startDate
     * or the task's endDate < parameter's endDate
     * @param dates
     * @return 1 if overlapping dates, else 0
     */
    public int compareTo(TaskDate dates) {
        if (this.startDate.compareTo(dates.getStartDate()) >= 0) {
            return 1;
        } else if (this.endDate.compareTo(dates.getEndDate()) <= 0) {
            return 1;
        } else {
            return 0;
        }
    }
}

@@ -3665,19 +3665,22 @@
 f th
-e parameter
+is tasks dates
  lie
@@ -3690,30 +3690,27 @@
 ithin th
-is tasks dates
+e parameter
 ,%0A     *
@@ -3744,20 +3744,25 @@
 .e, the 
-task
+parameter
 's start
@@ -3770,19 +3770,14 @@
 ate 
-%3E parameter
+%3C task
 's s
@@ -3799,20 +3799,25 @@
  or the 
-task
+parameter
 's endDa
@@ -3823,19 +3823,14 @@
 ate 
-%3C parameter
+%3E task
 's e
@@ -3969,57 +3969,324 @@
 if (
-this.startDate.compareTo(dates.getStartDate()) %3E=
+dates == null %7C%7C dates.getStartDate() == null %7C%7C%0A                dates.getEndDate() == null %7C%7C this.startDate == null%0A                %7C%7C this.endDate == null) %7B%0A            return 0;%0A        %7D else if (this.startDate.compareTo(dates.getStartDate()) %3C 0 &&%0A                this.endDate.compareTo(dates.getEndDate()) %3C
  0) 
@@ -4298,33 +4298,33 @@
          return 
-1
+0
 ;%0A        %7D else
@@ -4324,24 +4324,94 @@
  %7D else if (
+this.startDate.compareTo(dates.getStartDate()) %3E 0 &&%0A                
 this.endDate
@@ -4441,18 +4441,17 @@
 Date()) 
-%3C=
+%3E
  0) %7B%0A  
@@ -4467,17 +4467,17 @@
  return 
-1
+0
 ;%0A      
@@ -4498,33 +4498,33 @@
          return 
-0
+1
 ;%0A        %7D%0A    

Modify the compareTo function