package org.maachang.dao.dbms;

import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.maachang.dao.MaachangDaoException;

/**
 * Metaカラムファクトリ.
 * 
 * @version 2008/08/19
 * @author masahito suzuki
 * @since MaachangDao 1.00
 */
public class MetaFactory {
    
    /**
     * シングルトン.
     */
    private static final MetaFactory SNGL = new MetaFactory() ;
    
    /**
     * レコードファクトリ.
     */
    private RecordFactory recordFactory = null ;
    
    /**
     * 管理オブジェクト.
     */
    private Map<String,MetaColumn> map = null ;
    
    /**
     * オブジェクトを取得.
     * @return MetaFactory オブジェクトが返されます.
     */
    public static final MetaFactory getInstance() {
        return SNGL ;
    }
    
    /**
     * コンストラクタ.
     */
    private MetaFactory() {
        //this.map = new HashMap<String,MetaColumn>() ;
        this.map = Collections.synchronizedMap( new HashMap<String,MetaColumn>() ) ;
    }
    
    /**
     * レコードファクトリを設定.
     * @param recordFactory レコードファクトリを設定します.
     */
    public void init( RecordFactory recordFactory ) {
        this.recordFactory = recordFactory ;
    }
    
    /**
     * 指定テーブルに対するメタカラムを取得.
     */
    private MetaColumn createMetaColumn( String table )
        throws Exception {
        Connection conn = null ;
        ResultSet r = null ;
        try {
            conn = recordFactory.getConnectionManager().getConnection();
            if (conn == null) {
                throw new IOException("コネクションオブジェクトの取得に失敗しました");
            }
            r = conn.createStatement().executeQuery("select * from " + table);
            ResultSetMetaData meta = r.getMetaData();
            MetaColumn ret = new MetaColumn(table, meta);
            r.close();
            r = null ;
            conn.close() ;
            conn = null ;
            return ret;
        } finally {
            if( r != null ) {
                try {
                    r.close() ;
                } catch( Exception e ) {
                }
            }
            r = null ;
            if( conn != null ) {
                try {
                    conn.close() ;
                } catch( Exception ee ) {
                }
            }
        }
    }
    
    /**
     * オブジェクトが利用可能かチェック.
     * @return boolean [true]の場合は、利用可能です.
     */
    public boolean isUse() {
        return recordFactory != null ;
    }
    
    /**
     * 現在確保されているメタカラム群をクリア.
     */
    public void clear() {
        map.clear() ;
    }
    
    /**
     * 指定テーブルのメタカラムを取得.
     * @param name 対象のテーブル名を設定します.
     * @return MetaColumns メタカラムオブジェクトが返されます.
     * @exception Exception 例外.
     */
    public MetaColumn getMetaColumn( String table )
        throws Exception {
        return getMetaColumn( false,table ) ;
    }
    
    /**
     * 指定テーブルのメタカラムを取得.
     * @param mode [true]の場合、名前をDB名に変換して処理します.
     * @param name 対象のテーブル名を設定します.
     * @return MetaColumns メタカラムオブジェクトが返されます.
     * @exception Exception 例外.
     */
    public MetaColumn getMetaColumn( boolean mode,String table )
        throws Exception {
        if( isUse() == false ) {
            throw new MaachangDaoException( "オブジェクトの初期化が行われていません" ) ;
        }
        MetaColumn ret = null ;
        if( mode ) {
            table = DbUtil.convertJavaNameByDBName( table ) ;
        }
        if( ( ret = map.get( table ) ) == null ) {
            ret = createMetaColumn( table ) ;
            if( ret != null ) {
                map.put( table,ret ) ;
            }
            else {
                throw new MaachangDaoException( "指定テーブル名[" + table + "]は存在しません" ) ;
            }
        }
        return ret ;
    }
}
