package eu.dnetlib.openaire.common;

import java.text.FieldPosition;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;

import com.fasterxml.jackson.databind.util.StdDateFormat;

public class RFC3339DateFormat extends StdDateFormat {

	/**
	 *
	 */
	private static final long serialVersionUID = 8174507696046505992L;

	private static final TimeZone TIMEZONE_Z = TimeZone.getTimeZone("UTC");

	// Same as ISO8601DateFormat but serializing milliseconds.
	@Override
	public StringBuffer format(final Date date, final StringBuffer toAppendTo, final FieldPosition fieldPosition) {
		final String value = format(date, true, TIMEZONE_Z, Locale.US);
		toAppendTo.append(value);
		return toAppendTo;
	}

	/**
	 * Format date into yyyy-MM-ddThh:mm:ss[.sss][Z|[+-]hh:mm]
	 *
	 * @param date
	 *            the date to format
	 * @param millis
	 *            true to include millis precision otherwise false
	 * @param tz
	 *            timezone to use for the formatting (UTC will produce 'Z')
	 * @return the date formatted as yyyy-MM-ddThh:mm:ss[.sss][Z|[+-]hh:mm]
	 */
	private static String format(final Date date, final boolean millis, final TimeZone tz, final Locale loc) {
		final Calendar calendar = new GregorianCalendar(tz, loc);
		calendar.setTime(date);

		// estimate capacity of buffer as close as we can (yeah, that's pedantic ;)
		final StringBuilder sb = new StringBuilder(30);
		sb.append(String.format("%04d-%02d-%02dT%02d:%02d:%02d", calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH) + 1, calendar
			.get(Calendar.DAY_OF_MONTH), calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), calendar.get(Calendar.SECOND)));
		if (millis) {
			sb.append(String.format(".%03d", calendar.get(Calendar.MILLISECOND)));
		}

		final int offset = tz.getOffset(calendar.getTimeInMillis());
		if (offset != 0) {
			final int hours = Math.abs(offset / (60 * 1000) / 60);
			final int minutes = Math.abs(offset / (60 * 1000) % 60);
			sb.append(String.format("%c%02d:%02d", offset < 0 ? '-' : '+', hours, minutes));
		} else {
			sb.append('Z');
		}
		return sb.toString();
	}

}
