package org.maachang.mimdb.core ;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;

import org.maachang.mimdb.MimdbException;
import org.maachang.mimdb.core.util.Config;

/**
 * JDBCから、テーブル定義.
 * 
 * @version 2013/10/28
 * @author masahito suzuki
 * @since MasterInMemDB 1.00
 */
final class MimdbJdbcTable {
    private MimdbJdbcTable() {}
    
    /** Fetchサイズ. **/
    private static final int FETCH_SIZE = 100 ;
    
    /**
     * Confオブジェクトを設定して、テーブル定義.
     * @param conf 対象のConfオブジェクトを定義します.
     * @return String 生成されたテーブル名が返却されます.
     * @exception Exception 例外.
     */
    public static final String create( Config conf ) throws Exception {
        // jdbc定義情報を取得.
        String driver = conf.getString( "jdbc","driver",0 ) ;
        String url = conf.getString( "jdbc","url",0 ) ;
        String user = conf.getString( "jdbc","user",0 ) ;
        String passwd = conf.getString( "jdbc","passwd",0 ) ;
        String sql = conf.getString( "jdbc","sql",0 ) ;
        
        if( driver == null || ( driver = driver.trim() ).length() <= 0 ) {
            throw new MimdbException( "JDBCドライバー名が設定されていません" ) ;
        }
        if( url == null || ( url = url.trim() ).length() <= 0 ) {
            throw new MimdbException( "JDBC接続先が設定されていません" ) ;
        }
        if( sql == null || ( sql = sql.trim() ).length() <= 0 ) {
            throw new MimdbException( "JDBC接続SQL条件が設定されていません" ) ;
        }
        
        // mimdb共通を取得.
        String tableName = MimdbTableInstance.getTableName( conf ) ;
        String primary = MimdbTableInstance.getPrimaryKey( conf ) ;
        String[] index = MimdbTableInstance.getIndexNames( conf ) ;
        String[] ngram = MimdbTableInstance.getNGramIndexNames( conf ) ;
        String[] hash = MimdbTableInstance.getHashIndexNames( conf ) ;
        boolean compress = MimdbTableInstance.getCompressFlag( conf ) ;
        int compressLength = MimdbTableInstance.getCompressLength( conf ) ;
        
        // データベース接続.
        Statement st = null ;
        ResultSet rs = null ;
        Connection conn = driverConnection( driver,url,user,passwd ) ;
        try {
            
            // 読み込み専用ステートメント取得.
            st = conn.createStatement(
                ResultSet.TYPE_FORWARD_ONLY,
                ResultSet.CONCUR_READ_ONLY ) ;
            
            st.setFetchSize( FETCH_SIZE ) ; // 先読み件数.
            
            // SQL実行.
            rs = st.executeQuery( sql ) ;
            
            try {
                
                // テーブル生成開始.
                long id = MimdbTableInstance.begin( tableName ) ;
                
                // テーブルオブジェクトを生成.
                MimdbTable table = new MimdbTable( id,tableName,4096,primary,
                    index,ngram,hash,compress,compressLength,rs ) ;
                
                // DB接続-後始末.
                conn.commit() ;
                
                rs.close() ;
                rs = null ;
                st.close() ;
                st = null ;
                conn.close() ;
                conn = null ;
                
                // テーブルFIX.
                table.fix() ;
                
                // テーブル管理オブジェクトにテーブル登録.
                MimdbTableManager.getInstance().put( table ) ;
                
            } finally {
                // 処理終了.
                MimdbTableInstance.end( tableName ) ;
            }
            
        } catch( Exception e ) {
            throw new MimdbException( "[" + tableName + "]のJDBC読み込みでエラーが発生しました",e ) ;
        } finally {
            if( rs != null ) {
                try {
                    rs.close() ;
                } catch( Exception e ) {}
            }
            if( st != null ) {
                try {
                    st.close() ;
                } catch( Exception e ) {}
            }
            if( conn != null ) {
                try {
                    conn.close() ;
                } catch( Exception e ) {}
            }
        }
        return tableName ;
    }
    
    /** 読み込み専用コネクションオブジェクトを取得. **/
    private static final Connection driverConnection( String driver,String url,String user,String passwd )
        throws Exception {
        Class.forName( driver ) ;
        Connection ret ;
        Properties p = new java.util.Properties() ;
        //p.put("block size",512) ;
        if( user == null || user.length() <= 0 ) {
            p.put("user","") ;
            p.put("password","") ;
            ret = DriverManager.getConnection( url,p ) ;
        }
        else {
            p.put("user",user) ;
            p.put("password",passwd) ;
            ret = DriverManager.getConnection( url,p ) ;
        }
        ret.setReadOnly( false ) ;
        ret.setAutoCommit( false ) ; // setFetchSizeを有効にする場合はAutoCommitをoff.
        return ret;
    }
    
}
