/********************************************************************
 * Copyright © 2004 VHA. All rights reserved
 ********************************************************************/
package gov.va.med.esr.common.persistent.hibernate;

// Java Classes
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;

import org.hibernate.HibernateException;
import org.hibernate.type.StringType;
import org.hibernate.type.TimestampType;
import org.hibernate.usertype.UserType;

import gov.va.med.esr.common.infra.ImpreciseDate;

/**
 * @author Martin Francisco
 */
public class CombinedImpreciseDateType implements UserType {
	private final StringType stringType;

	// public static final String DATABASE_FORMAT = "yyyyMMddHHmmss.SSSZ"; // if need time
	public static final String DATABASE_FORMAT = ImpreciseDate.STANDARD_IMPRECISE_DATE_FORMAT_WITH_ALL_COMPONENTS;

	public CombinedImpreciseDateType() {
		super();

		this.stringType = new StringType();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.hibernate.UserType#sqlTypes()
	 */
	public int[] sqlTypes() {
		return new int[] { stringType.sqlType() };
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.hibernate.UserType#returnedClass()
	 */
	public Class returnedClass() {
		return ImpreciseDate.class;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.hibernate.UserType#equals(java.lang.Object, java.lang.Object)
	 */
	public boolean equals(Object x, Object y) throws HibernateException {
		return ((x == y) || ((x != null) && x.equals(y)));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.hibernate.UserType#nullSafeGet(java.sql.ResultSet,
	 *      java.lang.String[], java.lang.Object)
	 */
	public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
			throws HibernateException, SQLException {
		String string = (String) this.stringType.nullSafeGet(rs, names[0]);

		try {
			return fromDatabaseValue(string);
		} catch(ParseException e) {
			throw new HibernateException("Can not parse database String date into ImpreciseDate", e);
		}
	}

	public static ImpreciseDate fromDatabaseValue(String date) throws ParseException {
		ImpreciseDate val = null;
		if (date != null) {
			val = new ImpreciseDate(date);
			// alternative way to do this....
			/*if (date.length() <= 6) {
				// imprecise
				val = new ImpreciseDate(date);
			} else {
				// precise
				val = new ImpreciseDate((new SimpleDateFormat(DATABASE_FORMAT))
						.parse(date));
			}*/
		}
	
		return val;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.hibernate.UserType#nullSafeSet(java.sql.PreparedStatement,
	 *      java.lang.Object, int)
	 */
	public void nullSafeSet(PreparedStatement st, Object value, int index)
			throws HibernateException, SQLException {
		stringType.nullSafeSet(st, toDatabaseValue((ImpreciseDate) value),
				index);
	}

	public static String toDatabaseValue(ImpreciseDate date) {
		return date != null ? date.toStandardFormat() : null;
		// alternative way to do this....
		/*String val = null;
		if (date != null) {
			if (date.isPrecise())
				val = new SimpleDateFormat(DATABASE_FORMAT).format(date
						.getDate());
			else
				val = date.getString();
		}
		return val;*/
	}

	
	/*
	 * (non-Javadoc)
	 * 
	 * @see org.hibernate.UserType#deepCopy(java.lang.Object)
	 */
	public Object deepCopy(Object value) throws HibernateException {
		// The type is immutable so it's ok to return the same instance.
		return value;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.hibernate.UserType#isMutable()
	 */
	public boolean isMutable() {
		return false;
	}

	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;
	}

	public int hashCode(Object x) throws HibernateException {
		return x != null ? x.hashCode() : 0;
	}

}