package name.ltp.jdbcwrapper;

import java.sql.*;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;

public class StatementWrapper implements Statement, AutoCloseable
{
	public ConnectionWrapper c;
	public Statement s;
	public final long time;
	public final StackTraceElement[] stack;

	public final List<ResultSetWrapper> resultsets = Collections.synchronizedList(new LinkedList<ResultSetWrapper>());

	protected StatementWrapper(ConnectionWrapper c, Statement s)
	{
		this.c = c;
		this.s = s;
		time = System.currentTimeMillis();
		stack = Thread.currentThread().getStackTrace();

		synchronized(JdbcWatcher.i().sts)
		{
			JdbcWatcher.i().sts.add(this);
		}
	}

	@Override
	public ResultSetWrapper executeQuery(String sql) throws SQLException
	{
		ResultSetWrapper rsw = new ResultSetWrapper(this, s.executeQuery(sql));
		resultsets.add(rsw);
		return rsw;
	}

	@Override
	public void close() throws SQLException
	{
		if(resultsets.size() > 0)
			try
			{
				ListIterator<ResultSetWrapper> i = resultsets.listIterator(resultsets.size() - 1);
				if(i.hasNext())
					try
					{
						i.next().close();
						i.remove();
					}
					catch(Exception e)
					{Err.i().err(e.toString());}
				while(i.hasPrevious())
					try
					{
						i.previous().close();
						i.remove();
					}
					catch(Exception e)
					{Err.i().err(e.toString());}
			}
			catch(Exception e)
			{Err.i().err(e.toString());}

		if(s != null)
			s.close();

		s = null;
	}

	@Override
	public int executeUpdate(String sql) throws SQLException
	{
		return s.executeUpdate(sql);
	}

	@Override
	public int getMaxFieldSize() throws SQLException
	{
		return s.getMaxFieldSize();
	}

	@Override
	public void setMaxFieldSize(int max) throws SQLException
	{
		s.setMaxFieldSize(max);
	}

	@Override
	public int getMaxRows() throws SQLException
	{
		return s.getMaxRows();
	}

	@Override
	public void setMaxRows(int max) throws SQLException
	{
		s.setMaxRows(max);
	}

	@Override
	public void setEscapeProcessing(boolean enable) throws SQLException
	{
		s.setEscapeProcessing(enable);
	}

	@Override
	public int getQueryTimeout() throws SQLException
	{
		return s.getQueryTimeout();
	}

	@Override
	public void setQueryTimeout(int seconds) throws SQLException
	{
		s.setQueryTimeout(seconds);
	}

	@Override
	public void cancel() throws SQLException
	{
		s.cancel();
	}

	@Override
	public SQLWarning getWarnings() throws SQLException
	{
		return s.getWarnings();
	}

	@Override
	public void clearWarnings() throws SQLException
	{
		s.clearWarnings();
	}

	@Override
	public void setCursorName(String name) throws SQLException
	{
		s.setCursorName(name);
	}

	@Override
	public boolean execute(String sql) throws SQLException
	{
		return s.execute(sql);
	}

	@Override
	public ResultSetWrapper getResultSet() throws SQLException
	{
		ResultSetWrapper rsw = new ResultSetWrapper(this, s.getResultSet());
		resultsets.add(rsw);
		return rsw;
	}

	@Override
	public int getUpdateCount() throws SQLException
	{
		return s.getUpdateCount();
	}

	@Override
	public boolean getMoreResults() throws SQLException
	{
		return s.getMoreResults();
	}

	@Override
	public void setFetchDirection(int direction) throws SQLException
	{
		s.setFetchDirection(direction);
	}

	@Override
	public int getFetchDirection() throws SQLException
	{
		return s.getFetchDirection();
	}

	@Override
	public void setFetchSize(int rows) throws SQLException
	{
		s.setFetchSize(rows);
	}

	@Override
	public int getFetchSize() throws SQLException
	{
		return s.getFetchSize();
	}

	@Override
	public int getResultSetConcurrency() throws SQLException
	{
		return s.getResultSetConcurrency();
	}

	@Override
	public int getResultSetType()  throws SQLException
	{
		return s.getResultSetType();
	}

	@Override
	public void addBatch( String sql ) throws SQLException
	{
		s.addBatch(sql);
	}

	@Override public
	void clearBatch() throws SQLException
	{
		s.clearBatch();
	}

	@Override public
	int[] executeBatch() throws SQLException
	{
		return s.executeBatch();
	}

	@Override public
	Connection getConnection()  throws SQLException
	{
		return c;
	}

	@Override public
	boolean getMoreResults(int current) throws SQLException
	{
		return s.getMoreResults(current);
	}

	@Override public
	ResultSetWrapper getGeneratedKeys() throws SQLException
	{
		ResultSetWrapper rsw = new ResultSetWrapper(this, s.getGeneratedKeys());
		resultsets.add(rsw);
		return rsw;
	}

	@Override public
	int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException
	{
		return s.executeUpdate(sql, autoGeneratedKeys);
	}

	@Override public
	int executeUpdate(String sql, int columnIndexes[]) throws SQLException
	{
		return s.executeUpdate(sql, columnIndexes);
	}

	@Override public
	int executeUpdate(String sql, String columnNames[]) throws SQLException
	{
		return s.executeUpdate(sql, columnNames);
	}

	@Override public
	boolean execute(String sql, int autoGeneratedKeys) throws SQLException
	{
		return s.execute(sql, autoGeneratedKeys);
	}

	@Override public
	boolean execute(String sql, int columnIndexes[]) throws SQLException
	{
		return s.execute(sql, columnIndexes);
	}

	@Override public
	boolean execute(String sql, String columnNames[]) throws SQLException
	{
		return s.execute(sql, columnNames);
	}

	@Override public
	int getResultSetHoldability() throws SQLException
	{
		return s.getResultSetHoldability();
	}

	@Override public
	boolean isClosed() throws SQLException
	{
		return s.isClosed();
	}

	@Override public
	void setPoolable(boolean poolable) throws SQLException
	{
		s.setPoolable(poolable);
	}

	@Override public
	boolean isPoolable() throws SQLException
	{
		return s.isPoolable();
	}

	@Override
	public void closeOnCompletion() throws SQLException
	{
		s.closeOnCompletion();
	}

	@Override
	public boolean isCloseOnCompletion() throws SQLException
	{
		return s.isCloseOnCompletion();
	}

	@Override
	public <T> T unwrap(Class<T> iface) throws SQLException
	{
		return s.unwrap(iface);
	}

	@Override
	public boolean isWrapperFor(Class<?> iface) throws SQLException
	{
		return s.isWrapperFor(iface);
	}
}

