/* $Id: DerbyOrganizationManagerDAO.java,v 1.4 2007/11/28 08:13:36 knakata Exp $
 *
 * Copyright (c)ARGO 21, Corporation. 2005, 2006.  All rights reserved.
 * 
 * This file is part of Nautica Workflow Core.
 * 
 *  Nautica Workflow Core is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation; either version 2.1 of the License, or
 *  (at your option) any later version.
 * 
 *  Nautica Workflow Core 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 Lesser General Public License for more details.
 * 
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with Nautica Workflow Core; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *  
 */
package jp.co.argo21.nautica.workflow.dataaccess.derby;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;

import jp.co.argo21.nautica.workflow.dataaccess.AbstractDAO;
import jp.co.argo21.nautica.workflow.dataaccess.OrganizationBean;
import jp.co.argo21.nautica.workflow.dataaccess.OrganizationManagerDAO;
import jp.co.argo21.nautica.workflow.dataaccess.UserBean;
import jp.co.argo21.nautica.workflow.engine.LogManager;

/**
 * OrganizationBeanをデータとするDerby用DAOクラスである。
 * <pre><tt>
 * WF_ORGANIZATIONテーブル
 * +----------------+--------------+------+-----+---------+-------+
 * | Field          | Type         | Null | Key | Default | Extra |
 * +----------------+--------------+------+-----+---------+-------+
 * | ORG_ID         | varchar(64)  |      | PRI |         |       |
 * | ORG_NAME       | varchar(128) |      |     |         |       |
 * | RESPONSIBLE_ID | varchar(64)  | YES  | MUL | NULL    |       |
 * | HIGHER_ORG_ID  | varchar(64)  | YES  | MUL | NULL    |       |
 * +----------------+--------------+------+-----+---------+-------+
 * </tt>
 * <tt>
 * WF_ORGUSERMAPテーブル
 * +---------+-------------+------+-----+---------+-------+
 * | Field   | Type        | Null | Key | Default | Extra |
 * +---------+-------------+------+-----+---------+-------+
 * | ORG_ID  | varchar(64) |      | PRI |         |       |
 * | USER_ID | varchar(64) |      | PRI |         |       |
 * +---------+-------------+------+-----+---------+-------+
 * </tt></pre>
 * 属性は、カラム名をキー値としている。
 * カラム名の大文字小文字に関わらず、属性のキー値は大文字で設定される。
 * 
 * @author  knakata(Argo 21, Corp.)
 * @version $Revision: 1.4 $
 * @since   Nautica Workflow 1.0
 */
