package WEB-INF.classes.wenrgise.ejb.common.utility;

import java.sql.BatchUpdateException;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Iterator;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import wenrgise.common.exception.EnrgiseSystemException;
import wenrgise.ejb.common.helper.DBObject;
import wenrgise.ejb.common.helper.InputDBObject;
import wenrgise.ejb.common.helper.QueryRow;
import wenrgise.ejb.common.helper.QueryValue;
import wenrgise.ejb.common.utility.ServiceLocator;

public class DBUtilitiesBean {
  private String sDbName = "jdbc/conDS";
  
  private ArrayList oOutParameters = null;
  
  private Connection oCon;
  
  private ResultSet oRs;
  
  private Connection oConn = null;
  
  private DataSource oDataSource = null;
  
  private PreparedStatement oDynamicBatchCall = null;
  
  private CallableStatement oBatchCall = null;
  
  private Connection oBatchCon = null;
  
  private Connection oPreParameterCon = null;
  
  private PreparedStatement oPreParameter = null;
  
  private Connection oPreUpsertCon = null;
  
  private PreparedStatement oPreUpsert = null;
  
  private boolean bDynamic = false;
  
  public DBUtilitiesBean() {}
  
  public DBUtilitiesBean(boolean bDynamic) {
    this.bDynamic = bDynamic;
  }
  
  public void createBatch(String sProcName) throws EnrgiseSystemException {
    InitialContext oInitCont = null;
    String sParam = String.valueOf(String.valueOf("{ call ").concat(String.valueOf(sProcName))).concat(String.valueOf("}"));
    boolean bCreateCoonectionError = false;
    try {
      Object dataSourceObj = ServiceLocator.getLocator().getLocalService(this.sDbName);
      this.oDataSource = (DataSource)dataSourceObj;
      this.oBatchCon = this.oDataSource.getConnection();
      bCreateCoonectionError = true;
      if (!this.bDynamic) {
        if (this.oBatchCall != null) {
          this.oBatchCall.close();
          this.oBatchCall = null;
        } 
        this.oBatchCall = this.oBatchCon.prepareCall(sParam);
        bCreateCoonectionError = false;
      } else {
        if (this.oDynamicBatchCall != null) {
          this.oDynamicBatchCall.close();
          this.oDynamicBatchCall = null;
        } 
        this.oDynamicBatchCall = this.oBatchCon.prepareStatement(sParam);
        bCreateCoonectionError = false;
      } 
    } catch (SQLException oExc) {
      System.out.println(oExc.getMessage());
      throw new EnrgiseSystemException(oExc);
    } finally {
      try {
        if (this.oBatchCon != null && bCreateCoonectionError) {
          if (!this.oBatchCon.isClosed())
            this.oBatchCon.close(); 
          this.oBatchCon = null;
        } 
      } catch (SQLException sQLException) {}
    } 
  }
  
  public void addToBatch(ArrayList oParameters) throws EnrgiseSystemException {
    if (!this.bDynamic) {
      addToProcBatch(oParameters);
    } else {
      addToDynamicBatch(oParameters);
    } 
  }
  
  private void addToDynamicBatch(ArrayList oParameters) throws EnrgiseSystemException {
    try {
      Iterator oIter = oParameters.iterator();
      while (oIter.hasNext()) {
        InputDBObject oObject = oIter.next();
        inspectExecuteParameter(oObject, this.oDynamicBatchCall);
      } 
      this.oBatchCall.addBatch();
    } catch (SQLException oSqlEx) {
      System.out.println(oSqlEx.getMessage());
      throw new EnrgiseSystemException(oSqlEx);
    } finally {
      try {
        if (this.oBatchCon != null) {
          if (!this.oBatchCon.isClosed())
            this.oBatchCon.close(); 
          this.oBatchCon = null;
        } 
      } catch (SQLException sQLException) {}
    } 
  }
  
  private void addToProcBatch(ArrayList oParameters) throws EnrgiseSystemException {
    try {
      Iterator oIter = oParameters.iterator();
      while (oIter.hasNext()) {
        DBObject oObject = oIter.next();
        inspectParameter(oObject, this.oBatchCall);
      } 
      this.oBatchCall.addBatch();
    } catch (SQLException oSqlEx) {
      oSqlEx.printStackTrace();
      System.out.println(oSqlEx.getMessage());
      try {
        if (this.oBatchCon != null)
          if (!this.oBatchCon.isClosed())
            this.oBatchCon.close();  
        this.oBatchCon = null;
      } catch (SQLException sQLException) {}
      throw new EnrgiseSystemException(oSqlEx);
    } 
  }
  
