package com.sun.identity.shared;

import java.text.MessageFormat;
import java.text.ParseException;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;

public class DateUtils {
   private static final String UTC_DATE_Z_FORMAT = "{0}-{1}-{2}T{3}:{4}:{5}Z";
   private static final String UTC_DATE_FORMAT = "{0}-{1}-{2}T{3}:{4}:{5}";
   private static final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone("UTC");

   public static String dateToString(Date date) {
      return dateToString(date, "{0}-{1}-{2}T{3}:{4}:{5}");
   }

   public static String toUTCDateFormat(Date date) {
      return dateToString(date, "{0}-{1}-{2}T{3}:{4}:{5}Z");
   }

   private static String dateToString(Date date, String format) {
      GregorianCalendar cal = new GregorianCalendar(UTC_TIME_ZONE);
      cal.setTime(date);
      String[] params = new String[]{
         formatInteger(cal.get(1), 4),
         formatInteger(cal.get(2) + 1, 2),
         formatInteger(cal.get(5), 2),
         formatInteger(cal.get(11), 2),
         formatInteger(cal.get(12), 2),
         formatInteger(cal.get(13), 2)
      };
      return MessageFormat.format(format, params);
   }

   private static String formatInteger(int value, int length) {
      String val = Integer.toString(value);
      int diff = length - val.length();

      for (int i = 0; i < diff; i++) {
         val = "0" + val;
      }

      return val;
   }

   public static Date stringToDate(String strDate) throws ParseException {
      int[] diffTime = null;
      boolean plusTime = true;
      int idxT = strDate.indexOf(84);
      if (idxT == -1) {
         throw new ParseException("Invalid Date Format", 0);
      }

      int idxDiffUTC = strDate.indexOf(45, idxT);
      if (idxDiffUTC == -1) {
         idxDiffUTC = strDate.indexOf(43, idxT);
         plusTime = false;
      }

      if (idxDiffUTC != -1) {
         diffTime = getDiffTime(strDate, idxDiffUTC);
         strDate = strDate.substring(0, idxDiffUTC);
      }

      int idxMilliSec = strDate.indexOf(46);
      if (idxMilliSec != -1) {
         strDate = strDate.substring(0, idxMilliSec);
      } else {
         char lastChar = strDate.charAt(strDate.length() - 1);
         if (lastChar == 'z' || lastChar == 'Z') {
            strDate = strDate.substring(0, strDate.length() - 1);
         }
      }

      return createDate(strDate, diffTime, plusTime);
   }

   private static int[] getDiffTime(String strDate, int idx) throws ParseException {
      String strDiff = strDate.substring(idx + 1, strDate.length() - 1);
      int[] diffArray = new int[2];
      int colonIdx = strDiff.indexOf(58);
      if (colonIdx == -1) {
         throw new ParseException("Invalid Date Format", 0);
      }

      try {
         diffArray[0] = Integer.parseInt(strDiff.substring(0, colonIdx));
         diffArray[1] = Integer.parseInt(strDiff.substring(colonIdx + 1));
         return diffArray;
      } catch (NumberFormatException nfe) {
         throw new ParseException("Invalid Date Format", 0);
      }
   }

   private static Date createDate(String strDate, int[] timeDiff, boolean plusDiff) throws ParseException {
      try {
         int year = Integer.parseInt(strDate.substring(0, 4));
         if (strDate.charAt(4) != '-') {
            throw new ParseException("Invalid Date Format", 0);
         }

         int month = Integer.parseInt(strDate.substring(5, 7)) - 1;
         if (strDate.charAt(7) != '-') {
            throw new ParseException("Invalid Date Format", 0);
         }

         int day = Integer.parseInt(strDate.substring(8, 10));
         if (strDate.charAt(10) != 'T') {
            throw new ParseException("Invalid Date Format", 0);
         }

         int hour = Integer.parseInt(strDate.substring(11, 13));
         if (strDate.charAt(13) != ':') {
            throw new ParseException("Invalid Date Format", 0);
         }

         int minute = Integer.parseInt(strDate.substring(14, 16));
         int second = 0;
         if (strDate.length() > 17) {
            if (strDate.charAt(16) != ':') {
               throw new ParseException("Invalid Date Format", 0);
            }

            second = Integer.parseInt(strDate.substring(17, 19));
         }

         GregorianCalendar cal = new GregorianCalendar(year, month, day, hour, minute, second);
         cal.setTimeZone(UTC_TIME_ZONE);
         if (timeDiff != null) {
            int hourDiff = plusDiff ? timeDiff[0] : -1 * timeDiff[0];
            int minuteDiff = plusDiff ? timeDiff[1] : -1 * timeDiff[1];
            cal.add(10, hourDiff);
            cal.add(12, minuteDiff);
         }

         return cal.getTime();
      } catch (NumberFormatException nfe) {
         throw new ParseException("Invalid Date Format", 0);
      }
   }
}
