package eu.dnetlib.dlms.jdbc;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.List;
import java.util.concurrent.ExecutionException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * ResultSet implementation. This is a simple implementation for ResultSet instances that are forward-only and non
 * concurrently updatable.
 * 
 * @author lexis
 */
public class SimpleDOLResultSet extends DOLResultSet {

	/** logger. */
	private static final Log log = LogFactory.getLog(SimpleDOLResultSet.class);

	/**
	 * Constructor.
	 * 
	 * @param statement
	 *            the statement whose execution has generated this ResultSet instance.
	 * @param columns
	 *            CoumnInfo array. Each element describes a column of the result set.
	 * @throws SQLException
	 *             sql exception
	 */
	public SimpleDOLResultSet(final DOLStatement statement, final ColumnInfo[] columns) throws SQLException {
		super(statement, columns);
		super.setFetchDirection(ResultSet.FETCH_FORWARD);
		super.setConcurrency(ResultSet.CONCUR_READ_ONLY);
		super.setType(ResultSet.TYPE_FORWARD_ONLY);

	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.dlms.jdbc.DOLResultSet#setFetchDirection(int)
	 */
	@Override
	public void setFetchDirection(final int direction) throws SQLException {
		if (this.isClosed())
			throw new SQLException();
		else
			throw new SQLFeatureNotSupportedException("It's not allowed to change fetch direction on a " + this.getClass() + " instance");
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.dlms.jdbc.DOLResultSet#setConcurrency(int)
	 */
	@Override
	void setConcurrency(final int concurrency) throws SQLException {
		if (this.isClosed())
			throw new SQLException();
		else
			throw new SQLFeatureNotSupportedException("It's not allowed to change concurrency on a " + this.getClass() + " instance");

	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.dlms.jdbc.DOLResultSet#setType(int)
	 */
	@Override
	void setType(final int type) throws SQLException {
		if (this.isClosed())
			throw new SQLException();
		else
			throw new SQLFeatureNotSupportedException("It's not allowed to change type on a " + this.getClass() + " instance");

	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.dlms.jdbc.DOLResultSet#getColumnData(int)
	 */
	@Override
	Object getColumnData(final int index) throws SQLException {
		if (this.isClosed()) {
			throw new SQLException();
		}
		//TODO: now that I introduced ExecutorService in AbstractDOLExecutor, I do not know how many column we have
		//		if (index < 0 || index >= this.getColumnInfos().length)
		//			throw new SQLException("No column with index " + index);
		DataResult currentRow = this.getCurrentRow();
		if (currentRow.isSentinel()) {
			throw new SQLException("No current row available");
		}
		this.setWasNull((currentRow.getData()[index] == null));
		return currentRow.getData()[index];
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see eu.dnetlib.dlms.jdbc.DOLResultSet#next()
	 */
	@Override
	public boolean next() throws SQLException {
		if (this.isClosed()) {
			throw new SQLException();
		}
		try {
			if (this.getCurrResultIndex() == -1) {
				List<DataResult> currRes = this.getStatement().getDolExecuter().getNextResult(); //call executor for the list of result
				log.debug("currres == " + currRes);
				if (currRes.size() > 0) {
					this.setResults(currRes);
					this.setCurrResultIndex(0);
					return !currRes.get(0).isSentinel();
				} else
					return false;
			} else {
				//we are already iterating over results
				int currPos = this.getCurrResultIndex();
				log.debug("currPos == " + currPos);
				if (this.getResults().size() > currPos + 1) {
					this.setCurrResultIndex(++currPos);
					return !this.getResults().get(currPos).isSentinel();
				}
				return false;
			}
			//			DataResult current = this.getStatement().getDolExecuter().getNextRow();
			//			this.setCurrentRow(current);
			//			log.debug("Got a row which is a sentinel? " + current.isSentinel());
			//			return !current.isSentinel();
		} catch (InterruptedException e) {
			throw new SQLException(e);
		} catch (ExecutionException e) {
			throw new SQLException(e);
		}
	}

}
