package ru.yandex.webmaster3.core.semantic.review_business.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Helps to convert dates and strings
 * Deal with UTC date-time format.
 * For details see http://www.w3.org/TR/NOTE-datetime
 *
 * @author Dima Schitinin <dimas@yandex-team.ru>
 */
public final class DateHelper {

    private static final Logger log = LoggerFactory.getLogger(DateHelper.class);

    private DateHelper() {
    }

    /**
     * Represents UTC date format without time
     */
    public static ThreadLocal<DateFormat> DATE_FORMAT =
            new ThreadLocal<DateFormat>() {
                @Override
                protected DateFormat initialValue() {
                    return new SimpleDateFormat("yyyy-MM-dd");
                }
            };

    /**
     * Represents UTC date format with time
     */
    public static ThreadLocal<DateFormat> DATE_WITH_TIME_FORMAT =
            new ThreadLocal<DateFormat>() {
                @Override
                protected DateFormat initialValue() {
                    return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
                }
            };

    public static ThreadLocal<DateFormat> DATE_TIME_WITH_ZONE_FORMAT =
            new ThreadLocal<DateFormat>() {
                @Override
                protected DateFormat initialValue() {
                    return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
                }
            };

    /**
     * Writes date in UTC format with time
     *
     * @param date date to be written
     * @return date representation in UTC string
     */
    public static String write(final Date date) {
        if (date == null) {
            log.error("Try to write null date", new Throwable());
            return null;
        }
        return DATE_TIME_WITH_ZONE_FORMAT.get().format(date);
    }

    /**
     * Writes date in UTC format with time
     * if date is not null
     *
     * @param date date to be written to string
     * @return date representation in UTC string or
     *         null if date is null
     */
    public static String safeWrite(final Date date) {
        if (date == null) {
            return null;
        }
        return DATE_TIME_WITH_ZONE_FORMAT.get().format(date);
    }

    /**
     * Tries to read date from string.
     * Assume that argument is UTC representation of date
     *
     * @param dateAsStr date to be parsed
     * @return Date instance if successfully parsed
     *         or null otherwise
     */
    public static Date read(final String dateAsStr) {
        if (dateAsStr == null || dateAsStr.isEmpty()) {
            return null;
        }
        try {
            return DATE_TIME_WITH_ZONE_FORMAT.get().parse(dateAsStr);
        } catch (ParseException ex1) {
            try {
                return DATE_WITH_TIME_FORMAT.get().parse(dateAsStr);
            } catch (ParseException ex2) {
                try {
                    return DATE_FORMAT.get().parse(dateAsStr);
                } catch (ParseException ex3) {
                    try {
                        if (dateAsStr.length() == 10) {
                            Date date = new Date(Long.parseLong(dateAsStr + "000"));
                            return date;
                        } else if (dateAsStr.length() == 13) {
                            Date date = new Date(Long.parseLong(dateAsStr));
                            return date;
                        } else throw new NumberFormatException();
                    } catch (NumberFormatException ex) {
                        log.error("Unable to parse '" + dateAsStr + "'");
                        return null;
                    }
                }
            }
        }

    }
}

