package org.maachang.mimdb ;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.DriverPropertyInfo;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Properties;
import java.util.logging.Logger;

import org.maachang.mimdb.core.MimdbConnection;
import org.maachang.mimdb.core.impl.MimdbUtils;
import org.maachang.mimdb.core.util.AtomicNumber32;
import org.maachang.mimdb.jdbc.MimdbJdbcConnection;

/**
 * Mimdb-JDBCドライバ定義.
 * 
 * @version 2013/11/19
 * @author masahito suzuki
 * @since MasterInMemDB 1.00
 */
public class Driver implements java.sql.Driver {
    private Driver() {}
    
    /** URLヘッダ. **/
    private static final String HEAD_URL = "jdbc:mimdb:" ;
    private static final int HEAD_URL_LENGTH = HEAD_URL.length() ;
    
    /** 組み込み条件. **/
    private static final String EMBEDDED = "embedded" ;
    private static final String MEMORY = ":memory:" ;
    private static final String MEM = "memory" ;
    
    
    /** ドライバーロード用. **/
    private static final Driver INSTANCE = new Driver() ;
    private static final AtomicNumber32 regFlag = new AtomicNumber32( 0 ) ;
    
    // class.forName呼び出し時に、mimdbをデータベースマネージャに登録.
    static {
        try {
            load() ;
        } catch (SQLException e) {
        }
    }
    
    /**
     * JDBCコネクションを取得.
     * @param url 対象のURLを設定します.
     * @param info 対象の定義設定情報を設定します.
     * @return Connection コネクションオブジェクトが返却されます.
     * @exception Exception 例外.
     */
    public Connection connect(String url, Properties info) throws SQLException {
        String base = url ;
        if( !acceptsURL( url ) ) {
            throw new SQLException( "URLが間違っています:" + url ) ;
        }
        url = url.substring( HEAD_URL_LENGTH ).trim() ;
        try {
            return new MimdbJdbcConnection( getConnection( url,info ) ) ;
        } catch( Exception e ) {
            throw new SQLException( "URLの読み込みに失敗:" + base,e ) ;
        }
    }
    
    /** 接続句に対するコネクションオブジェクトを返却. **/
    private static final MimdbConnection getConnection( String url,Properties info )
        throws Exception {
        
        // 組み込み用コネクションの場合.
        String s = url.toLowerCase() ;
        if( EMBEDDED.equals( s ) || MEMORY.equals( s ) || MEM.equals( s ) ) {
            return MimdbConnection.create() ;
        }
        
        // クライアント接続の場合.
        String addr = null ;
        int port = -1 ;
        int p = url.indexOf( ":" ) ;
        if( p == -1 ) {
            addr = url ;
            port = -1 ;
        }
        else {
            addr = url.substring( 0,p ).trim() ;
            port = MimdbUtils.convertInt( url.substring( p+1 ).trim() ) ;
        }
        int timeout = -1 ;
        if( info.get( "timeout" ) != null ) {
            timeout = MimdbUtils.convertInt( info.get( "timeout" ) ) ;
        }
        return MimdbConnection.create( timeout,addr,port ) ;
    }
    
    /**
     * URLが正しいかチェック.
     * @param url 対象のURLを設定します.
     * @return boolean [true]の場合、正しいURLです.
     */
    public boolean acceptsURL(String url) {
        if( url == null ) {
            return false ;
        }
        return ( url.startsWith( HEAD_URL ) ) ;
    }
    
    /**
     * メジャーバージョンを取得.
     * @return int メジャーバージョンが返却されます.
     */
    public int getMajorVersion() {
        return Mimdb.VERSION_MAJOR ;
    }
    
    /**
     * マイナーバージョンを取得.
     * @return int マイナーバージョンが返却されます.
     */
    public int getMinorVersion() {
        return Mimdb.VERSION_MINOR;
    }
    
    /**
     * プロパティー情報の取得.
     * @param url 対象のURLを設定します.
     * @param info 対象の定義設定を設定します.
     * @return DriverPropertyInfo[] オブジェクトが返却されます.
     */
    public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) {
        return new DriverPropertyInfo[0];
    }
    
    /**
     * このドライバが JDBC CompliantTM であるかどうかを通知します.
     * @return boolean mimdbはSQL 92 Entry Levelに対応していないのでfalseが返却されます.
     */
    public boolean jdbcCompliant() {
        return false ;
    }
    
    /**
     * データベースマネージャに手動登録.
     * @exception SQLException SQL例外.
     */
    public static final void load() throws SQLException {
        int old ;
        if( ( old = regFlag.setToBeforeReturn( 1 ) ) == 0) {
            try {
                 DriverManager.registerDriver(INSTANCE) ;
            } catch( SQLException e ) {
                regFlag.set( old ) ;
                throw e ;
            }
        }
    }
    
    /**
     * データベースマネージャに手動解除.
     * @exception SQLException SQL例外.
     */
    public static final void unload() throws SQLException {
        int old ;
        if( ( old = regFlag.setToBeforeReturn( 0 ) ) == 1) {
            try {
                DriverManager.deregisterDriver(INSTANCE);
                regFlag.set( 0 ) ;
            } catch( SQLException e ) {
                regFlag.set( old ) ;
                throw e ;
            }
        }
    }
    
    /**
     * データベースマネージャに登録済みかチェック.
     * @return boolean [true]の場合は登録されています.
     */
    public static final boolean isRegister() {
        return regFlag.get() == 1 ;
    }
    
    
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }
}
