/*
 * Decompiled with CFR 0.152.
 */
package org.jxmpp.util;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class XmppDateTime {
    private static final DateFormatType dateFormatter = DateFormatType.XEP_0082_DATE_PROFILE;
    private static final Pattern datePattern = Pattern.compile("^\\d+-\\d+-\\d+$");
    private static final DateFormatType timeFormatter = DateFormatType.XEP_0082_TIME_MILLIS_ZONE_PROFILE;
    private static final Pattern timePattern = Pattern.compile("^(\\d+:){2}\\d+.\\d+(Z|([+-](\\d+:\\d+)))$");
    private static final DateFormatType timeNoZoneFormatter = DateFormatType.XEP_0082_TIME_MILLIS_PROFILE;
    private static final Pattern timeNoZonePattern = Pattern.compile("^(\\d+:){2}\\d+.\\d+$");
    private static final DateFormatType timeNoMillisFormatter = DateFormatType.XEP_0082_TIME_ZONE_PROFILE;
    private static final Pattern timeNoMillisPattern = Pattern.compile("^(\\d+:){2}\\d+(Z|([+-](\\d+:\\d+)))$");
    private static final DateFormatType timeNoMillisNoZoneFormatter = DateFormatType.XEP_0082_TIME_PROFILE;
    private static final Pattern timeNoMillisNoZonePattern = Pattern.compile("^(\\d+:){2}\\d+$");
    private static final DateFormatType dateTimeFormatter = DateFormatType.XEP_0082_DATETIME_MILLIS_PROFILE;
    private static final Pattern dateTimePattern = Pattern.compile("^\\d+(-\\d+){2}+T(\\d+:){2}\\d+.\\d+(Z|([+-](\\d+:\\d+)))?$");
    private static final DateFormatType dateTimeNoMillisFormatter = DateFormatType.XEP_0082_DATETIME_PROFILE;
    private static final Pattern dateTimeNoMillisPattern = Pattern.compile("^\\d+(-\\d+){2}+T(\\d+:){2}\\d+(Z|([+-](\\d+:\\d+)))?$");
    private static final DateFormat xep0091Formatter = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss");
    private static final DateFormat xep0091Date6DigitFormatter = new SimpleDateFormat("yyyyMd'T'HH:mm:ss");
    private static final DateFormat xep0091Date7Digit1MonthFormatter = new SimpleDateFormat("yyyyMdd'T'HH:mm:ss");
    private static final DateFormat xep0091Date7Digit2MonthFormatter = new SimpleDateFormat("yyyyMMd'T'HH:mm:ss");
    private static final Pattern xep0091Pattern = Pattern.compile("^\\d+T\\d+:\\d+:\\d+$");
    private static final List<PatternCouplings> couplings = new ArrayList<PatternCouplings>();
    private static final Pattern SECOND_FRACTION;

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    public static Date parseXEP0082Date(String dateString) throws ParseException {
        for (PatternCouplings coupling : couplings) {
            Matcher matcher = coupling.pattern.matcher(dateString);
            if (!matcher.matches()) continue;
            return coupling.formatter.parse(dateString);
        }
        DateFormatType dateFormatType = dateTimeNoMillisFormatter;
        synchronized (dateFormatType) {
            return dateTimeNoMillisFormatter.parse(dateString);
        }
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    public static Date parseDate(String dateString) throws ParseException {
        Matcher matcher = xep0091Pattern.matcher(dateString);
        if (matcher.matches()) {
            int length = dateString.split("T")[0].length();
            if (length < 8) {
                Date date = XmppDateTime.handleDateWithMissingLeadingZeros(dateString, length);
                if (date != null) {
                    return date;
                }
            } else {
                DateFormat dateFormat = xep0091Formatter;
                synchronized (dateFormat) {
                    return xep0091Formatter.parse(dateString);
                }
            }
        }
        return XmppDateTime.parseXEP0082Date(dateString);
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    public static String formatXEP0082Date(Date date) {
        DateFormatType dateFormatType = dateTimeFormatter;
        synchronized (dateFormatType) {
            return dateTimeFormatter.format(date);
        }
    }

    public static String convertXep82TimezoneToRfc822(String dateString) {
        if (dateString.charAt(dateString.length() - 1) == 'Z') {
            return dateString.replace("Z", "+0000");
        }
        return dateString.replaceAll("([\\+\\-]\\d\\d):(\\d\\d)", "$1$2");
    }

    public static String convertRfc822TimezoneToXep82(String dateString) {
        int length = dateString.length();
        String res = dateString.substring(0, length - 2);
        res = res + ':';
        res = res + dateString.substring(length - 2, length);
        return res;
    }

    public static String asString(TimeZone timeZone) {
        int rawOffset = timeZone.getRawOffset();
        int hours = rawOffset / 3600000;
        int minutes = Math.abs(rawOffset / 60000 - hours * 60);
        return String.format("%+d:%02d", hours, minutes);
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    private static Date handleDateWithMissingLeadingZeros(String stampString, int dateLength) throws ParseException {
        if (dateLength == 6) {
            DateFormat dateFormat = xep0091Date6DigitFormatter;
            synchronized (dateFormat) {
                return xep0091Date6DigitFormatter.parse(stampString);
            }
        }
        Calendar now = Calendar.getInstance();
        Calendar oneDigitMonth = XmppDateTime.parseXEP91Date(stampString, xep0091Date7Digit1MonthFormatter);
        Calendar twoDigitMonth = XmppDateTime.parseXEP91Date(stampString, xep0091Date7Digit2MonthFormatter);
        List<Calendar> dates = XmppDateTime.filterDatesBefore(now, oneDigitMonth, twoDigitMonth);
        if (!dates.isEmpty()) {
            return XmppDateTime.determineNearestDate(now, dates).getTime();
        }
        return null;
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    private static Calendar parseXEP91Date(String stampString, DateFormat dateFormat) {
        try {
            DateFormat dateFormat2 = dateFormat;
            synchronized (dateFormat2) {
                dateFormat.parse(stampString);
                return dateFormat.getCalendar();
            }
        }
        catch (ParseException e) {
            return null;
        }
    }

    private static List<Calendar> filterDatesBefore(Calendar now, Calendar ... dates) {
        ArrayList<Calendar> result = new ArrayList<Calendar>();
        for (Calendar calendar : dates) {
            if (calendar == null || !calendar.before(now)) continue;
            result.add(calendar);
        }
        return result;
    }

    private static String handleMilliseconds(String dateString) {
        Matcher matcher = SECOND_FRACTION.matcher(dateString);
        if (!matcher.matches()) {
            return dateString;
        }
        int fractionalSecondsDigitCount = matcher.group(1).length();
        if (fractionalSecondsDigitCount == 3) {
            return dateString;
        }
        int posDecimal = dateString.indexOf(".");
        StringBuilder sb = new StringBuilder(dateString.length() - fractionalSecondsDigitCount + 3);
        if (fractionalSecondsDigitCount > 3) {
            sb.append(dateString.substring(0, posDecimal + 4));
        } else {
            sb.append(dateString.substring(0, posDecimal + fractionalSecondsDigitCount + 1));
            for (int i = fractionalSecondsDigitCount; i < 3; ++i) {
                sb.append('0');
            }
        }
        sb.append(dateString.substring(posDecimal + fractionalSecondsDigitCount + 1));
        return sb.toString();
    }

    private static Calendar determineNearestDate(final Calendar now, List<Calendar> dates) {
        Collections.sort(dates, new Comparator<Calendar>(){

            @Override
            public int compare(Calendar o1, Calendar o2) {
                Long diff1 = new Long(now.getTimeInMillis() - o1.getTimeInMillis());
                Long diff2 = new Long(now.getTimeInMillis() - o2.getTimeInMillis());
                return diff1.compareTo(diff2);
            }
        });
        return dates.get(0);
    }

    static {
        TimeZone utc = TimeZone.getTimeZone("UTC");
        xep0091Formatter.setTimeZone(utc);
        xep0091Date6DigitFormatter.setTimeZone(utc);
        xep0091Date7Digit1MonthFormatter.setTimeZone(utc);
        xep0091Date7Digit1MonthFormatter.setLenient(false);
        xep0091Date7Digit2MonthFormatter.setTimeZone(utc);
        xep0091Date7Digit2MonthFormatter.setLenient(false);
        couplings.add(new PatternCouplings(datePattern, dateFormatter));
        couplings.add(new PatternCouplings(dateTimePattern, dateTimeFormatter));
        couplings.add(new PatternCouplings(dateTimeNoMillisPattern, dateTimeNoMillisFormatter));
        couplings.add(new PatternCouplings(timePattern, timeFormatter));
        couplings.add(new PatternCouplings(timeNoZonePattern, timeNoZoneFormatter));
        couplings.add(new PatternCouplings(timeNoMillisPattern, timeNoMillisFormatter));
        couplings.add(new PatternCouplings(timeNoMillisNoZonePattern, timeNoMillisNoZoneFormatter));
        SECOND_FRACTION = Pattern.compile(".*\\.(\\d{1,})(Z|((\\+|-)\\d{4}))");
    }

    private static class PatternCouplings {
        final Pattern pattern;
        final DateFormatType formatter;

        public PatternCouplings(Pattern datePattern, DateFormatType dateFormat) {
            this.pattern = datePattern;
            this.formatter = dateFormat;
        }
    }

    public static enum DateFormatType {
        XEP_0082_DATE_PROFILE("yyyy-MM-dd"),
        XEP_0082_DATETIME_PROFILE("yyyy-MM-dd'T'HH:mm:ssZ"),
        XEP_0082_DATETIME_MILLIS_PROFILE("yyyy-MM-dd'T'HH:mm:ss.SSSZ"),
        XEP_0082_TIME_PROFILE("hh:mm:ss"),
        XEP_0082_TIME_ZONE_PROFILE("hh:mm:ssZ"),
        XEP_0082_TIME_MILLIS_PROFILE("hh:mm:ss.SSS"),
        XEP_0082_TIME_MILLIS_ZONE_PROFILE("hh:mm:ss.SSSZ"),
        XEP_0091_DATETIME("yyyyMMdd'T'HH:mm:ss");

        private final String FORMAT_STRING;
        private final DateFormat FORMATTER;
        private final boolean CONVERT_TIMEZONE;
        private final boolean HANDLE_MILLIS;

        private DateFormatType(String dateFormat) {
            this.FORMAT_STRING = dateFormat;
            this.FORMATTER = new SimpleDateFormat(this.FORMAT_STRING);
            this.FORMATTER.setTimeZone(TimeZone.getTimeZone("UTC"));
            this.CONVERT_TIMEZONE = dateFormat.charAt(dateFormat.length() - 1) == 'Z';
            this.HANDLE_MILLIS = dateFormat.contains("SSS");
        }

        /*
         * WARNING - Removed try catching itself - possible behaviour change.
         */
        public String format(Date date) {
            String res;
            DateFormat dateFormat = this.FORMATTER;
            synchronized (dateFormat) {
                res = this.FORMATTER.format(date);
            }
            if (this.CONVERT_TIMEZONE) {
                res = XmppDateTime.convertRfc822TimezoneToXep82(res);
            }
            return res;
        }

        /*
         * WARNING - Removed try catching itself - possible behaviour change.
         */
        public Date parse(String dateString) throws ParseException {
            if (this.CONVERT_TIMEZONE) {
                dateString = XmppDateTime.convertXep82TimezoneToRfc822(dateString);
            }
            if (this.HANDLE_MILLIS) {
                dateString = XmppDateTime.handleMilliseconds(dateString);
            }
            DateFormat dateFormat = this.FORMATTER;
            synchronized (dateFormat) {
                return this.FORMATTER.parse(dateString);
            }
        }
    }
}