  public void executeBatch() throws EnrgiseSystemException {
    try {
      if (!this.bDynamic) {
        this.oBatchCall.executeBatch();
      } else {
        this.oDynamicBatchCall.executeBatch();
      } 
    } catch (BatchUpdateException oBatchEx) {
      System.out.println("Batch Update Failed");
      System.out.println(String.valueOf(String.valueOf(String.valueOf(String.valueOf(String.valueOf(String.valueOf(String.valueOf(String.valueOf(String.valueOf("Casue ").concat(String.valueOf(oBatchEx.getCause()))).concat(String.valueOf(" Message "))).concat(String.valueOf(oBatchEx.getMessage()))).concat(String.valueOf(" SQL State "))).concat(String.valueOf(oBatchEx.getSQLState()))).concat(String.valueOf(" Update Count "))).concat(String.valueOf(oBatchEx.getUpdateCounts()))).concat(String.valueOf(" SQL Trace "))).concat(String.valueOf(oBatchEx.getStackTrace())));
      throw new EnrgiseSystemException(oBatchEx);
    } catch (SQLException oSqlEx) {
      System.out.println(String.valueOf("dbutilities").concat(String.valueOf(oSqlEx.getMessage())));
      oSqlEx.printStackTrace();
      throw new EnrgiseSystemException(oSqlEx);
    } finally {
      try {
        if (this.oBatchCon != null)
          if (!this.oBatchCon.isClosed())
            this.oBatchCon.close();  
      } catch (SQLException sQLException) {}
    } 
  }
  
  public int executeUpsert(ArrayList oParameters, String sQuery) throws EnrgiseSystemException {
    int iCount = 0;
    try {
      this.oDataSource = (DataSource)ServiceLocator.getLocator().getLocalService(this.sDbName);
      if (this.oPreUpsert != null)
        this.oPreUpsert.close(); 
      if (this.oPreUpsertCon != null) {
        this.oPreUpsertCon.close();
        this.oPreUpsertCon = null;
      } 
      this.oPreUpsertCon = this.oDataSource.getConnection();
      this.oPreUpsert = this.oPreUpsertCon.prepareStatement(sQuery);
      Iterator oIter = oParameters.iterator();
      while (oIter.hasNext()) {
        InputDBObject oObject = oIter.next();
        inspectExecuteParameter(oObject, this.oPreUpsert);
      } 
      iCount = this.oPreUpsert.executeUpdate();
      while (true);
    } catch (Exception oExc) {
      System.out.println(oExc.getMessage());
      oExc.printStackTrace();
      throw new EnrgiseSystemException(oExc);
    } finally {
      try {
        if (this.oPreUpsertCon != null) {
          if (!this.oPreUpsertCon.isClosed())
            this.oPreUpsertCon.close(); 
          this.oPreUpsertCon = null;
        } 
      } catch (SQLException oSqlEx) {
        System.out.println(oSqlEx.getMessage());
        throw new EnrgiseSystemException(oSqlEx);
      } 
      return iCount;
    } 
  }
  
  public ArrayList executeQuery(ArrayList oParameters, String sQuery) throws EnrgiseSystemException {
    ResultSet oRs = null;
    ArrayList oResult = null;
    try {
      this.oDataSource = (DataSource)ServiceLocator.getLocator().getLocalService(this.sDbName);
      if (oRs != null) {
        oRs.close();
        oRs = null;
      } 
      if (this.oPreParameter != null)
        this.oPreParameter.close(); 
      if (this.oPreParameterCon != null) {
        this.oPreParameterCon.close();
        this.oPreParameterCon = null;
      } 
      this.oPreParameterCon = this.oDataSource.getConnection();
      this.oPreParameter = this.oPreParameterCon.prepareStatement(sQuery);
      Iterator oIter = oParameters.iterator();
      while (oIter.hasNext()) {
        InputDBObject oObject = oIter.next();
        inspectExecuteParameter(oObject, this.oPreParameter);
      } 
      oRs = this.oPreParameter.executeQuery();
      if (oRs == null)
        throw new EnrgiseSystemException(); 
      oResult = convertToList(oRs);
      while (true);
    } catch (Exception oExc) {
      System.out.println(oExc.getMessage());
      oExc.printStackTrace();
      throw new EnrgiseSystemException(oExc);
    } finally {
      try {
        if (this.oPreParameterCon != null)
          if (this.oPreParameterCon.isClosed())
            this.oPreParameterCon.close();  
      } catch (SQLException oSqlEx) {
        System.out.println(oSqlEx.getMessage());
        throw new EnrgiseSystemException(oSqlEx);
      } 
      return oResult;
    } 
  }
  