public class DerbyOrganizationManagerDAO extends AbstractDAO 
implements OrganizationManagerDAO
{
	/** エンジンログ */
	protected static Logger eLog = LogManager.getEngineLogger();
	
	/** 組織IDのカラム名 */
	private static final String ORG_ID = "ORG_ID";
	/** 組織名のカラム名 */
	private static final String ORG_NAME = "ORG_NAME";
	/** 上位組織IDのカラム名 */
	private static final String HIGHER_ORG_ID = "HIGHER_ORG_ID";
    
    private static final String SQL_SELECT_BY_ORG_ID
        = "select * from WF_ORGANIZATION where ORG_ID = ? ";
    
    private static final String SQL_SELECT_USERS_BY_ORG_ID
        = "select U.* from WF_USER U, WF_ORGUSERMAP OUM " +
          "where OUM.ORG_ID = ? and U.USER_ID = OUM.USER_ID ";
    
    private static final String SQL_SELECT_BY_USER_ID
        = "select O.* from WF_ORGANIZATION O, WF_ORGUSERMAP OUM " +
          "where OUM.USER_ID = ? and O.ORG_ID = OUM.ORG_ID ";
    
    private static final String SQL_SELECT_HIGHER_BY_ORG_ID
        = "SELECT ORG_HIGH.* FROM WF_ORGANIZATION ORG_HIGH, WF_ORGANIZATION ORG_LOW " + 
          "WHERE ORG_HIGH.ORG_ID = ORG_LOW.HIGHER_ORG_ID " + 
          "AND ORG_LOW.ORG_ID = ? ";
    
    /**
     * 組織関連テーブルに対するアクセスオブジェクトを生成する。
     * 
     * @param conn コネクション
     */
    DerbyOrganizationManagerDAO(Connection conn) {
        super(conn);
    }

    /**
     * 指定された組織IDの組織情報を返す。
     * 該当する組織情報が存在しない場合は null を返す。
     * 
     * @param  oid 組織ID
     * @return 指定された組織IDの情報を持つOrganizationBean
	 * @throws SQLException 任意のSQL例外
     * @see jp.co.argo21.nautica.workflow.dataaccess.OrganizationManagerDAO#findByOrganizationID(java.lang.String)
     */
    public OrganizationBean findByOrganizationID(String oid) 
    throws SQLException {
        
        PreparedStatement st = getConnection().prepareStatement(SQL_SELECT_BY_ORG_ID);
		try {
			st.setString(1, oid);

			/************** DEBUG **************/
			eLog.debug(st.toString());
			/***********************************/

			ResultSet rs = st.executeQuery();
			
			OrganizationBean bean = null;
			if (rs.next()) {
			    bean = createBean(rs);
			}
			
			return bean;
			
		} finally {
			st.close();
		}
    }

    /**
     * 指定された組織のユーザ情報の配列を返す。
     * 該当するユーザ情報が存在しない場合は空の配列を返す。
     * 
     * @param  oid 組織ID
     * @return 指定された組織に所属するユーザ情報を持つUserBeanの配列
	 * @throws SQLException 任意のSQL例外
     * @see jp.co.argo21.nautica.workflow.dataaccess.OrganizationManagerDAO#findUsersByOrganizationID(java.lang.String)
     */
    public UserBean[] findUsersByOrganizationID(String oid)
    throws SQLException {
        
        PreparedStatement st = getConnection().prepareStatement(SQL_SELECT_USERS_BY_ORG_ID);
		try {
			st.setString(1, oid);			

			/************** DEBUG **************/
			eLog.debug(st.toString());
			/***********************************/

			ResultSet rs = st.executeQuery();
						
			List<UserBean> beanList = new ArrayList<UserBean>();
			while (rs.next()) {
				beanList.add(DerbyUserManagerDAO.createBean(rs));
			}
			
			return (UserBean[]) beanList.toArray(new UserBean[beanList.size()]);
			
		} finally {
			st.close();
		}
    }

    /**
     * 指定されたユーザの所属する組織情報の配列を返す。
     * 該当する組織情報が存在しない場合は空の配列を返す。
     * 
     * @param  uid ユーザID
     * @return 指定されたユーザが所属する組織情報を持つOrganizationBeanの配列
	 * @throws SQLException 任意のSQL例外
     * @see jp.co.argo21.nautica.workflow.dataaccess.OrganizationManagerDAO#findByUserID(java.lang.String)
     */
    public OrganizationBean[] findByUserID(String uid) 
    throws SQLException {
        
        PreparedStatement st = getConnection().prepareStatement(SQL_SELECT_BY_USER_ID);
		try {
			st.setString(1, uid);

			/************** DEBUG **************/
			eLog.debug(st.toString());
			/***********************************/

			ResultSet rs = st.executeQuery();
			
			List<OrganizationBean> beanList = new ArrayList<OrganizationBean>();
			while (rs.next()) {
				beanList.add(createBean(rs));
			}	
			
			return (OrganizationBean[]) beanList.toArray(new OrganizationBean[beanList.size()]);
			
		} finally {
			st.close();
		}
    }

    /**
     * 指定された組織の上位組織情報を返す。
	 * 該当する上位組織情報が存在しない場合は null を返す。
     * 
     * @param oid 組織ID
     * @return OrganizationBean
	 * @throws SQLException 任意のSQL例外
     * @see jp.co.argo21.nautica.workflow.dataaccess.OrganizationManagerDAO#findHigherByOrganizationID(java.lang.String)
     */
    public OrganizationBean findHigherByOrganizationID(String oid)
    throws SQLException {

        PreparedStatement st = getConnection().prepareStatement(SQL_SELECT_HIGHER_BY_ORG_ID);
		try {
			st.setString(1, oid);

			/************** DEBUG **************/
			eLog.debug(st.toString());
			/***********************************/

			ResultSet rs = st.executeQuery();
			
			OrganizationBean bean = null;
			if (rs.next()) {
			    bean = createBean(rs);
			}
			
			return bean;
						
		} finally {
			st.close();
		}
    }
    
    /**
     * ResultSet中の情報からOrganizationBeanを作成する。
     * 
     * @param  rs ResultSet
     * @return ResultSetから取得した情報を持つOrganizationBean
	 * @throws SQLException 任意のSQL例外
     */
    static OrganizationBean createBean(ResultSet rs)
    throws SQLException
    {
    	OrganizationBean bean = new OrganizationBean();
    	
    	bean.setID(rs.getString(ORG_ID));
    	bean.setName(rs.getString(ORG_NAME));
    	bean.setAttribute(HIGHER_ORG_ID, rs.getString(HIGHER_ORG_ID));
    	
    	return bean;
    }
}