package org.maachang.comet.conf ;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;

import org.maachang.comet.MaachangDef;
import org.maachang.conf.Config;
import org.maachang.conf.ReadIni;
import org.maachang.util.FileUtil;

/**
 * データベースによるユーザ認証定義.
 *
 * @version 2007/08/29
 * @author  masahito suzuki
 * @since   MaachangComet 1.00
 */
public class DbAuthUsers {
    
    /**
     * ターゲットセクション名.
     */
    private static final String BASE_SECTION = "db-auth-users" ;
    
    /**
     * キャラクタセット.
     */
    private static final String CHARSET = "UTF8" ;
    
    /**
     * 読み込みファイル名.
     */
    private static final String READ_FILE = MaachangDef.DIRECTORY_CONFIG+"dbusers.conf" ;
    
    /**
     * 読み込み対象データ.
     */
    private Config iniParams = null ;
    
    /**
     * 対象ファイル.
     */
    private String fileName = null ;
    
    /**
     * 最終更新日.
     */
    private long lastUpdate = -1L ;
    
    /**
     * オープン.
     * <BR><BR>
     * オープンします.
     * <BR>
     * @exception Exception 例外.
     */
    public synchronized void open() throws Exception {
        this.open( READ_FILE ) ;
    }
    
    /**
     * オープン.
     * <BR><BR>
     * オープンします.
     * <BR>
     * @param name 対象のファイル名を設定します.
     * @exception Exception 例外.
     */
    public synchronized void open( String name ) throws Exception {
        this.fileName = FileUtil.getFullPath( name ) ;
        try {
            this.reload() ;
        } catch( Exception e ) {
            this.close() ;
            throw e ;
        } finally {
        }
    }
    
    /**
     * クローズ.
     * <BR><BR>
     * クローズ処理.
     */
    public synchronized void close() {
        iniParams = null ;
        fileName = null ;
        lastUpdate = -1L ;
    }
    
    /**
     * DBアクセスリロードタイミングを取得.
     * <BR><BR>
     * DBアクセスリロードタイミングを取得します.
     * <BR>
     * @return long リロードタイミングを取得します.
     */
    public long getReloadTime() {
        updateByReload() ;
        String str = iniParams.get( BASE_SECTION,"reload",0 ) ;
        long ret = AuthUserByDatabase.DEFAULT_RELOAD_TIME ;
        if( str != null ) {
            try {
                ret = Long.parseLong( str ) ;
            } catch( Exception e ) {
                ret = AuthUserByDatabase.DEFAULT_RELOAD_TIME ;
            }
        }
        return ret ;
    }
    
    /**
     * 接続テーブル名を取得.
     * <BR><BR>
     * 接続テーブル名を取得します.
     * <BR>
     * @return String 接続テーブル名が返されます.
     */
    public String getTable() {
        updateByReload() ;
        return iniParams.get( BASE_SECTION,"table",0 ) ;
    }
    
    /**
     * 接続ユーザカラム名を取得.
     * <BR><BR>
     * 接続ユーザカラム名を取得します.
     * <BR>
     * @return String 接続ユーザカラム名が返されます.
     */
    public String getUserColumn() {
        updateByReload() ;
        return iniParams.get( BASE_SECTION,"user",0 ) ;
    }
    
    /**
     * 接続パスワードカラム名を取得.
     * <BR><BR>
     * 接続パスワードカラム名を取得します.
     * <BR>
     * @return String 接続パスワードカラム名が返されます.
     */
    public String getPasswdColumn() {
        updateByReload() ;
        return iniParams.get( BASE_SECTION,"passwd",0 ) ;
    }
    
    /**
     * ユーザ名に対するパスワードを取得.
     * <BR><BR>
     * ユーザ名に対するパスワードを取得します.
     * <BR>
     * @param user ユーザ名を設定します.
     * @return String[] パスワードが返されます.<BR>
     *                  [null]が返された場合、対象ユーザは存在しません.
     * @exception Exception 例外.
     */
    public String[] getPassword( String user )
        throws Exception {
        if( user == null || ( user = user.trim() ).length() <= 0 ) {
            throw new IllegalArgumentException( "ユーザ名が不正です" ) ;
        }
        updateByReload() ;
        String[] ret = iniParams.getAll( BASE_SECTION,user ) ;
        if( ret == null ) {
            return null ;
        }
        int len = ret.length ;
        for( int i = 0 ; i < len ; i ++ ) {
            if( ret[ i ] == null ) {
                ret[ i ] = "" ;
            }
        }
        return ret ;
    }
    
    /**
     * 指定ユーザ名が存在するかチェック.
     * <BR><BR>
     * 指定ユーザ名が存在するかチェックします.
     * <BR>
     * @param user 対象のユーザ名を設定します.
     * @return boolean [true]が返された場合、存在します.
     * @exception Exception 例外.
     */
    public boolean isUser( String user )
        throws Exception {
        if( user == null || ( user = user.trim() ).length() <= 0 ) {
            throw new IllegalArgumentException( "ユーザ名が不正です" ) ;
        }
        updateByReload() ;
        return ( iniParams.size( BASE_SECTION,user ) > 0 ) ? true : false ;
    }
    
    /**
     * 再読み込み.
     */
    private final void reload()
        throws Exception {
        BufferedReader buf = null ;
        if( FileUtil.isFileExists( fileName ) == true ) {
            try {
                buf = new BufferedReader(
                    new InputStreamReader(
                        new FileInputStream( fileName ),CHARSET ) ) ;
                Config iniParams = new Config() ;
                ReadIni.analisys( iniParams,buf ) ;
                buf.close() ;
                buf = null ;
                long last = FileUtil.getLastTime( fileName ) ;
                // 読み込みデータを設定.
                this.iniParams = iniParams ;
                this.lastUpdate = last ;
            } catch( Exception e ) {
                throw e ;
            } finally {
                if( buf != null ) {
                    try {
                        buf.close() ;
                    } catch( Exception e ) {
                    }
                }
            }
        }
    }
    
    /**
     * ファイルが更新されている場合は、再読み込み.
     */
    private void updateByReload() {
        try {
            long tm = FileUtil.getLastTime( fileName ) ;
            if( lastUpdate != tm ) {
                this.reload() ;
            }
        } catch( Exception e ) {
        }
    }
}