  public ArrayList callProc(ArrayList oParameters, String sProcName) throws EnrgiseSystemException {
    CallableStatement oCall = null;
    if (this.oOutParameters == null) {
      this.oOutParameters = new ArrayList();
    } else {
      this.oOutParameters.clear();
    } 
    try {
      Object datasourceObj = null;
      datasourceObj = ServiceLocator.getLocator().getLocalService(this.sDbName);
      this.oDataSource = (DataSource)datasourceObj;
      Object conObj = this.oDataSource.getConnection();
      this.oCon = (Connection)conObj;
      if (oCall != null)
        oCall.close(); 
      String sParam = String.valueOf(String.valueOf("{ call ").concat(String.valueOf(sProcName))).concat(String.valueOf("}"));
      Object callObj = this.oCon.prepareCall(sParam);
      oCall = (CallableStatement)callObj;
      Iterator oIter = oParameters.iterator();
      while (oIter.hasNext()) {
        DBObject oObject = oIter.next();
        inspectParameter(oObject, oCall);
      } 
      oCall.execute();
      Iterator oOutIter = this.oOutParameters.iterator();
      while (oOutIter.hasNext())
        getOutParameters(oOutIter.next(), oCall); 
      if (this.oOutParameters.size() >= 3) {
        DBObject oErrLog = this.oOutParameters.get(this.oOutParameters.size() - 3);
        String sErrorLog = (String)oErrLog.getObject();
        DBObject oErrMessage = this.oOutParameters.get(this.oOutParameters.size() - 2);
        String sErrorMessage = (String)oErrLog.getObject();
        DBObject oErr = this.oOutParameters.get(this.oOutParameters.size() - 1);
        Integer oErrorCode = (Integer)oErr.getObject();
        if (null != oErrorCode && !oErrorCode.equals(new Integer(0))) {
          System.out.println(String.valueOf("Error calling procedure ").concat(String.valueOf(sProcName)));
          if (null != sErrorLog)
            System.out.println(String.valueOf("Error Log ").concat(String.valueOf(sErrorLog))); 
          if (null != sErrorMessage)
            System.out.println(String.valueOf("Error Message ").concat(String.valueOf(sErrorMessage))); 
          throw new EnrgiseSystemException();
        } 
      } 
      return this.oOutParameters;
    } catch (Exception oExc) {
      System.out.println(oExc.getMessage());
      oExc.printStackTrace();
      throw new EnrgiseSystemException(oExc);
    } finally {
      try {
        if (this.oCon != null) {
          if (!this.oCon.isClosed())
            this.oCon.close(); 
          this.oCon = null;
        } 
      } catch (Exception exception) {}
    } 
  }
  
  public ArrayList executeQuery(String sQuery) throws EnrgiseSystemException {
    PreparedStatement oPre = null;
    ArrayList oResult = null;
    try {
      this.oDataSource = (DataSource)ServiceLocator.getLocator().getLocalService(this.sDbName);
      if (this.oRs != null) {
        this.oRs.close();
        this.oRs = null;
      } 
      if (oPre != null)
        oPre.close(); 
      if (this.oConn != null) {
        this.oConn.close();
        this.oConn = null;
      } 
      this.oConn = this.oDataSource.getConnection();
      oPre = this.oConn.prepareStatement(sQuery);
      this.oRs = oPre.executeQuery();
      oResult = convertToList(this.oRs);
      while (true);
    } catch (SQLException oExc) {
      System.out.println(String.valueOf(String.valueOf(String.valueOf("From DBUtility ").concat(String.valueOf(oExc.getClass().getName()))).concat(String.valueOf(" "))).concat(String.valueOf(oExc.getMessage())));
      throw new EnrgiseSystemException(oExc);
    } finally {
      try {
        if (this.oConn != null)
          if (!this.oConn.isClosed())
            this.oConn.close();  
      } catch (SQLException oSqEx) {
        throw new EnrgiseSystemException(oSqEx);
      } 
      return oResult;
    } 
  }
  
