
package gov.va.med.cds.ars.persistence;

import java.io.Serializable;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;

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

import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.usertype.UserType;

public class XmlDateOnlyUserType implements UserType {
	private int[] types = { Types.DATE };

	private static SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");

	public int[] sqlTypes() {
		return types;
	}

	@SuppressWarnings("rawtypes")
	public Class returnedClass() {
		return XMLGregorianCalendar.class;
	}

	public boolean equals(Object a, Object b) throws HibernateException {
		return (a == b) || ((a != null) && (b != null) && (a.equals(b)));
	}

	public int hashCode(Object o) throws HibernateException {
		return o.hashCode();
	}

	public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner)
			throws HibernateException, SQLException {
		String strDate = rs.getString(names[0]);
		java.util.Date date = null;

		XMLGregorianCalendar returnDate = null;
		Date databaseDate;

		try {
			date = formatter.parse(strDate);
		} catch (ParseException e) {
			throw new IllegalStateException("XmlDateOnlyUserType nullSafeGet date parse failure : " + strDate);
		}

		databaseDate = new Date(date.getTime());
		returnDate = asXMLGregorianCalendar(databaseDate);
		return returnDate;
	}

	public void nullSafeSet(PreparedStatement ps, Object value, int index, SessionImplementor sessionImplementor)
			throws HibernateException, SQLException {
		throw new IllegalStateException("nullSafeSet not implemented for usertype XmlDateUserType.");
	}

	public Object deepCopy(Object o) throws HibernateException {
		Date returnDate = null;

		if (o instanceof Date) {
			returnDate = new Date(((Date) o).getTime());
		}
		return returnDate;
	}

	public boolean isMutable() {
		return true;
	}

	public Serializable disassemble(Object value) throws HibernateException {
		return (Serializable) value;
	}

	public Object assemble(Serializable cached, Object owner) throws HibernateException {
		return cached;
	}

	public Object replace(Object original, Object target, Object owner) throws HibernateException {
		return original;
	}

	/**
	 * Converts a java.util.Date into an instance of XMLGregorianCalendar
	 * 
	 * @param date
	 *            database date
	 * @return xml object of date
	 */
	public static XMLGregorianCalendar asXMLGregorianCalendar(Date date) {
		if (date == null) {
			return null;
		} else {
			GregorianCalendar cal = new GregorianCalendar();
			cal.setTimeInMillis(date.getTime());
			XMLGregorianCalendar xmlDate = null;
			try {
				xmlDate = DatatypeFactory.newInstance().newXMLGregorianCalendarDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH)+1, cal.get(Calendar.DAY_OF_MONTH),DatatypeConstants.FIELD_UNDEFINED);
			} catch (DatatypeConfigurationException e) {
				throw new IllegalStateException("Error in XML Date conversion : " + e);
			}
			return xmlDate;
		}
	}
}
