/*
_____       _    _    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.sql.*;
import java.util.*;

public class PicoConnection implements Connection {
   protected PicoDbApi odbcApi;
   protected PicoDriver myDriver;
   protected int hEnv;
   protected OdbcConnection hDbc;
   protected SQLWarning lastWarning;
   protected boolean closed;
   protected String url;
   protected int odbcVer;
   protected String catalog;
   // protected Hashtable typeInfo;
   protected Hashtable statements;

   public PicoConnection(int hE, PicoDriver driver) {
      odbcApi = new PicoDbApi ();
      myDriver = driver;
      hEnv = hE;
      hDbc = null;
      url = null;
      lastWarning = null;
      closed = true;
   }
/*
   protected void buildTypeInfo() throws SQLException {
      typeInfo = new Hashtable();
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("Caching SQL type information");
      ResultSet resultset = getMetaData().getTypeInfo();
      for(boolean flag = resultset.next(); flag; flag = resultset.next()) {
         String s = resultset.getString(1);
         int i = resultset.getInt(2);
         if(typeInfo.get(new Integer(i)) == null) {
            PicoTypeInfo info = new PicoTypeInfo();
            info.setName(s);
            info.setPrec(resultset.getInt(3));
            typeInfo.put(new Integer(i), info);
         }
      }

      resultset.close();
   }
*/

   public void clearWarnings() throws SQLException {
      lastWarning = null;
   }

   public void close() throws SQLException {
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("*Connection.close");
      if(!closed) {
         closeAllStatements();
         myDriver.closeConnection(hDbc);
         hDbc = null;
         odbcApi.finalize ();
         odbcApi = null;
         closed = true;
      }
      url = null;
   }

   public synchronized void closeAllStatements() throws SQLException {
      if(DriverManager.getLogWriter() != null)
         DriverManager.println(statements.size() + " Statement(s) to close");
      if(statements.size() == 0)
         return;
      Statement statement;
      for(Enumeration en = statements.keys(); en.hasMoreElements();
          statement.close())
         statement = (Statement)en.nextElement();
   }

   public void commit() throws SQLException {
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("*Connection.commit");
      odbcApi.SQLTransact(hEnv, hDbc, (short)0);
   }

   public Statement createStatement() throws SQLException {
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("*Connection.createStatement");
      PicoStatement stmt = new PicoStatement(this, odbcApi /* , null */);
      registerStatement(stmt);
      return stmt;
   }

   public Statement createStatement(int rsSetType, int rsSetConurrency) {
      throw new UnsupportedOperationException();
   }

   public Statement createStatement(int rsSetType, int rsSetConurrency,
                                    int rsSetHoldability) {
      throw new UnsupportedOperationException();
   }

   public void deregisterStatement(Statement statement) {
      if(statements.get(statement) != null) {
         if(DriverManager.getLogWriter() != null)
            DriverManager.println("deregistering Statement " + statement);
         statements.remove(statement);
      }
   }

   protected void finalize() {
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("Connection.finalize " + this);
      try {
         close();
      }
      catch(SQLException ex) { }
   }

   public boolean getAutoCommit() throws SQLException {
      boolean Return = false;
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("*Connection.getAutoCommit");
      validateConnection();
      int i = odbcApi.SQLGetConnectOption(hDbc, (short)102);
      if(i == 1)
         Return = true;
      return Return;
   }

   public String getCatalog() throws SQLException {
      return catalog;
   }

   public OdbcConnection getHDBC() {
      return hDbc;
   }

   public DatabaseMetaData getMetaData() throws SQLException {
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("*Connection.getMetaData");
      validateConnection();
      PicoDatabaseMetaData metadata = new PicoDatabaseMetaData(odbcApi, this);
      return metadata;
   }

   public int getTransactionIsolation() throws SQLException {
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("*Connection.getTransactionIsolation");
      validateConnection();
      return odbcApi.SQLGetConnectOption(hDbc, OdbcDef.SQL_TXN_ISOLATION);
   }

   public Map getTypeMap() {
      throw new UnsupportedOperationException();
   }

   public String getURL() {
      return url;
   }

   public SQLWarning getWarnings() throws SQLException {
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("*Connection.getWarnings");
      return lastWarning;
   }

   public void initialize(String dsn, Properties info, int timeOut)
      throws SQLException {
      String user = info.getProperty("user", "");
      String pass = info.getProperty("password", "");

      odbcApi.charSet = info.getProperty("charSet", 
                                         System.getProperty("file.encoding"));
      try {
         hDbc = new OdbcConnection (odbcApi, dsn, user, pass);
/*
      } catch(SQLWarning warn) {
         lastWarning = warn;
*/
      } catch(SQLException ex) {
         try {
            odbcApi.SQLFreeConnect(hDbc);
         } catch(SQLException e1) {
         }
         hDbc = null;
         throw ex;
      }
      closed = false;
      statements = new Hashtable();
      if (DriverManager.getLogWriter() != null) {
         DatabaseMetaData md = getMetaData();
         if (md != null) {
            DriverManager.println("Driver name:   " + md.getDriverName());
            DriverManager.println("Driver version: " + md.getDriverVersion());
         }
      }
      catalog = dsn;
      /* NOT yet impleneted on server side
      if (timeOut > 0) {
         setLoginTimeout(timeOut);
      } */
      // buildTypeInfo();
   }

   public boolean isClosed() throws SQLException {
      return closed;
   }

   public boolean isReadOnly() throws SQLException {
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("*Connection.isReadOnly");
      boolean flag = false;
      validateConnection();
      int i = odbcApi.SQLGetConnectOption(hDbc, (short)101);
      if(i == 1)
         flag = true;
      return flag;
   }

   public String nativeSQL(String s) throws SQLException {
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("*Connection.nativeSQL (" + s + ")");
      throw new UnsupportedOperationException();
   }

   public CallableStatement prepareCall(String s) throws SQLException {
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("*Connection.prepareCall (" + s + ")");
      throw new UnsupportedOperationException();
   }

   public CallableStatement prepareCall(String s, int rsSetType,
                                                  int rsSetConurrency) {
      throw new UnsupportedOperationException();
   }

   public CallableStatement prepareCall(String s, int rsSetType,
                                                  int rsSetConurrency,
                                                  int rsSetHoldability) {
      throw new UnsupportedOperationException();
   }

   public PreparedStatement prepareStatement(String s) throws SQLException {
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("*Connection.prepareStatement (" + s + ")");
      SQLWarning sqlwarning = null;
      PicoPreparedStatement pstmt = 
                      new PicoPreparedStatement(this, odbcApi /* , typeInfo */);
      OdbcStatement hstmt = pstmt.getHSTMT();
      try {
         odbcApi.SQLPrepare(hstmt, s);
      } catch(SQLWarning sqlwarning1) {
         sqlwarning = sqlwarning1;
      } catch(SQLException sqlexception) {
         pstmt.close();
         throw sqlexception;
      }
      pstmt.setWarning(sqlwarning);
      registerStatement(pstmt);
      return pstmt;
   }

   public PreparedStatement prepareStatement(String s, int rsSetType,
                                                       int rsSetConurrency) {
      throw new UnsupportedOperationException();
   }

   public PreparedStatement prepareStatement(String s, int rsSetType,
                                                       int rsSetConurrency,
                                                       int rsSetHoldability) {
      throw new UnsupportedOperationException();
   }

   public PreparedStatement prepareStatement(String s, int autoGeneratedKeys) {
      throw new UnsupportedOperationException();
   }

   public PreparedStatement prepareStatement(String s, int columnIndexes[]) {
      throw new UnsupportedOperationException();
   }

   public PreparedStatement prepareStatement(String s, String columnIndexes[]) {
      throw new UnsupportedOperationException();
   }

   protected void registerStatement(Statement statement) {
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("Registering Statement " + statement);
      statements.put(statement, "");
   }

   public void rollback() throws SQLException {
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("*Connection.rollback");
      odbcApi.SQLTransact(hEnv, hDbc, (short)1);
   }

   public void setAutoCommit(boolean flag) throws SQLException {
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("*Connection.setAutoCommit (" + flag + ")");
      int i = 1;
      validateConnection();
      if(!flag)
         i = 0;
      odbcApi.SQLSetConnectOption(hDbc, OdbcDef.SQL_AUTOCOMMIT, i);
   }

   public void setCatalog(String s) throws SQLException {
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("*Connection.setCatalog (" + s + ")");
      validateConnection();
      odbcApi.SQLSetConnectOption(hDbc, OdbcDef.SQL_CURRENT_QUALIFIER, s);
   }

   protected void setLoginTimeout(int i) throws SQLException {
      odbcApi.SQLSetConnectOption(hDbc, OdbcDef.SQL_LOGIN_TIMEOUT, i);
   }

   public void setReadOnly(boolean flag) throws SQLException {
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("*Connection.setReadOnly (" + flag + ")");
      int i = 0;
      validateConnection();
      if(flag)
         i = 1;
      try {
         odbcApi.SQLSetConnectOption(hDbc, OdbcDef.SQL_ACCESS_MODE, i);
      } catch(SQLException ex) {
         if(DriverManager.getLogWriter() != null)
            DriverManager.println("setReadOnly exception ignored");
      }
   }

   public void setTransactionIsolation(int i) throws SQLException {
      if(DriverManager.getLogWriter() != null)
         DriverManager.println("*Connection.setTransactionIsolation (" + i + ")");
      validateConnection();
      switch(i) {
      case 0: // '\0'
         setAutoCommit(true);
         break;

      case 1: // '\001'
         setAutoCommit(false);
         odbcApi.SQLSetConnectOption(hDbc, OdbcDef.SQL_TXN_ISOLATION,
                                           OdbcDef.SQL_TXN_READ_UNCOMMITTED);
         break;

      case 2: // '\002'
         setAutoCommit(false);
         odbcApi.SQLSetConnectOption(hDbc, OdbcDef.SQL_TXN_ISOLATION,
                                           OdbcDef.SQL_TXN_READ_COMMITTED);
         break;

      case 4: // '\004'
         setAutoCommit(false);
         odbcApi.SQLSetConnectOption(hDbc, OdbcDef.SQL_TXN_ISOLATION,
                                           OdbcDef.SQL_TXN_REPEATABLE_READ);
         break;

      case 8: // '\b'
         setAutoCommit(false);
         odbcApi.SQLSetConnectOption(hDbc, OdbcDef.SQL_TXN_ISOLATION,
                                           OdbcDef.SQL_TXN_SERIALIZABLE);
         break;

      case 3: // '\003'
      case 5: // '\005'
      case 6: // '\006'
      case 7: // '\007'
      default:
         setAutoCommit(false);
         odbcApi.SQLSetConnectOption(hDbc, OdbcDef.SQL_TXN_ISOLATION, i);
         break;

      }
   }

   public void setTypeMap(Map map) {
      throw new UnsupportedOperationException();
   }

   public void setURL(String s) {
      url = s;
   }

   public void validateConnection() throws SQLException {
      if(isClosed())
         throw new SQLException("Connection is closed");
      else
         return;
   }

   public void setHoldability(int holdability) throws SQLException {
      throw new UnsupportedOperationException();
   }

   public int getHoldability() throws SQLException {
      throw new UnsupportedOperationException();
   }

   public Savepoint setSavepoint () {
      throw new UnsupportedOperationException();
   }

   public Savepoint setSavepoint (String name) {
      throw new UnsupportedOperationException();
   }

   public void rollback(Savepoint savepoint) throws SQLException {
      throw new UnsupportedOperationException();
   }

   public void releaseSavepoint (Savepoint savepoint) throws SQLException {
      throw new UnsupportedOperationException();
   }
}