  public int executeUpsert(String sQuery) throws EnrgiseSystemException {
    PreparedStatement oPre = null;
    Connection oPreCon = null;
    int iCount = 0;
    try {
      this.oDataSource = (DataSource)ServiceLocator.getLocator().getLocalService(this.sDbName);
      if (oPre != null)
        oPre.close(); 
      oPreCon = this.oDataSource.getConnection();
      oPre = oPreCon.prepareStatement(sQuery);
      iCount = oPre.executeUpdate();
      while (true);
    } catch (SQLException oExc) {
      System.out.println(String.valueOf(String.valueOf(String.valueOf("From DBUtility ").concat(String.valueOf(oExc.getClass().getName()))).concat(String.valueOf(" "))).concat(String.valueOf(oExc.getMessage())));
      throw new EnrgiseSystemException(oExc);
    } finally {
      try {
        if (oPreCon != null)
          if (!oPreCon.isClosed())
            oPreCon.close();  
      } catch (SQLException oSqEx) {
        throw new EnrgiseSystemException(oSqEx);
      } 
      return iCount;
    } 
  }
  
  private void inspectParameter(DBObject oDBObject, CallableStatement oCall) throws SQLException {
    int iPosition = oDBObject.getPosition();
    int iDirection = oDBObject.getDirection();
    int iDataType = oDBObject.getDataType();
    if (iDirection == 1 || iDirection == 3) {
      Object oObject = oDBObject.getObject();
      switch (iDataType) {
        case 12:
          if (oObject != null) {
            oCall.setString(iPosition, oObject.toString());
            break;
          } 
          oCall.setString(iPosition, (String)null);
          break;
        case 4:
          if (oObject != null) {
            oCall.setInt(iPosition, Integer.parseInt(oObject.toString()));
            break;
          } 
          oCall.setInt(iPosition, 0);
          break;
        case 8:
          if (oObject != null) {
            oCall.setDouble(iPosition, Double.parseDouble(oObject.toString()));
            break;
          } 
          oCall.setDouble(iPosition, 0.0D);
          break;
        case -5:
          if (oObject != null) {
            oCall.setLong(iPosition, ((Long)oObject).longValue());
            break;
          } 
          oCall.setLong(iPosition, 0L);
          break;
        case 91:
          if (oObject != null) {
            oCall.setDate(iPosition, (Date)oObject);
            break;
          } 
          oCall.setDate(iPosition, (Date)null);
          break;
        case 93:
          if (oObject != null) {
            oCall.setTimestamp(iPosition, (Timestamp)oObject);
            break;
          } 
          oCall.setTimestamp(iPosition, (Timestamp)null);
          break;
        case 2000:
          if (oObject != null) {
            oCall.setObject(iPosition, oObject);
            break;
          } 
          oCall.setObject(iPosition, (Object)null);
          break;
      } 
    } 
    if (iDirection == 2 || iDirection == 3) {
      oCall.registerOutParameter(iPosition, iDataType);
      this.oOutParameters.add(new DBObject(iPosition, iDataType));
    } 
  }
  
  private void inspectExecuteParameter(InputDBObject oDBObject, PreparedStatement oCall) throws SQLException {
    int iPosition = oDBObject.getPosition();
    int iDataType = oDBObject.getDataType();
    Object oObject = oDBObject.getObject();
    switch (iDataType) {
      case 12:
        if (oObject != null) {
          oCall.setString(iPosition, oObject.toString());
          break;
        } 
        oCall.setString(iPosition, (String)null);
        break;
      case 1:
        if (oObject != null) {
          oCall.setString(iPosition, oObject.toString());
          break;
        } 
        oCall.setString(iPosition, (String)null);
        break;
      case 4:
        if (oObject != null) {
          oCall.setInt(iPosition, Integer.parseInt(oObject.toString()));
          break;
        } 
        oCall.setInt(iPosition, 0);
        break;
      case 8:
        if (oObject != null) {
          oCall.setDouble(iPosition, Double.parseDouble(oObject.toString()));
          break;
        } 
        oCall.setDouble(iPosition, 0.0D);
        break;
      case -5:
        if (oObject != null) {
          oCall.setLong(iPosition, ((Long)oObject).longValue());
          break;
        } 
        oCall.setLong(iPosition, 0L);
        break;
      case 91:
        if (oObject != null) {
          oCall.setDate(iPosition, (Date)oObject);
          break;
        } 
        oCall.setDate(iPosition, (Date)null);
        break;
      case 93:
        if (oObject != null) {
          oCall.setTimestamp(iPosition, (Timestamp)oObject);
          break;
        } 
        oCall.setTimestamp(iPosition, (Timestamp)null);
        break;
      case 2000:
        oCall.setObject(iPosition, oObject);
        break;
    } 
  }
  
