package com.eactive.eai.common.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.sql.DataSource;


import com.eactive.eai.common.exception.ExceptionUtil;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.common.util.ServiceLocator;

/**
* 1. 기능 : DB Access 관련 로직을 구현하기 위한 DAO 클래스의 기본 기능을 갖는 Base 클래스
* 2. 처리 개요 : DB Access 관련 로직을 구현하기 위한 DAO 클래스의 기본 기능을 갖는 Base 클래스를 정의한다.
* *     -
* 3. 주의사항
*
* @author  :
* @version : v 1.0.0
* @see : 관련 기능을 참조
* @since   :
*/
public abstract class BaseDAO
{
    /**
     * JDBC Connection object
     */
    protected Connection conn;
    /**
     * JDBC PreparedStatement
     */
    protected PreparedStatement preparedStatement;
    /**
     * JDBC DataSource의 JNDI 이름
     */
    protected String jndiName;

    protected Logger logger;

    protected static boolean isApplication;

    static {
        String wlServer = System.getProperty("weblogic.Name");
		isApplication = (wlServer==null)? true : false;
    }

    /**
    * 1. 기능 :  Default Constructor
    * 2. 처리 개요 : jndiName을 Keys.EAI_DATASOURCE로 초기화한다.
    * 3. 주의사항
    *
    **/
    public BaseDAO() {
        this.jndiName = Keys.EAI_DATASOURCE;
		this.logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
    }

    /**
    * 1. 기능 :  jndiDataSource 이름을 초기화하기 위한 setter 메서드
    * 2. 처리 개요 : jndiDataSource 이름을 초기화한다.
    *     -
    * 3. 주의사항
    *
    * @param jndiDataSource JDBCDataSource의 jndi 이름
    **/
    protected void setJNDIName(String jndiDataSource) {
        this.jndiName = jndiDataSource;
    }

    /**
    * 1. 기능 :  JDBC Connection 을 생성하는 메서드
    * 2. 처리 개요 : JDBC DataSource를 JNDI 서비스로 부터 얻어 Connection 객체를 생성 초기화하고,
    *       Connection으로 부터 PreparedStatement를 얻어 초기화한다.
    *
    * 3. 주의사항
    *
    * @param    query   실행한 SQL Query
    * @exception    DAOException    Connection 및 PreparedStatement를 생성 초기화 할때 발생하는 오류
    **/
    protected void connect(String query) throws DAOException {
        try {
			if (conn != null && !conn.isClosed()) {
				logger.warn("★★★★★ Connection 이 이미 연결되어있습니다. 기존 Connection의 PreparedStatement를 재설정합니다.");
				closeStatement();
			} else {
				ServiceLocator sl = ServiceLocator.getInstance();
				DataSource dataSource = sl.getDataSource(jndiName);
				
				conn = dataSource.getConnection();
			}
            
            preparedStatement = conn.prepareStatement(query);

		} catch(Exception e) {
			logger.error("BaseDAO:connect 시 에러 발생["+ e.toString() + "]");
            throw new DAOException("BaseDAO:connect 시 에러 발생["+ e.toString() + "]");
        }
    }

    /**
    * 1. 기능 :  JDBC Connection 을 생성하는 메서드
    * 2. 처리 개요 : JDBC DataSource를 JNDI 서비스로 부터 얻어 Connection 객체를 생성 초기화하고,
    *       Connection으로 부터 PreparedStatement를 얻어 초기화한다.
    *     -
    * 3. 주의사항
    *
    * @param    providerURL   DataSource가 Remote 서버에 있을 경우 Remote 서버의 URL
    * @param    query   실행한 SQL Query
    * @exception    DAOException    Connection 및 PreparedStatement를 생성 초기화 할때 발생하는 오류
    **/
    protected void connect(String providerURL, String query) throws DAOException {
        try {
			if (conn != null && !conn.isClosed()) {
				logger.warn("★★★★★ Connection 이 이미 연결되어있습니다. 기존 Connection의 PreparedStatement를 재설정합니다.");
				closeStatement();

			} else {
				ServiceLocator sl = ServiceLocator.getInstance();
				DataSource dataSource = sl.getRemoteDataSource(providerURL, jndiName);
				conn = dataSource.getConnection();
			}

            preparedStatement = conn.prepareStatement(query);
		} catch(Exception e) {
			logger.error("BaseDAO:connect 시 에러 발생["+ e.toString() + "]");
            throw new DAOException("BaseDAO:connect 시 에러 발생["+ e.toString() + "]");
        }
    }

