/*
* Copyright 2014 - LAit SpA
*				 Realizzato da Icona Management srl su commessa LAit SpA
* Copyright 2015- LAit SpA
*                                                  Aggiornato da LAit SpA
*
* Concesso in licenza a norma dell'EUPL, versione 1.1 o
* successive dell'EUPL (la "Licenza")– non appena saranno
* approvate dalla Commissione europea;
* Non è possibile utilizzare l'opera salvo nel rispetto della Licenza.
* È possibile ottenere una copia della Licenza al seguente indirizzo:
*
* http://ec.europa.eu/idabc/eupl
*
* Salvo diversamente indicato dalla legge applicabile o
* concordato per iscritto, il software distribuito secondo
* i termini della Licenza è distribuito "TAL QUALE",
* SENZA GARANZIE O CONDIZIONI DI ALCUN TIPO,
* esplicite o implicite.
* Si veda la Licenza per la lingua specifica che disciplina
* le autorizzazioni e le limitazioni secondo i termini della
* Licenza.
*/
/**
 * 
 */
package it.laitspa.cpf.util.misc;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

/**
 * @author Dario
 * 
 */
public class DateUtils
{
  protected static SimpleDateFormat shortDateFormat     = new SimpleDateFormat(
                                                            "dd/MM/yy");
  protected static SimpleDateFormat longDateFormat      = new SimpleDateFormat(
                                                            "dd/MM/yyyy");
  protected static SimpleDateFormat shortDateTimeFormat = new SimpleDateFormat(
                                                            "dd/MM/yy HH:mm:ss");
  protected static SimpleDateFormat longDateTimeFormat  = new SimpleDateFormat(
                                                            "dd/MM/yyyy HH:mm:ss");
  protected static SimpleDateFormat shortTimeFormat     = new SimpleDateFormat(
                                                            "HH:mm");
  protected static SimpleDateFormat longTimeFormat      = new SimpleDateFormat(
                                                            "HH:mm:ss");
  protected static SimpleDateFormat timestamp14Format   = new SimpleDateFormat(
                                                            "yyyyMMddHHmmss");
  protected static SimpleDateFormat timestamp8Format    = new SimpleDateFormat(
                                                            "yyyyMMdd");
  protected static SimpleDateFormat dbDayFormat         = new SimpleDateFormat(
                                                            "yyyy-MM-dd");
  protected static SimpleDateFormat dbDateTimeFormat    = new SimpleDateFormat(
                                                            "yyyy-MM-dd HH:mm:ss.0");
  protected static SimpleDateFormat f24paymentTimestamp = new SimpleDateFormat(
                                                            "yyyyMMdd");
  protected static SimpleDateFormat currencyTimestamp   = new SimpleDateFormat(
                                                            "yyyyMMdd");
  protected static SimpleDateFormat monthYearFormat     = new SimpleDateFormat(
                                                            "MMMMM yyyy");
  protected static SimpleDateFormat yearMonthFormat     = new SimpleDateFormat(
                                                            "yyyyMM");
  protected static SimpleDateFormat yearFormat          = new SimpleDateFormat(
                                                            "yyyy");

  public static Date getMidnightDate(Date d)
  {
    if(d == null)
      return null;

    GregorianCalendar gc = new GregorianCalendar();
    gc.setTime(d);
    gc.set(Calendar.HOUR_OF_DAY, 0);
    gc.set(Calendar.MINUTE, 0);
    gc.set(Calendar.SECOND, 0);
    gc.set(Calendar.MILLISECOND, 0);

    return gc.getTime();
  }

  public static Date getNextMidnightDate(Date d)
  {
    if(d == null)
      return null;

    GregorianCalendar gc = new GregorianCalendar();
    gc.setTime(getMidnightDate(d));
    gc.add(Calendar.DATE, 1);

    return gc.getTime();
  }

  public static Date getOtherDayOfSameMonth(Date d, int day)
  {
    if(d == null)
      return null;

    GregorianCalendar gc = new GregorianCalendar();
    gc.setTime(d);
    gc.set(Calendar.DAY_OF_MONTH, day);

    return gc.getTime();
  }

