/*
_____       _    _    Corso   Italia,  178
(_|__   .  (_   |_|_  56125           Pisa
(_|_) |)|(()_)()| |   tel.  +39  050 46380
  |   |               picosoft@picosoft.it

 Copyright (C) Picosoft s.r.l. 1995-2002

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2, or (at your option)
 any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/
package IT.picosoft.jdbc;

import java.io.*;
import java.math.BigDecimal;
import java.sql.*;
import java.util.Calendar;
import java.util.Hashtable;
import java.util.Vector;

public class PicoPreparedStatement extends PicoStatement
             implements PreparedStatement {

   Vector boundParams = new Vector();

   public PicoPreparedStatement(PicoConnection con,PicoDbApi api
                                /* ,Hashtable typeInfo */) throws SQLException {
      super(con, api /*, typeInfo */);
   }

   public void addBatch() {
      throw new UnsupportedOperationException();
   }

   public void clearParameters() throws SQLException {
      boundParams.removeAllElements();
   }

   public synchronized void close() throws SQLException {
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("*Statement.close hStmt =" + hStmt);
      if (!myConnection.isClosed()) {
         clearMyResultSet();
         try {
            clearWarnings();
            if (!hStmt.isDropped()) {
               hStmt.drop();
               clearParameters();
            }
         } catch(SQLException ex) { }
      }
      myConnection.deregisterStatement(this);
   }

   public synchronized boolean execute() throws SQLException {
      int i;
      boolean Return = false;

      if(DriverManager.getLogWriter() != null)
         DriverManager.println("*PreparedStatement.execute");
      clearWarnings();
      reset();
      try {
         odbcApi.SQLExecuteParams(hStmt, boundParams);
      } catch(SQLWarning sqlwarning) {
         setWarning (sqlwarning);
      }
      int nCol = -1;
      if((nCol = getColumnCount()) > 0)
         Return = true;
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("*PreparedStatement.execute nCol=" + nCol);
      return Return;
   }

   public ResultSet executeQuery() throws SQLException {
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("*PreparedStatement.executeQuery");
      ResultSet Return = null;
      if(execute())
         Return = getResultSet(false);
      else
         throw new SQLException("No ResultSet was produced");
      return Return;
   }

   public ResultSet executeQuery(String s) throws SQLException {
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("*PreparedStatement.executeQuery (" + s + ")");
      throw new SQLException("Driver does not support this function", "IM001");
   }

   public int executeUpdate() throws SQLException {
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("*PreparedStatement.executeUpdate");
      int i = -1;
      if(!execute())
         i = getUpdateCount();
      else
         throw new SQLException("No row count was produced");
      return i;
   }

   public int executeUpdate(String s) throws SQLException {
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("*PreparedStatement.executeUpdate (" + s + ")");
      throw new SQLException("Driver does not support this function", "IM001");
   }

   public ResultSetMetaData getMetaData() {
      throw new UnsupportedOperationException();
   }

   public static int getTypeFromObject(Object obj) {
      int Return;

      if (obj == null)
         Return = 0;
      else if (obj instanceof String)
         Return = OdbcDef.SQL_VARCHAR;
      else if (obj instanceof BigDecimal)
         Return = OdbcDef.SQL_NUMERIC;
      else if (obj instanceof Boolean)
         Return = OdbcDef.SQL_BIT;
      else if (obj instanceof Byte)
         Return = OdbcDef.SQL_TINYINT;
      else if (obj instanceof Integer)
         Return = OdbcDef.SQL_INTEGER;
      else if (obj instanceof Long)
         Return = OdbcDef.SQL_BIGINT;
      else if (obj instanceof Float)
         Return = OdbcDef.SQL_REAL;
      else if (obj instanceof Double)
         Return = OdbcDef.SQL_DOUBLE;
      else if (obj instanceof byte[])
         Return = OdbcDef.SQL_LONGVARBINARY;
      else if (obj instanceof Date)
         Return = OdbcDef.SQL_C_DATE;
      else if (obj instanceof Time)
         Return = OdbcDef.SQL_C_TIME;
      else if (obj instanceof Timestamp)
         Return = OdbcDef.SQL_C_TIMESTAMP;
      else
         Return = 9999;
      return Return;
   }
   public void setObject(int paramIndex, Object obj) throws SQLException {
      setObject(paramIndex, obj, getTypeFromObject(obj));
   }

   public void setObject(int paramIndex, Object obj, int type)
               throws SQLException {
      setObject(paramIndex, obj, type, 0);
   }

   public void setObject(int paramIndex, Object obj, int type,  Calendar cal)
                   throws SQLException {
      setObject(paramIndex, obj, type, 0, cal);
   }
   
   public void setObject(int paramIndex, Object obj, int type, int scale)
                   throws SQLException {
      setObject(paramIndex, obj, type, scale, (Calendar) null);
   }

   public void setObject(int paramIndex, Object obj, int type, int scale,
                                             Calendar cal) throws SQLException {
      switch (type) {
      case OdbcDef.SQL_TYPE_NULL:
         break;
      case OdbcDef.SQL_CHAR:
      case OdbcDef.SQL_VARCHAR:
      case OdbcDef.SQL_LONGVARCHAR: 
      case OdbcDef.SQL_NUMERIC:
      case OdbcDef.SQL_DECIMAL:
      case OdbcDef.SQL_C_BIT: 
      case OdbcDef.SQL_C_TINYINT: 
      case OdbcDef.SQL_SMALLINT:
      case OdbcDef.SQL_INTEGER:
      case OdbcDef.SQL_BIGINT: 
      case OdbcDef.SQL_REAL:
      case OdbcDef.SQL_FLOAT:
      case OdbcDef.SQL_DOUBLE:
      case OdbcDef.SQL_BINARY:
      case OdbcDef.SQL_VARBINARY: 
      case OdbcDef.SQL_LONGVARBINARY: 
      case OdbcDef.SQL_C_DATE:
      case OdbcDef.SQL_C_TIME:
      case OdbcDef.SQL_C_TIMESTAMP:
         break;
      default:
         throw new SQLException(
            "Unknown SQL Type for PreparedStatement.setObject (SQL Type=" +
            type + ")");
      }
      if ((paramIndex + 1) > boundParams.size())
         boundParams.setSize(paramIndex + 1);
      boundParams.set(paramIndex,
                        new PicoBoundParam(OdbcDef.SQL_PARAM_INPUT,
                                           (short) type, scale, obj, cal));
   }

   public void setArray(int paramIndex, Array array) {
      throw new UnsupportedOperationException();
   }

   public void setAsciiStream(int paramIndex, InputStream is, int len)
      throws SQLException {
      throw new UnsupportedOperationException();
   }

   public void setBigDecimal(int paramIndex, BigDecimal num)
          throws SQLException {
      setObject(paramIndex, num, OdbcDef.SQL_NUMERIC, num.scale());
   }

   public void setBinaryStream(int paramIndex, InputStream inputstream, int j)
      throws SQLException {
      throw new UnsupportedOperationException();
   }

   public void setBlob(int paramIndex, Blob blob) {
      throw new UnsupportedOperationException();
   }

   public void setBoolean(int paramIndex, boolean val)
                                        throws SQLException {
      Boolean obj = new Boolean(val);
      setObject(paramIndex, obj, OdbcDef.SQL_BIT, 0);
   }

   public void setByte(int paramIndex, byte byte0) throws SQLException {
      Byte obj = new Byte (byte0);
      setObject(paramIndex, obj, OdbcDef.SQL_TINYINT, 0);
   }

   public void setBytes(int paramIndex, byte abyte0[]) throws SQLException {
      setObject(paramIndex, abyte0, OdbcDef.SQL_TINYINT, 0);
   }

   public void setCharacterStream(int paramIndex, Reader reader, int j) {
      throw new UnsupportedOperationException();
   }

   public void setClob(int paramIndex, Clob clob) {
      throw new UnsupportedOperationException();
   }

   public void setDate(int paramIndex, Date obj) throws SQLException {
      setObject(paramIndex, obj, OdbcDef.SQL_C_DATE, 0);
   }

   public void setDate(int paramIndex, Date obj, Calendar cal)
                                                  throws SQLException {
      setObject(paramIndex, obj, OdbcDef.SQL_C_DATE, 0, cal);
   }

   public void setDecimal(int paramIndex, BigDecimal obj)
                         throws SQLException {
      setObject(paramIndex, obj, OdbcDef.SQL_NUMERIC, obj.scale());
   }

   public void setDouble(int paramIndex, double val) throws SQLException {
      Double obj = new Double(val);
      setObject(paramIndex, obj, OdbcDef.SQL_DOUBLE, 0);
   }

   public void setFloat(int paramIndex, float val) throws SQLException {
      Float obj = new Float(val);
      setObject(paramIndex, obj, OdbcDef.SQL_REAL, 0);
   }

   public void setReal(int paramIndex, float val) throws SQLException {
      Float obj = new Float(val);
      setObject(paramIndex, obj, OdbcDef.SQL_REAL, 0);
   }

   public void setInt(int paramIndex, int val) throws SQLException {
      Integer obj = new Integer(val);
      setObject(paramIndex, obj, OdbcDef.SQL_INTEGER, 0);
   }

   public void setLong(int paramIndex, long val) throws SQLException {
      Integer obj = new Integer((int)val);
      setObject(paramIndex, obj, OdbcDef.SQL_INTEGER, 0);
   }

   public void setNull(int paramIndex, int type) throws SQLException {
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("*PreparedStatement.setNull (" + paramIndex + "," + type + ")");
      setObject(paramIndex, null, type, 0);
   }

   public void setNull(int paramIndex, int type, String s) throws SQLException {
      setObject(paramIndex, null, type, 0);
   }


   public void setRef(int paramIndex, Ref ref) {
      throw new UnsupportedOperationException();
   }

   public void setShort(int paramIndex, short val) throws SQLException {
      Integer obj = new Integer(val);
      setObject(paramIndex, obj, OdbcDef.SQL_SMALLINT, 0);
   }

   public void setString(int paramIndex, String obj) throws SQLException {
      setObject(paramIndex, obj, OdbcDef.SQL_CHAR, 0);
   }

   public void setTime(int paramIndex, Time time) throws SQLException {
      setObject(paramIndex, time, OdbcDef.SQL_C_TIME, 0);
   }

   public void setTime(int paramIndex, Time time, Calendar cal)
                                                       throws SQLException {
      setObject(paramIndex, time, OdbcDef.SQL_C_TIME, 0, cal);
   }

   public void setTimestamp(int paramIndex, Timestamp ts)
                                                        throws SQLException {
      setObject(paramIndex, ts, OdbcDef.SQL_C_TIMESTAMP, 0);
   }

   public void setTimestamp(int paramIndex, Timestamp ts, Calendar cal)
                                                         throws SQLException {
      setObject(paramIndex, ts, OdbcDef.SQL_C_TIMESTAMP, 0, cal);
   }

   public void setUnicodeStream(int paramIndex, InputStream inputstream, int j)
      throws SQLException {
      throw new UnsupportedOperationException();
   }

   public void setURL(int paramIndex, java.net.URL obj) throws SQLException {
      String o = obj.toString();
      setObject(paramIndex, o, getTypeFromObject(o));
   }

   public ParameterMetaData getParameterMetaData () throws SQLException {
      throw new UnsupportedOperationException();
   }
}
