package seedu.todo.commons.util;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.TextStyle;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.Locale;

/**
 * A utility class for Dates and LocalDateTimes
 */
public class DateUtil {

    private static final String FROM_NOW = "later";
    private static final String TILL_NOW = "ago";
    private static final String TODAY = "Today";
    private static final String TOMORROW = "Tomorrow";
    private static final String DAY = "day";
    private static final String DAYS = "days";
    
    /**
     * Converts a LocalDateTime object to a legacy java.util.Date object.
     * 
     * @param dateTime   LocalDateTime object.
     * @return           Date object.
     */
    public static Date toDate(LocalDateTime dateTime) {
        return Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * Performs a "floor" operation on a LocalDateTime, and returns a new LocalDateTime
     * with time set to 00:00.
     * 
     * @param dateTime   LocalDateTime for operation to be performed on.
     * @return           "Floored" LocalDateTime.
     */
    public static LocalDateTime floorDate(LocalDateTime dateTime) {
        return dateTime.toLocalDate().atTime(0, 0);
    }

    /**
     * Formats a LocalDateTime to a relative date. 
     * Prefers DayOfWeek format, for dates up to 6 days from today.
     * Otherwise, returns a relative time (e.g. 13 days from now).
     * 
     * @param dateTime   LocalDateTime to format.
     * @return           Formatted relative day.
     */
    public static String formatDay(LocalDateTime dateTime) {
        LocalDate date = dateTime.toLocalDate();
        long daysDifference = LocalDate.now().until(date, ChronoUnit.DAYS);

        // Consider today's date.
        if (date.isEqual(LocalDate.now())) {
            return String.format("%s %s", TODAY, formatDateDisplay(date, true));
        }
        
        if (daysDifference == 1) {
            return String.format("%s %s", TOMORROW, formatDateDisplay(date, true));
        }

        // Consider dates up to 6 days from today.
        if (daysDifference > 1 && daysDifference <= 6) {
            return String.format("%s %s", date.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.US), formatDateDisplay(date, false));
                   
        }

        // Otherwise, dates should be a relative days ago/from now format.
        return String.format("%d %s %s", Math.abs(daysDifference), 
                StringUtil.pluralizer((int) Math.abs(daysDifference), DAY, DAYS), 
                daysDifference > 0 ? FROM_NOW : TILL_NOW);
    }
    
    /**
     * Formats a LocalDateTime to a shorten date. 
     * 
     * @param dateTime   LocalDateTime to format, withDaysOfWeek.
     * @return           Formatted shorten day.
     */
    private static String formatDateDisplay(LocalDate date, boolean withDaysOfWeek) {
        //return with the days of the week
        if (withDaysOfWeek) {
            return String.format("%s %s %s", date.getDayOfWeek().getDisplayName(TextStyle.SHORT, Locale.US),
                    date.getDayOfMonth(), date.getMonth().getDisplayName(TextStyle.SHORT, Locale.US));
        }
        else {
            return String.format("%s %s", date.getDayOfMonth(), date.getMonth().getDisplayName(TextStyle.FULL, Locale.US).substring(0, 3));            
        }
    }

}

@@ -112,16 +112,59 @@
 ZoneId;%0A
+import java.time.format.DateTimeFormatter;%0A
 import j
@@ -1978,68 +1978,13 @@
 urn 
-String.format(%22%25s %25s%22, TODAY, formatDateDisplay(date, true))
+TODAY
 ;%0A  
@@ -2058,71 +2058,16 @@
 urn 
-String.format(%22%25s %25s%22, TOMORROW, formatDateDisplay(date, true))
+TOMORROW
 ;%0A  
@@ -2201,39 +2201,16 @@
   return
- String.format(%22%25s %25s%22,
  date.ge
@@ -2267,62 +2267,9 @@
 .US)
-, formatDateDisplay(date, false));%0A                   
+;
 %0A   
@@ -2625,17 +2625,92 @@
 hort
-en
  date. 
+Excludes the day of week only if%0A     * the date is within 2-6 days from now.
 %0A   
@@ -2837,30 +2837,29 @@
     */%0A    p
-rivate
+ublic
  static Stri
@@ -2871,19 +2871,17 @@
 rmat
-DateDisplay
+ShortDate
 (Loc
@@ -2890,158 +2890,176 @@
 Date
+Time
  date
-, boolean withDaysOfWeek) %7B%0A        //return with the days of the week%0A        if (withDaysOfWeek) %7B%0A     
+Time) %7B%0A        LocalDate date = dateTime.toLocalDate();%0A        long daysDifference = LocalDate.now().until(date, ChronoUnit.DAYS);%0A
        
-return
  String
-.format(%22%25s %25s %25s%22,
+ dayOfWeek =
  dat
@@ -3117,17 +3117,17 @@
 cale.US)
-,
+;
 %0A       
@@ -3131,120 +3131,296 @@
     
-            date.getDayOfMonth(), date.getMonth().getDisplayName(TextStyle.SHORT, Locale.US));%0A        %7D
+String shortDate = date.format(DateTimeFormatter.ofPattern(%22dd MMM%22));%0A        %0A        // Don't show dayOfWeek for days d, such that d = %7Bn+2,...,n+6%7D, where n = date now%0A        if (daysDifference %3E= 2 && daysDifference %3C= 6) %7B%0A            return String.format(%22%25s%22, shortDate);
 %0A       
  els
@@ -3415,16 +3415,18 @@
 %0A       
+ %7D
  else %7B%0A
@@ -3473,115 +3473,28 @@
 , da
-te.getDayOfMonth(), date.getMonth().getDisplayName(TextStyle.FULL, Locale.US).substring(0, 3));            
+yOfWeek, shortDate);
 %0A   

Extract out usage of formatDateDisplay, refactor to formatShortDate