  public static Date getOtherTimeOfSameDay(Date d, int hour, int minutes,
      int seconds)
  {
    if(d == null)
      return null;

    GregorianCalendar gc = new GregorianCalendar();
    gc.setTime(d);
    gc.set(Calendar.HOUR_OF_DAY, hour);
    gc.set(Calendar.MINUTE, minutes);
    gc.set(Calendar.SECOND, seconds);
    gc.set(Calendar.MILLISECOND, 0);

    return gc.getTime();
  }

  public static Date normalize(Date d)
  {
    if(d == null)
      return null;

    GregorianCalendar gc = new GregorianCalendar();
    gc.setTime(d);
    gc.set(Calendar.SECOND, 0);
    gc.set(Calendar.MILLISECOND, 0);

    return gc.getTime();
  }

  public static Date getOneMinuteBefore(Date d)
  {
    if(d == null)
      return null;

    GregorianCalendar gc = new GregorianCalendar();
    gc.setTime(d);
    gc.add(Calendar.MINUTE, -1);

    return gc.getTime();
  }

  public static Date getMinutesBefore(Date d, int minutes)
  {
    if(d == null)
      return null;

    GregorianCalendar gc = new GregorianCalendar();
    gc.setTime(d);
    gc.add(Calendar.MINUTE, -minutes);

    return gc.getTime();
  }

  public static Date getSecondsAfter(Date d, int seconds)
  {
    if(d == null)
      return null;

    GregorianCalendar gc = new GregorianCalendar();
    gc.setTime(d);
    gc.add(Calendar.SECOND, +seconds);

    return gc.getTime();
  }

  public static Date getOneHourBefore(Date d)
  {
    if(d == null)
      return null;

    GregorianCalendar gc = new GregorianCalendar();
    gc.setTime(d);
    gc.add(Calendar.HOUR_OF_DAY, -1);

    return gc.getTime();
  }

  public static Date getOneDayBefore(Date d)
  {
    if(d == null)
      return null;

    GregorianCalendar gc = new GregorianCalendar();
    gc.setTime(d);
    gc.add(Calendar.DAY_OF_MONTH, -1);

    return gc.getTime();
  }

  public static Date getLastDayOfSameMonth(Date d)
  {
    if(d == null)
      return null;

    GregorianCalendar gc = new GregorianCalendar();
    gc.setTime(d);
    gc.add(Calendar.MONTH, 1);
    gc.set(Calendar.DAY_OF_MONTH, 1);
    gc.add(Calendar.DAY_OF_MONTH, -1);

    return gc.getTime();
  }

  public static boolean isMoreOrEqual(Date firstTimestamp, Date secondTimestamp)
  {
    long firstTS = firstTimestamp.getTime();
    long secondTS = secondTimestamp.getTime();

    return(firstTS >= secondTS);
  }

  public static boolean isMoreOrEqual(String first, String second)
  {
    if(!isValid(first) || !isValid(second))
      return false;
    
    try
    {
      return isMoreOrEqual(parse(first), parse(second));
    }
    catch(ParseException e)
    {
      return false;
    }
  }

  public static boolean isBetween(Date firstTimestamp, Date secondTimestamp,
      Date testTimestamp)
  {
    long firstTS = firstTimestamp.getTime();
    long secondTS = secondTimestamp.getTime();
    long testTS = testTimestamp.getTime();

    return((testTS >= firstTS) && (testTS <= secondTS));
  }