  private void getOutParameters(DBObject oOutDBObject, CallableStatement oCall) throws SQLException {
    int iPosition = oOutDBObject.getPosition();
    int iDataType = oOutDBObject.getDataType();
    switch (iDataType) {
      case 12:
        oOutDBObject.setObject(oCall.getString(iPosition));
        break;
      case 1:
        oOutDBObject.setObject(oCall.getString(iPosition));
        break;
      case 4:
        oOutDBObject.setObject(new Integer(oCall.getInt(iPosition)));
        break;
      case -5:
        oOutDBObject.setObject(new Long(oCall.getLong(iPosition)));
        break;
      case 8:
        oOutDBObject.setObject(new Double(oCall.getDouble(iPosition)));
        break;
      case 91:
        oOutDBObject.setObject(oCall.getDate(iPosition));
        break;
      case 93:
        oOutDBObject.setObject(oCall.getTimestamp(iPosition));
        break;
      case 2000:
        oOutDBObject.setObject(oCall.getObject(iPosition));
        break;
      case -10:
        oOutDBObject.setObject(convertToList((ResultSet)oCall.getObject(iPosition)));
        break;
    } 
  }
  
  private ArrayList convertToList(ResultSet oRs2) throws SQLException {
    if (null == oRs2)
      return null; 
    ResultSetMetaData oRsMt = oRs2.getMetaData();
    int iColumnCount = oRsMt.getColumnCount();
    int iIndex = 0;
    ArrayList oList = new ArrayList();
    String[] sColumnName = new String[iColumnCount];
    int[] iColumnType = new int[iColumnCount];
    for (iIndex = 0; iIndex < iColumnCount; iIndex++) {
      sColumnName[iIndex] = oRsMt.getColumnName(iIndex + 1);
      iColumnType[iIndex] = oRsMt.getColumnType(iIndex + 1);
    } 
    while (oRs2.next()) {
      QueryRow oRow = new QueryRow(iColumnCount);
      for (iIndex = 0; iIndex < iColumnCount; iIndex++) {
        QueryValue oValue = new QueryValue();
        setValue(sColumnName[iIndex], iColumnType[iIndex], oValue, oRs2);
        oRow.getRow().put(sColumnName[iIndex].toUpperCase(), oValue);
      } 
      oList.add(oRow);
    } 
    oRs2.close();
    oRs2 = null;
    return oList;
  }
  
  private void setValue(String sColumnName, int iColumnType, QueryValue oValue, ResultSet oRs2) throws SQLException {
    switch (iColumnType) {
      case 2:
        oValue.setString(oRs2.getString(sColumnName));
        break;
      case 12:
        oValue.setString(oRs2.getString(sColumnName));
        break;
      case 1:
        oValue.setString(oRs2.getString(sColumnName));
        break;
      case 4:
        oValue.setInt(oRs2.getInt(sColumnName));
        break;
      case -5:
        oValue.setLong(oRs2.getLong(sColumnName));
        break;
      case 8:
        oValue.setDouble(oRs2.getDouble(sColumnName));
        break;
      case 91:
        oValue.setDate(oRs2.getDate(sColumnName));
        break;
      case 93:
        oValue.setTimestamp(oRs2.getTimestamp(sColumnName));
        break;
      case 2004:
        oValue.setBlob(oRs2.getBlob(sColumnName));
        break;
      case 2005:
        oValue.setClob(oRs2.getClob(sColumnName));
        break;
    } 
  }
  
  protected void finalize() {
    try {
      close();
    } catch (SQLException sQLException) {}
  }
  
  private void close() throws SQLException {
    if (this.oCon != null) {
      if (!this.oCon.isClosed())
        this.oCon.close(); 
      this.oCon = null;
    } 
    if (this.oConn != null) {
      if (!this.oConn.isClosed())
        this.oConn.close(); 
      this.oConn = null;
    } 
  }
}
