package eu.dnetlib.dlms.jdbc;

import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.Array;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.NClob;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.Ref;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.RowId;
import java.sql.SQLException;
import java.sql.SQLXML;
import java.sql.Time;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.TimeZone;

import eu.dnetlib.dlms.rmi.ParameterDescription;
import eu.dnetlib.dlms.rmi.StatementDescription;
import eu.dnetlib.enabling.tools.ServiceResolver;

public class WSRemotePreparedStatement extends WSRemoteStatement implements PreparedStatement {

	private StatementDescription statementDescription;

	public WSRemotePreparedStatement(final ServiceResolver serviceResolver, final WSRemoteConnection connection, final String source) {
		super(serviceResolver, connection);
		this.statementDescription = new StatementDescription();

		this.statementDescription.setSource(source);
	}

	public boolean execute() throws SQLException {
		this.remoteExecute(this.statementDescription);
		return true;
	}

	public ResultSet executeQuery() throws SQLException {
		this.remoteExecute(this.statementDescription);
		return this.getResultSet();
	}

	public int executeUpdate() throws SQLException {
		this.remoteExecute(this.statementDescription);
		this.getResultSet().next();
		return 0;
	}

	public void setString(final int parameterIndex, final String x) throws SQLException {
		this.setParameter(parameterIndex, new ParameterDescription("STRING", x));
	}

	public void setInt(final int parameterIndex, final int x) throws SQLException {
		this.setParameter(parameterIndex, new ParameterDescription("INT", Integer.toString(x)));
	}

	public void setLong(final int parameterIndex, final long x) throws SQLException {
		this.setParameter(parameterIndex, new ParameterDescription("INT", Long.toString(x)));
	}

	public void setBoolean(final int parameterIndex, final boolean x) throws SQLException {
		this.setParameter(parameterIndex, new ParameterDescription("BOOLEAN", Boolean.toString(x)));

	}

	public void setObject(final int parameterIndex, final Object x) throws SQLException {
		if (x instanceof InformationObject)
			this.setParameter(parameterIndex, new ParameterDescription("INFORMATION_OBJECT", this.serializeInformationObject((InformationObject) x)));
		else
			throw new IllegalArgumentException("Cannot serialize " + x);
	}

	public void setURL(final int parameterIndex, final URL x) throws SQLException {
		this.setParameter(parameterIndex, new ParameterDescription("URL", x.toString()));

	}

	public void setDate(final int parameterIndex, final Date x) throws SQLException {
		final DateFormat df = DateFormat.getDateInstance();
		df.setTimeZone(TimeZone.getTimeZone("GMT"));

		this.setParameter(parameterIndex, new ParameterDescription("DATE", df.format(x)));
	}

	protected void setParameter(final int pos, final ParameterDescription description) {
		this.ensurePositional();
		final List<ParameterDescription> params = this.statementDescription.getPositionalParameters();

		if (pos > (params.size() + 1))
			throw new IllegalArgumentException("cannot set parameter " + pos + " because not in order");
		if (pos == (params.size() + 1)) {
			params.add(description);
			return;
		}
		params.set(pos - 1, description);
	}

	private void ensurePositional() {
		if (this.statementDescription.getPositionalParameters() == null)
			this.statementDescription.setPositionalParameters(new ArrayList<ParameterDescription>());
		this.statementDescription.setNamedParameters(null);
	}

	@SuppressWarnings("unused")
	private void ensureNamed() {
		if (this.statementDescription.getNamedParameters() == null)
			this.statementDescription.setNamedParameters(new HashMap<String, ParameterDescription>());
		this.statementDescription.setPositionalParameters(null);
	}

	public void addBatch() throws SQLException {
		// TODO Auto-generated method stub

	}

	public void clearParameters() throws SQLException {
		this.statementDescription.setPositionalParameters(new ArrayList<ParameterDescription>());
	}

	public ResultSetMetaData getMetaData() throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	public ParameterMetaData getParameterMetaData() throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	public void setArray(final int parameterIndex, final Array x) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setAsciiStream(final int parameterIndex, final InputStream x) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setAsciiStream(final int parameterIndex, final InputStream x, final int length) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setAsciiStream(final int parameterIndex, final InputStream x, final long length) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setBigDecimal(final int parameterIndex, final BigDecimal x) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setBinaryStream(final int parameterIndex, final InputStream x) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setBinaryStream(final int parameterIndex, final InputStream x, final int length) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setBinaryStream(final int parameterIndex, final InputStream x, final long length) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setBlob(final int parameterIndex, final Blob x) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setBlob(final int parameterIndex, final InputStream inputStream) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setBlob(final int parameterIndex, final InputStream inputStream, final long length) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setByte(final int parameterIndex, final byte x) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setBytes(final int parameterIndex, final byte[] x) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setCharacterStream(final int parameterIndex, final Reader reader) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setCharacterStream(final int parameterIndex, final Reader reader, final int length) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setCharacterStream(final int parameterIndex, final Reader reader, final long length) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setClob(final int parameterIndex, final Clob x) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setClob(final int parameterIndex, final Reader reader) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setClob(final int parameterIndex, final Reader reader, final long length) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setDate(final int parameterIndex, final Date x, final Calendar cal) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setDouble(final int parameterIndex, final double x) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setFloat(final int parameterIndex, final float x) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setNCharacterStream(final int parameterIndex, final Reader value) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setNCharacterStream(final int parameterIndex, final Reader value, final long length) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setNClob(final int parameterIndex, final NClob value) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setNClob(final int parameterIndex, final Reader reader) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setNClob(final int parameterIndex, final Reader reader, final long length) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setNString(final int parameterIndex, final String value) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setNull(final int parameterIndex, final int sqlType) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setNull(final int parameterIndex, final int sqlType, final String typeName) throws SQLException {
		// TODO Auto-generated method stub

	}

	private String serializeInformationObject(final InformationObject x) {
		return new Long(x.getId()).toString() + "," + x.getType() + "," + x.getSet();
	}

	public void setObject(final int parameterIndex, final Object x, final int targetSqlType) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setObject(final int parameterIndex, final Object x, final int targetSqlType, final int scaleOrLength) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setRef(final int parameterIndex, final Ref x) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setRowId(final int parameterIndex, final RowId x) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setSQLXML(final int parameterIndex, final SQLXML xmlObject) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setShort(final int parameterIndex, final short x) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setTime(final int parameterIndex, final Time x) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setTime(final int parameterIndex, final Time x, final Calendar cal) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setTimestamp(final int parameterIndex, final Timestamp x) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setTimestamp(final int parameterIndex, final Timestamp x, final Calendar cal) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setUnicodeStream(final int parameterIndex, final InputStream x, final int length) throws SQLException {
		// TODO Auto-generated method stub

	}

	public StatementDescription getStatementDescription() {
		return this.statementDescription;
	}

	public void setStatementDescription(final StatementDescription statementDescription) {
		this.statementDescription = statementDescription;
	}

}