  public static boolean isSameDay(Date firstTimestamp, Date secondTimestamp)
  {
    GregorianCalendar gc1 = new GregorianCalendar();
    gc1.setTime(firstTimestamp);
    
    GregorianCalendar gc2 = new GregorianCalendar();
    gc2.setTime(secondTimestamp);
    
    // Compare years.
    //
    if(gc1.get(GregorianCalendar.YEAR) != gc2.get(GregorianCalendar.YEAR))
      return false;
    
    // Compare months.
    //
    if(gc1.get(GregorianCalendar.MONTH) != gc2.get(GregorianCalendar.MONTH))
      return false;
    
    // Compare dates.
    //
    if(gc1.get(GregorianCalendar.DATE) != gc2.get(GregorianCalendar.DATE))
      return false;

    return true;
  }

  
  public static boolean isToday(Date d)
  {
    return isSameDay(new Date(), d);
  }
  
  
  public static boolean isBetweenNotEqualRight(Date firstTimestamp,
      Date secondTimestamp, Date testTimestamp)
  {
    long firstTS = firstTimestamp.getTime();
    long secondTS = secondTimestamp.getTime();
    long testTS = testTimestamp.getTime();

    return((testTS >= firstTS) && (testTS < secondTS));
  }

  public static float getRemainingHoursBetween(Date firstTimestamp,
      Date secondTimestamp)
  {
    if(firstTimestamp == null || secondTimestamp == null)
      return 0.0f;

    float diffInHours = ((float)secondTimestamp.getTime() - firstTimestamp
        .getTime()) / (3600000.0f);

    return diffInHours;
  }

  public static Date parse(String s) throws ParseException
  {
    if(FormUtils.isEmpty(s))
      return null;

    SimpleDateFormat sdf = null;
    
    Pattern p = Pattern.compile("^\\d{1,2}/\\d{1,2}/\\d{4}$");
    Matcher m = p.matcher(s);
    if(m.find())
      sdf = longDateFormat;
    else
    {
      p = Pattern.compile("^\\d{1,2}/\\d{1,2}/\\d{2}$");
      m = p.matcher(s);
      if(m.find())
        sdf = shortDateFormat;
      else
        return null;
    }

    return sdf.parse(s);
  }

  
  public static Date parseDateTime(String s) 
    throws ParseException
  {
    if(FormUtils.isEmpty(s))
      return null;

    if(!isValidDateTime(s))
      return null;
    
    return longDateTimeFormat.parse(s);
  }

  
  public static boolean isValidDateTime(String s)
  {
    SimpleDateFormat sdf = longDateTimeFormat;
    
    Pattern p = Pattern.compile("^\\d{1,2}/\\d{1,2}/\\d{4}( \\d{2}:\\d{2}:\\d{2})$");
    Matcher m = p.matcher(s);
    if(!m.find())
      return false;

    Date parsedDate = null;
    try
    {
      parsedDate = sdf.parse(s);
    }
    catch(ParseException e)
    {
      e.printStackTrace();
    }

    String[] dateparts = s.split("/");
    String day = (dateparts[0].length() == 1) ? ("0" + dateparts[0]) : dateparts[0];
    String month = (dateparts[1].length() == 1) ? ("0" + dateparts[1]) : dateparts[1];
    String year = dateparts[2];
    
    String fpd = sdf.format(parsedDate);
    return fpd.equals(day + "/" + month + "/" + year);
  }

  
  public static boolean isValid(String s)
  {
    SimpleDateFormat sdf = null;
    
    Pattern p = Pattern.compile("^\\d{1,2}/\\d{1,2}/\\d{4}$");
    Matcher m = p.matcher(s);
    if(m.find())
      sdf = longDateFormat;
    else
    {
      p = Pattern.compile("^\\d{1,2}/\\d{1,2}/\\d{2}$");
      m = p.matcher(s);
      if(m.find())
        sdf = shortDateFormat;
      else
        return false;
    }

    Date parsedDate = null;
    try
    {
      parsedDate = sdf.parse(s);
    }
    catch(ParseException e)
    {
      e.printStackTrace();
    }

    String[] dateparts = s.split("/");
    String day = (dateparts[0].length() == 1) ? ("0" + dateparts[0]) : dateparts[0];
    String month = (dateparts[1].length() == 1) ? ("0" + dateparts[1]) : dateparts[1];
    String year = dateparts[2];
    
    String fpd = sdf.format(parsedDate);
    return fpd.equals(day + "/" + month + "/" + year);
  }

  public static String getStringDayForDB(Date date)
  {
    return date != null ? dbDayFormat.format(date) : null;
  }

