package eu.dnetlib.enabling.is.sn.resourcestate.hib;

import static java.sql.Types.VARCHAR;

import java.io.Serializable;
import java.io.StringReader;
import java.io.StringWriter;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.EndpointReference;
import javax.xml.ws.wsaddressing.W3CEndpointReference;

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

/**
 * Serializes Endpoint reference types to database columns (strings).
 * 
 * @author marko
 * 
 */
public class EndpointReferenceType implements UserType { // NOPMD

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.hibernate.usertype.UserType#assemble(java.io.Serializable, java.lang.Object)
	 */
	@Override
	public Object assemble(final Serializable arg0, final Object owner) {
		if (arg0 == null) return null;
		return EndpointReference.readFrom(new StreamSource(new StringReader((String) arg0)));
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.hibernate.usertype.UserType#deepCopy(java.lang.Object)
	 */
	@Override
	public Object deepCopy(final Object arg0) {
		if (arg0 == null) return null;

		return arg0;
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.hibernate.usertype.UserType#disassemble(java.lang.Object)
	 */
	@Override
	public Serializable disassemble(final Object arg0) {
		final StringWriter buffer = new StringWriter();
		((W3CEndpointReference) arg0).writeTo(new StreamResult(buffer));
		return buffer.toString();
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.hibernate.usertype.UserType#equals(java.lang.Object, java.lang.Object)
	 */
	@Override
	public boolean equals(final Object arg0, final Object arg1) {
		if (arg0 == arg1) // NOPMD
			return true;
		if ((arg0 == null) || (arg1 == null)) return false;
		return arg0.equals(arg1);
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.hibernate.usertype.UserType#hashCode(java.lang.Object)
	 */
	@Override
	public int hashCode(final Object arg0) {
		return disassemble(arg0).hashCode();
	}

	@Override
	public boolean isMutable() {
		return false;
	}

	/**
	 * 
	 * {@inheritDoc}
	 * 
	 * @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet, java.lang.String[], org.hibernate.engine.spi.SessionImplementor,
	 *      java.lang.Object)
	 */
	@Override
	public Object nullSafeGet(final ResultSet rset, final String[] names, final SessionImplementor si, final Object owner) throws SQLException {
		return assemble(rset.getString(names[0]), owner);
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.hibernate.usertype.UserType#nullSafeSet(java.sql.PreparedStatement, java.lang.Object, int,
	 *      org.hibernate.engine.spi.SessionImplementor)
	 */
	@Override
	public void nullSafeSet(final PreparedStatement statement, final Object epr, final int index, final SessionImplementor arg3) throws HibernateException,
			SQLException {
		if (epr != null) {
			statement.setString(index, (String) disassemble(epr));
		}

	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.hibernate.usertype.UserType#replace(java.lang.Object, java.lang.Object, java.lang.Object)
	 */
	@Override
	public Object replace(final Object arg0, final Object arg1, final Object arg2) {
		// is not mutable
		return null;
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.hibernate.usertype.UserType#returnedClass()
	 */
	@Override
	@SuppressWarnings("rawtypes")
	public Class returnedClass() {
		return W3CEndpointReference.class;
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.hibernate.usertype.UserType#sqlTypes()
	 */
	@Override
	public int[] sqlTypes() {
		return new int[] { VARCHAR };
	}

}
