package com.capgemini.framework.common;

import lombok.extern.slf4j.Slf4j;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

/** This class formats Date for use with Teamcenter. */
@Slf4j
public final class TeamcenterDateFormatter {

    /** Date Format of the form 'dd/MM/yyyy HH:mm:ss' which gives '2014/Apr/08 14:08:44' in US timezone. */
    public static final String DD_MM_YYYY_HH_MM_SS = "dd/MM/yyyy HH:mm:ss";
    /** Date Format of the form 'yyyy/MMM/dd' which gives '2014/Apr/08' in US timezone. */
    private static final String YYYY_MMM_DD = "yyyy/MMM/dd";
    /** Date Format of the form 'dd-MMMM-yyyy' which gives '08-April-2014' in US timezone. */
    private static final String DD_MMMM_YYYY = "dd MMMM yyyy";
    /** Date Format of the form 'dd-MMM-yyyy' which gives '08-Apr-2014' in US timezone. */
    private static final String DD_MMM_YYYY = "dd-MMM-yyyy";
    /** Date Format of the form 'dd-MM-yyyy' which gives '08-04-2014'. */
    public static final String DD_MM_YYYY = "dd-MM-yyyy";
    /** Date Format of the form 'dd-MM-yyyy HH:mm' which gives '08-07-2014 10:12'. */
    public static final String DD_MM_YYYY_HH_MM = DD_MM_YYYY + " HH:mm";
    /** Date Format of the form 'yyyyMMdd' which gives '20140408'. */
    public static final String YYYYMMDD = "yyyyMMdd";
    /** Date Format of the form 'YYYYMMDD_hhmmss' which gives '20140408_140844'. */
    public static final String YYYYMMDD_HHMMSS = "yyyyMMdd_HHmmss";

    private static final Locale LOCAL_US = Locale.US;
    private static final String TIME_ZONE_PARIS = "Europe/Paris";

    private TeamcenterDateFormatter() {
        // Private to make this class a Helper.
    }

    /**
     * Returns the current time with format "dd/MM/yyyy HH:mm:ss".
     * 
     * @return a String
     */
    public static String getCurrentTime() {
        DateFormat dateFormat = new SimpleDateFormat(DD_MM_YYYY_HH_MM_SS);
        Calendar cal = Calendar.getInstance();
        return dateFormat.format(cal.getTime()); // ex: "01/09/2014 16:00:22"
    }

    /**
     * Make an object Calendar for Teamcenter 10 with String parameter format : dd-MM-yyyy.
     * 
     * @param aDate a string date to parseformat
     * @return calendar
     */
    public static Calendar makeTeamcenterCalendar(final String aDate) {
        if (aDate == null || aDate.isEmpty()) {
            return Calendar.getInstance();
        } else {
            SimpleDateFormat curFormater = new SimpleDateFormat(DD_MM_YYYY);
            try {
                Date dateObj = curFormater.parse(aDate);
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(dateObj);
              calendar.set(Calendar.HOUR, 23);
              calendar.set(Calendar.MINUTE, 59);
              calendar.set(Calendar.SECOND, 59);
                return calendar;
            } catch (ParseException e) {
                log.error("WRONG format: " + aDate + ", expecting " + DD_MM_YYYY + " defaulting to current date", e);
                return Calendar.getInstance();
            }
        }
    }

    /**
     * Takes a {@link Calendar} and formats it to 'dd-MMM-yyyy' using {@link Locale#US} for use in the Saved Query of Teamcenter 10.
     * 
     * @param inputDate (may be null, to represent 'NOW')
     * @return a String showing the date in the new format
     */
    public static synchronized String translateDateFormatForRequest(final Calendar inputDate) {
        return new SimpleDateFormat(DD_MMM_YYYY, LOCAL_US).format(inputDate == null ? Calendar.getInstance().getTime() : inputDate.getTime());
    }

    /**
     * Takes a date with format 'dd-MM-yyyy' and formats it to 'dd-MMM-yyyy' for Saved Query of Teamcenter 10.
     * 
     * @param inputDate with this format: dd-MM-yyyy (may be null, to represent 'NOW')
     * @return a String showing the date in the new format
     */
    public static String translateDateFormatForRequest(final String inputDate) {
        // format type
        SimpleDateFormat dateFormatInput = new SimpleDateFormat(DD_MM_YYYY);
        SimpleDateFormat dateFormatOutput = new SimpleDateFormat(DD_MMM_YYYY, LOCAL_US);

        if (inputDate == null || inputDate.isEmpty()) {
            return dateFormatOutput.format(Calendar.getInstance().getTime());
        } else {
            try {
                Date dateInputParsed = dateFormatInput.parse(inputDate);
                return dateFormatOutput.format(dateInputParsed);
            } catch (ParseException e1) {
                log.error("WRONG format : expecting " + DD_MMM_YYYY, e1);
                return DD_MMM_YYYY;
            }
        }
    }

    /**
     * Format a date based on a pattern : yyyy/MMM/dd.
     * 
     * @param calendar a Calendar to fromat
     * @return date as a String
     */
    public static String formatCalendarYearMonthDay(final Calendar calendar) {
        SimpleDateFormat sdf = new SimpleDateFormat(YYYY_MMM_DD);
        return sdf.format(calendar.getTime());
    }

    /**
     * Format a date based on a pattern parameter.
     * 
     * @param calendar a Calendar to format
     * @param patternDate a format pattern
     * @return date as a String
     */
    public static String formatCalendarToPattern(final Calendar calendar, final String patternDate) {
        try {
            return new SimpleDateFormat(patternDate).format(calendar.getTime());
        } catch (IllegalArgumentException e) {
            log.warn("Invalid Date Format received (\"" + patternDate + "\"), defaulting to dd_MM_yyyy", e);
            return new SimpleDateFormat(DD_MM_YYYY).format(calendar.getTime());
        }
    }

    /**
     * Formats a date based on the following pattern : 'dd mmmm yyyy' , also using {@link TimeZone}: Europe (Paris) and french {@link Locale}.
     * 
     * @param calendar a Calendar to format to french
     * @return dateFormatFR
     */
    public static String formatCalendarToFrench(final Calendar calendar) {
        SimpleDateFormat sdf = new SimpleDateFormat(DD_MMMM_YYYY, Locale.FRENCH);
        sdf.setTimeZone(getParisTimeZone());
        Calendar theCalendar = calendar == null ? Calendar.getInstance() : calendar;
        return sdf.format(theCalendar.getTime());
    }

    /**
     * Returns the Paris {@link TimeZone}.
     * 
     * @return a {@link TimeZone}
     */
    public static TimeZone getParisTimeZone() {
        return TimeZone.getTimeZone(TeamcenterDateFormatter.TIME_ZONE_PARIS);
    }

}
