/********************************************************************
 * 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.sql.Timestamp;

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;
import gov.va.med.esr.common.infra.ImpreciseDateStringFormat;

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

    public ImpreciseDateType()
    {
        super();

        this.timestampType = new TimestampType();
        this.stringType = new StringType();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.hibernate.UserType#sqlTypes()
     */
    public int[] sqlTypes()
    {
        return new int[] {
                this.timestampType.sqlType(),
                this.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
    {
        Timestamp date = (Timestamp)this.timestampType
            .nullSafeGet(rs, names[0]);
        String string = (String)this.stringType.nullSafeGet(rs, names[1]);

        if(date != null)
        {
            return new ImpreciseDate(date);
        }
        else if(string != null)
        {
            return new ImpreciseDate((new ImpreciseDateStringFormat(string))
                .getCalendar());
        }
        else
        {
            return null;
        }
    }

    /*
     * (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
    {
        if(value != null)
        {
            ImpreciseDate impreciseDate = (ImpreciseDate)value;

            if(impreciseDate.isPrecise())
            {
                this.timestampType
                    .nullSafeSet(st, impreciseDate.getDate(), index);
                this.stringType.nullSafeSet(st, null, index + 1);
            }
            else
            {
                this.timestampType.nullSafeSet(st, null, index);
                this.stringType
                    .nullSafeSet(st, impreciseDate.getString(), index + 1);
            }
        }
        else
        {
            this.timestampType.nullSafeSet(st, null, index);
            this.stringType.nullSafeSet(st, null, index + 1);
        }
    }

    /*
     * (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;
	}	
	
}