/* $Id: MySQLOrganizationManagerDAO.java,v 1.1 2007/10/29 02:55:36 nito 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.mysql;

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をデータとするMySQL用DAOクラスである。
 * <pre><tt>
 * 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>
 * ORGUSERMAPテーブル
 * +---------+-------------+------+-----+---------+-------+
 * | Field   | Type        | Null | Key | Default | Extra |
 * +---------+-------------+------+-----+---------+-------+
 * | ORG_ID  | varchar(64) |      | PRI |         |       |
 * | USER_ID | varchar(64) |      | PRI |         |       |
 * +---------+-------------+------+-----+---------+-------+
 * </tt></pre>
 * 属性は、カラム名をキー値としている。
 * カラム名の大文字小文字に関わらず、属性のキー値は大文字で設定される。
 * 
 * @author  mmanabe(Argo 21, Corp.)
 * @version $Revision: 1.1 $
 * @since   Nautica Workflow 1.0
 */
public class MySQLOrganizationManagerDAO 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";
    
    private static final String SQL_SELECT_BY_ORG_ID
        = "select * from ORGANIZATION where ORG_ID = ?";
    
    private static final String SQL_SELECT_USERS_BY_ORG_ID
        = "select USER.* from USER, ORGUSERMAP" +
          " where ORGUSERMAP.ORG_ID = ? and USER.USER_ID = ORGUSERMAP.USER_ID;";
    
    private static final String SQL_SELECT_BY_USER_ID
        = "select ORGANIZATION.* from ORGANIZATION, ORGUSERMAP" +
          " where ORGUSERMAP.USER_ID = ? and ORGANIZATION.ORG_ID = ORGUSERMAP.ORG_ID;";
    
    private static final String SQL_SELECT_HIGHER_BY_ORG_ID
        = "SELECT ORG_HIGH.* FROM ORGANIZATION ORG_HIGH, ORGANIZATION ORG_LOW" + 
          " WHERE ORG_HIGH.ORG_ID = ORG_LOW.HIGHER_ORG_ID" + 
          " AND ORG_LOW.ORG_ID = ?";
    
    /**
     * 組織関連テーブルに対するアクセスオブジェクトを生成する。
     * 
     * @param conn コネクション
     */
    MySQLOrganizationManagerDAO(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(MySQLUserManagerDAO.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 {
        
        /* カラム名取得 */
        List<String> columnNames = new ArrayList<String>();
        for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
            columnNames.add(rs.getMetaData().getColumnName(i));
        }

        OrganizationBean bean = new OrganizationBean();
        for (int i = 0; i < columnNames.size(); i++) {
            String columnName = ((String) columnNames.get(i)).toUpperCase();
            String attribute = (String) rs.getObject(columnName);

            /* 組織ID設定 */
            if (columnName.equals(ORG_ID)) {
                bean.setID(attribute);
            }
            
            /* 組織名設定 */
            if (columnName.equals(ORG_NAME)) {
                bean.setName(attribute);                
            }

            /* 組織ID、組織名以外の情報を組織情報に設定 */
            if (!columnName.equals(ORG_ID)
                    && !columnName.equals(ORG_NAME)) {
                bean.setAttribute(columnName, attribute);
            }
        }
        return bean;
    }
}