package mit.sql ;

public class Clob
	implements	sql.Clob
{
	private static final String GETSUBSTRING = "getSubString" ;
	private static final String POSITION = "position" ;
	private static final Long INVALIDPOSITION = new Long( -1 ) ;

	private static final sql.TableException LOCALCLOBGETSUBSTRINGFAILED
		= new sql.TableException
			( sql.TableException.CLOBGETSUBSTRINGFAILED
			) ;

	private static final sql.TableException LOCALCLOBPOSITIONFAILED
		= new sql.TableException
			( sql.TableException.BLOBPOSITIONFAILED
			) ;

	private mit.sql.Rows rows = null ;
	private int row = 0 ;
	private int col = 0 ;
	private Long pos = INVALIDPOSITION ;
	private Integer len = new Integer( 0 ) ;
	private String searchstr = null ;
	private Long start = INVALIDPOSITION ;

	private long length = 0 ;
	public long length() { return this.length ; }

	protected Clob
		( mit.sql.Rows rows
		, long length
		, int row
		, int col
		)
	{
		this.rows = rows ;
		this.row = row ;
		this.col = col ;
		this.length = length ;
	}

	public String getSubString
		( Long pos
		, Integer len
		)
		throws Exception
	{
		this.pos = pos ;
		this.len = len ;
		mit.sql.Connection connection
			= ( mit.sql.Connection )
				rows.table.getConnection() ;
		String substr = null ;
		if( connection.hasClient() )
		{
			substr = getSubStringRemotely() ;
		}
		else
		{
			substr = getSubStringLocally() ;
		}
		return substr ;
	}

	private String getSubStringRemotely()
		throws Exception
	{
		Object[] args = new Object[ 2 ] ;
		args[ 0 ] = this.pos ;
		args[ 1 ] = this.len ;
		Class[] argstypes = new Class[ 2 ] ;
		argstypes[ 0 ] = args[ 0 ].getClass() ;
		argstypes[ 1 ] = args[ 1 ].getClass() ;
		mit.sql.Connection connection
			= ( mit.sql.Connection )
				rows.table.getConnection() ;
		mit.rmi.Client client = connection.getClient() ;
		return ( String ) client.invoke( this , GETSUBSTRING , argstypes , args ) ;
	}

	public String getSubStringLocally()
		throws Exception
	{
		java.sql.ResultSet rs = null ;
		try
		{
			rs = rows.getResultSet() ;
			int rsType = rs.getType() ;
			if( rs.TYPE_FORWARD_ONLY == rsType )
			{
				if( rs.next() )
				{
					return getSubStringFromResultSet( rs ) ;
				}
			}
			else if( rs.TYPE_SCROLL_INSENSITIVE == rsType )
			{
				rs.setFetchDirection( rs.FETCH_FORWARD ) ;
				if( rs.first() )
				{
					return getSubStringFromResultSet( rs ) ;
				}
			}
			else if( rs.TYPE_SCROLL_SENSITIVE == rsType )
			{
				rs.setFetchDirection( rs.FETCH_FORWARD ) ;
				boolean isRowAvailable = rs.first() ;
				if( rs.first() )
				{
					return getSubStringFromResultSet( rs ) ;
				}
			}
			java.sql.Statement statement = rs.getStatement() ;
			rs.close() ;
			statement.close() ;
		}
		catch( Exception ex )
		{
			if( null != rs )
			{
				rs.close() ;
			}
			String message = LOCALCLOBGETSUBSTRINGFAILED.getMessage() ;
			message += ex.getMessage() ;
			throw new sql.TableException( message ) ;
		}
		return null ;
	}

	private String getSubStringFromResultSet
		( java.sql.ResultSet rs 
		)
		throws Exception
	{
		int cursor = 0 ;
		boolean isRowAvailable = true ;
		while( isRowAvailable )
		{
			if( cursor == this.row )
			{
				java.sql.Clob clob = ( java.sql.Clob ) rs.getObject( this.col + 1 ) ;
				return clob.getSubString( this.pos.longValue() , this.len.intValue() ) ;
			}
			cursor ++ ;
			isRowAvailable = rs.next() ;
		}
		return null ;
	}

	public Long position
		( String searchstr
		, Long start
		)
		throws Exception
	{
		this.searchstr = searchstr ;
		this.start = start ;

		mit.sql.Connection connection
			= ( mit.sql.Connection )
				rows.table.getConnection() ;
		Long thePosition = INVALIDPOSITION ;
		if( connection.hasClient() )
		{
			thePosition = positionRemotely() ;
		}
		else
		{
			thePosition = positionLocally() ;
		}
		return thePosition ;
	}

	private Long positionRemotely()
		throws Exception
	{
		Object[] args = new Object[ 2 ] ;
		args[ 0 ] = this.searchstr ;
		args[ 1 ] = this.start ;
		Class[] argstypes = new Class[ 2 ] ;
		argstypes[ 0 ] = args[ 0 ].getClass() ;
		argstypes[ 1 ] = args[ 1 ].getClass() ;
		mit.sql.Connection connection
			= ( mit.sql.Connection )
				rows.table.getConnection() ;
		mit.rmi.Client client = connection.getClient() ;
		return ( Long ) client.invoke( this , POSITION , argstypes , args ) ;
	}

	private Long positionLocally()
		throws Exception
	{
		java.sql.ResultSet rs = null ;
		try
		{
			rs = rows.getResultSet() ;
			int rsType = rs.getType() ;
			if( rs.TYPE_FORWARD_ONLY == rsType )
			{
				if( rs.next() )
				{
					return positionFromResultSet( rs ) ;
				}
			}
			else if( rs.TYPE_SCROLL_INSENSITIVE == rsType )
			{
				rs.setFetchDirection( rs.FETCH_FORWARD ) ;
				if( rs.first() )
				{
					return positionFromResultSet( rs ) ;
				}
			}
			else if( rs.TYPE_SCROLL_SENSITIVE == rsType )
			{
				rs.setFetchDirection( rs.FETCH_FORWARD ) ;
				boolean isRowAvailable = rs.first() ;
				if( rs.first() )
				{
					return positionFromResultSet( rs ) ;
				}
			}
			java.sql.Statement statement = rs.getStatement() ;
			rs.close() ;
			statement.close() ;
		}
		catch( Exception ex )
		{
			if( null != rs )
			{
				rs.close() ;
			}
			String message = LOCALCLOBPOSITIONFAILED.getMessage() ;
			message += ex.getMessage() ;
			throw new sql.TableException( message ) ;
		}
		return INVALIDPOSITION ;
	}

	private Long positionFromResultSet
		( java.sql.ResultSet rs 
		)
		throws Exception
	{
		int cursor = 0 ;
		boolean isRowAvailable = true ;
		while( isRowAvailable )
		{
			if( cursor == this.row )
			{
				java.sql.Clob clob = ( java.sql.Clob ) rs.getObject( this.col + 1 ) ;
				return new Long( clob.position( this.searchstr , this.start.longValue() ) ) ;
			}
			cursor ++ ;
			isRowAvailable = rs.next() ;
		}
		return INVALIDPOSITION ;
	}

}