  public static String getStringDateTimeForDB(Date date)
  {
    return date != null ? dbDateTimeFormat.format(date) : null;
  }

  public static String getStringTimestamp14(Date date)
  {
    return date != null ? timestamp14Format.format(date) : null;
  }

  public static String getStringTimestamp8(Date date)
  {
    return date != null ? timestamp8Format.format(date) : null;
  }

  public static Date parseTimestamp14(String s) throws ParseException
  {
    if(FormUtils.isEmpty(s))
      return null;

    return timestamp14Format.parse(s);
  }

  public static Date parseTimestamp8(String s) throws ParseException
  {
    if(FormUtils.isEmpty(s))
      return null;

    return timestamp8Format.parse(s);
  }

  public static Date parseF24PaymentTimestamp(String s) throws ParseException
  {
    if(FormUtils.isEmpty(s))
      return null;

    return f24paymentTimestamp.parse(s);
  }

  public static Date parseCurrencyTimestamp(String s) throws ParseException
  {
    if(FormUtils.isEmpty(s))
      return null;

    return currencyTimestamp.parse(s);
  }

  public static String toLongDateString(Date d)
  {
    return longDateFormat.format(d);
  }

  public static String toShortDateString(Date d)
  {
    return shortDateFormat.format(d);
  }

  public static String toShortTimeString(Date d)
  {
    return shortTimeFormat.format(d);
  }

  public static String toLongTimeString(Date d)
  {
    return longTimeFormat.format(d);
  }

  public static String toShortDateTimeString(Date d)
  {
    return shortDateTimeFormat.format(d);
  }

  public static String toLongDateTimeString(Date d)
  {
    return longDateTimeFormat.format(d);
  }

  public static String toMonthYearString(Date d)
  {
    return monthYearFormat.format(d);
  }

  public static String toYearString(Date d)
  {
    return yearFormat.format(d);
  }
  
  public static String toYearMonthString(Date d)
  {
    return yearMonthFormat.format(d);
  }
  
  public static String toTimestamp8String(Date d)
  {
    return timestamp8Format.format(d);
  }

  
  public static Date getCurrentDate()
  {
    return getMidnightDate(new Date());
  }

  public static java.sql.Date toSQLDate(Date date)
  {
    try
    {
      if(date != null)
      {
        long date_long = date.getTime();
        return new java.sql.Date(date_long);
      }
      else
        return null;
    }
    catch(Exception e)
    {
      return null;
    }
  }
  
  public static java.sql.Timestamp toSQLTimestamp(Date date)
  {
    try
    {
      if(date != null)
      {
        long date_long = date.getTime();
        return new java.sql.Timestamp(date_long);
      }
      else
        return null;
    }
    catch(Exception e)
    {
      return null;
    }
  }

  public static Date min(Date d1, Date d2)
  {
    if(d1 == null || d2 == null)
      throw new IllegalArgumentException("No null arguments allowed.");

    if(d1.before(d2))
      return d1;
    else
      return d2;
  }
  
  public static XMLGregorianCalendar toXMLDate(Date date)
  {
    try
    {
      if(date != null)
      {
        GregorianCalendar c = new GregorianCalendar();
        c.setTime(date);
        XMLGregorianCalendar date2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
        return date2;
      }
      else
        return null;
    }
    catch(Exception e)
    {
      return null;
    }
  }
  
  public static Date toDate(XMLGregorianCalendar xc)
  {
    try
    {
      if(xc != null)
      {
        return xc.toGregorianCalendar().getTime();
      }
      else
        return null;
    }
    catch(Exception e)
    {
      return null;
    }
  }
  
  
  
  public static String toLitteralAspMonth(String mese)
  {
    String[] months = new String[]{"Gennaio", "Febbraio","Marzo", "Aprile", "Maggio", "Giugno", "Luglio",
        "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre", "Mese 13"};
    
    Integer month = Integer.parseInt(mese);
    
    if (month > 0 && month <= months.length)
      return months[month - 1];
    
    return null;
    
  }
}