    /**
    * 1. 기능 :  초기화된 SQL Query를 실행하여 결과에 접근하기 위한 ResultSet을 반환하는 메서드
    * 2. 처리 개요 : PreparedStatement의 executeQuery를 실행하고 결과값인 ResultSet을 반환한다.
    *     -
    * 3. 주의사항
    *
    * @return   SELECT Query 결과
    * @exception    DAOException    SQLException 발생 시
    **/
    protected ResultSet executeQuery() throws DAOException {
        try {
            ResultSet rs = preparedStatement.executeQuery();
            return rs;
        } catch(SQLException e) {
            throw new DAOException(ExceptionUtil.getErrorCode(e, "BECEAICDB102"));
        }
    }

    /**
    * 1. 기능 :  초기화된 SQL Query를 실행하여 결과에 접근하기 위한 ResultSet을 반환하는 메서드
    * 2. 처리 개요 : PreparedStatement의 executeUpdate를 실행하고 결과값인 변경된 record 수를 반환한다.
    *     -
    * 3. 주의사항
    *
    * @return   변경된 Record 수
    * @exception    DAOException    SQLException 발생 시
   **/
    protected int executeUpdate() throws DAOException {
        try {
            int result = preparedStatement.executeUpdate();
            return result;
        } catch(SQLException e) {
            throw new DAOException(ExceptionUtil.getErrorCode(e, "BECEAICDB103"));
        }
    }

    /**
    * 1. 기능 :  PreparedStatement를 재 초기화하는 메서드
    * 2. 처리 개요 : 기존 PreparedStatement를 close하고, 새로운 PreparedStatement를 생성 초기화한다.
    *     -
    * 3. 주의사항
    *
    * @param    query   PreparedStatement초기화하기 위한 SQL Query
    * @exception    DAOException    PreparedStatemnt를 생성하다 발생하는 SQLException
    **/
    protected void prepareStatement(String query) throws DAOException {
        try {
            closeStatement();
            preparedStatement = conn.prepareStatement(query);
            
        } catch(Exception e) {
            throw new DAOException(ExceptionUtil.getErrorCode(e, "BECEAICDB104"));
        }
    }

    /**
    * 1. 기능 :  생성한 Connection과 PreparedStatement를 close하는 메서드
    * 2. 처리 개요 : 생성한 Connection,PreparedStatement를 close 한다.
    *     -
    * 3. 주의사항
    *
    * @exception    DAOException
    **/
    protected void disconnect() throws DAOException{
        closeStatement();
        closeConnection();
    }

    /**
    * 1. 기능 : 생성한 PreparedStatement를 close하는 메서드
    * 2. 처리 개요 : 생성한 PreparedStatement를 close한다.
    *     -
    * 3. 주의사항
    *
    * @exception    DAOException
    **/
    protected void closeStatement() throws DAOException  {
        if (preparedStatement != null) {
            try {   preparedStatement.close(); } catch(Exception e) {throw new DAOException("BECEAICDB107");}
        }
    }

    /**
    * 1. 기능 : 생성한 Connection를 close하는 메서드
    * 2. 처리 개요 : 생성한 Connection를 close한다.
    *     -
    * 3. 주의사항
    *
    * @exception    DAOException
    **/
    protected void closeConnection() throws DAOException{

    	try {
			if (conn != null) conn.close();
        } catch (Exception e) {
            throw new DAOException("BECEAICDB108");
        }
    }
}
