package seedu.taskman.model.event;

import com.google.common.base.Objects;

import seedu.taskman.commons.exceptions.IllegalValueException;
import seedu.taskman.logic.parser.DateTimeParser;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Schedule {
    // UG/DG: specify new datetime format
    // todo: indicate in example that format: "month-date-year time". there MUST be a space before time, not colon
    public static final String MESSAGE_SCHEDULE_CONSTRAINTS =
            "Task schedule should only contain dates and times in the format: " +
                    // DATETIME to DATETIME
                    DateTimeParser.DESCRIPTION_DATE_TIME_SHORT + " (a \",\" or \"to\") " +
                    DateTimeParser.DESCRIPTION_DATE_TIME_SHORT +
                    // DATETIME for DURATION
                    "\nOr the format:\n" + DateTimeParser.DESCRIPTION_DATE_TIME_SHORT + " for " +
                    DateTimeParser.DESCRIPTION_DURATION +
                    "\nDATETIME: " + DateTimeParser.DESCRIPTION_DATE_TIME_FULL;

    public static final String ERROR_NEGATIVE_DURATION = "Duration is negative!";
    public static final String ERROR_BAD_START_DATETIME = "Bad start datetime";
    public static final String ERROR_BAD_END_DATETIME = "Bad end datetime";

    public static final String SCHEDULE_DIVIDER_GROUP = "((?:, )|(?: to )|(?: for ))";
    public static final String SCHEDULE_VALIDATION_REGEX =
            "(.*)" + SCHEDULE_DIVIDER_GROUP + "(.*)";

    public final long startEpochSecond;
    public final long endEpochSecond;

    public Schedule(long startEpochSecond, long endEpochSecond) throws IllegalValueException {

        boolean endIsBeforeStart = (endEpochSecond - startEpochSecond) < 0;
        if (startEpochSecond <= 0 || endEpochSecond <= 0 || endIsBeforeStart) {
            throw new IllegalValueException(ERROR_NEGATIVE_DURATION);
        }
        this.startEpochSecond = startEpochSecond;
        this.endEpochSecond = endEpochSecond;
    }

    public Schedule(String schedule) throws IllegalValueException {
        schedule = schedule.trim();
        Pattern pattern = Pattern.compile(SCHEDULE_VALIDATION_REGEX);
        Matcher matcher = pattern.matcher(schedule);
        if (!matcher.matches()) {
            throw new IllegalValueException(MESSAGE_SCHEDULE_CONSTRAINTS);
        } else {
            String start = matcher.group(1).trim();
            String divider = matcher.group(2).trim();
            boolean endingIsDuration = divider.contains("for");

            try {
                startEpochSecond = DateTimeParser.getUnixTime(start);
            } catch (DateTimeParser.IllegalDateTimeException e) {
                throw new IllegalValueException(
                        MESSAGE_SCHEDULE_CONSTRAINTS + "\n" +
                                ERROR_BAD_START_DATETIME + ", '" + start + "'");
            }

            if (endingIsDuration) {
                String duration = matcher.group(3).trim();
                endEpochSecond = DateTimeParser.naturalDurationToUnixTime(startEpochSecond, duration);
            } else {
                String endString = matcher.group(3).trim();
                long endEpochCandidate = DateTimeParser.getUnixTime(endString, ERROR_BAD_END_DATETIME);

                // user may have forgotten to type 'next' before the relative datetime
                // "sun 2359 to mon 2359" should be "... next mon 2359"
                endEpochSecond = (startEpochSecond > endEpochCandidate)
                        ? addNextToRelativeDateTime(endString)
                        : endEpochCandidate;
            }

            if (startEpochSecond > endEpochSecond) {
                throw new IllegalValueException(ERROR_NEGATIVE_DURATION);
            }
        }
    }

    private long addNextToRelativeDateTime(String dateTime) throws IllegalValueException {
        dateTime = "next " + dateTime;
        return DateTimeParser.getUnixTime(dateTime, ERROR_BAD_END_DATETIME);
    }

    public static boolean isValidSchedule(String test) {
        try {
            new Schedule(test);
            return true;
        } catch (IllegalValueException e) {
            return false;
        }
    }

    @Override
    public String toString() {
        return DateTimeParser.epochSecondToShortDateTime(startEpochSecond) +
                " to\n" +
                DateTimeParser.epochSecondToDetailedDateTime(endEpochSecond);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Schedule schedule = (Schedule) o;
        return startEpochSecond == schedule.startEpochSecond &&
                endEpochSecond == schedule.endEpochSecond;
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(startEpochSecond, endEpochSecond);
    }

}

@@ -69,16 +69,58 @@
 jects;%0A%0A
+import org.ocpsoft.prettytime.PrettyTime;%0A
 import s
@@ -225,16 +225,38 @@
 arser;%0A%0A
+import java.sql.Date;%0A
 import j
@@ -1574,73 +1574,207 @@
 lic 
-final long startEpochSecond;%0A    public final long endEpochSecond
+static final int MULTIPLIER_TIME_UNIX_TO_JAVA = 1000;%0A    public final long startEpochSecond;%0A    public final long endEpochSecond;%0A%0A    public final PrettyTime prettyTimeFormatter = new PrettyTime()
 ;%0A%0A 
@@ -4461,32 +4461,35 @@
 ring() %7B%0A       
+ /*
  return DateTime
@@ -4637,32 +4637,295 @@
 endEpochSecond);
+ */%0A        return String.format(%0A                prettyTimeFormatter.format(new Date(startEpochSecond * MULTIPLIER_TIME_UNIX_TO_JAVA)),%0A                %22 to%5Cn%22,%0A                prettyTimeFormatter.format(new Date(endEpochSecond * MULTIPLIER_TIME_UNIX_TO_JAVA)));
 %0A    %7D%0A%0A    @Ove

Add pretty time formatting to Schedule field