package org.maachang.comet.httpd.engine;

import java.net.InetAddress;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.maachang.comet.ServiceDef;
import org.maachang.comet.conf.IniFile;
import org.maachang.comet.conf.StartupConfig;
import org.maachang.comet.httpd.engine.comet.CometManager;
import org.maachang.comet.httpd.engine.errors.HttpdErrorPageManager;
import org.maachang.comet.httpd.engine.script.cron.CronTiemrThread;
import org.maachang.comet.httpd.engine.script.dao.DaoFactory;
import org.maachang.comet.httpd.engine.script.scripts.ApplicationScriptFactory;
import org.maachang.comet.httpd.engine.session.HttpdSessionManager;
import org.maachang.comet.httpd.engine.session.SessionService;
import org.maachang.comet.net.ssl.SslOption;
import org.maachang.conf.ConvIniParam;
import org.maachang.manager.GlobalManager;
import org.maachang.util.FileUtil;

/**
 * HTTPD-Engine開始処理.
 * 
 * @version 2007/08/26
 * @author masahito suzuki
 * @since MaachangComet 1.00
 */
public class StartupHttpdEngine {
    
    /**
     * LOG.
     */
    private static final Log LOG = LogFactory.getLog( StartupConfig.class ) ;
    
    /**
     * サーバセクション名.
     */
    private static final String BASE_SECTION = "server" ;
    
    /**
     * サーバ(NET)セクション名.
     */
    private static final String NET_SECTION = "net" ;
    
    /**
     * コンストラクタ.
     */
    private StartupHttpdEngine() {
        
    }
    
    /**
     * HTTPDエンジン内容を初期化.
     * <BR><BR>
     * HTTPDエンジン内容を初期化します.
     * <BR>
     * @param path 対象のパスを設定します.
     * @exception Exception 例外.
     */
    public static final void init( String path )
        throws Exception {
        // 初期化内容.
        // HttpdEngine.
        // CometManager.
        // ErrorManager.
        // SessionManager.
        // PublicManager.
        // ProxyManager.
        // ScriptManager.
        // ApplicationScriptFactory.
        // DaoFactory.
        // Cron.
        if( path == null || ( path = path.trim() ).length() <= 0 ) {
            throw new IllegalArgumentException( "引数は不正です" ) ;
        }
        path = FileUtil.getFullPath( path ) ;
        
        // GlobalManagerを取得.
        GlobalManager nm = GlobalManager.getInstance() ;
        
        // Configオブジェクトを取得.
        IniFile conf = ( IniFile )nm.get( ServiceDef.MANAGER_BY_CONFIG ) ;
        
        // DaoFactoryを初期化.
        LOG.info( "$$$ DaoFactory .... [START]" ) ;
        DaoFactory daoFactory = new DaoFactory() ;
        nm.put( ServiceDef.DAO_FACTORY,daoFactory ) ;
        LOG.info( "$$$ DaoFactory .... [END]" ) ;
        
        // ErrorManagerを初期化.
        LOG.info( "$$$ ErrorManager .... [START]" ) ;
        HttpdErrorPageManager errors = new HttpdErrorPageManager( path ) ;
        nm.put( ServiceDef.MANAGER_BY_ERROR_PAGE,errors ) ;
        LOG.info( "$$$ ErrorManager .... [END]" ) ;
        
        // SessionManagerを初期化.
        LOG.info( "$$$ SessionManager .... [START]" ) ;
        HttpdSessionManager sessions = null ;
        sessions = SessionService.getManager() ;
        nm.put( ServiceDef.MANAGER_BY_SESSION,sessions ) ;
        LOG.info( "$$$ SessionManager .... [END]" ) ;
        
        // CometManagerを初期化.
        LOG.info( "$$$ CometManager .... [START]" ) ;
        int length = getNumber( conf,"comet-pool" ) ;
        CometManager comet = null ;
        if( length <= 0 ) {
            comet = new CometManager() ;
        }
        else {
            comet = new CometManager( length ) ;
        }
        nm.put( ServiceDef.MANAGER_BY_COMET,comet ) ;
        LOG.info( "$$$ CometManager .... [poolSize:" + comet.getPoolSize() + "]" ) ;
        LOG.info( "$$$ CometManager .... [END]" ) ;
        
        // PublicManagerを初期化.
        LOG.info( "$$$ PublicManager .... [START]" ) ;
        HttpdPublicManager pubMan = new HttpdPublicManager( path ) ;
        nm.put( ServiceDef.MANAGER_BY_PUBLIC_PAGE,pubMan ) ;
        LOG.info( "$$$ PublicManager .... [END]" ) ;
        
        // WebAppScriptFactoryを初期化.
        LOG.info( "$$$ ApplicationScriptFactory .... [START]" ) ;
        ApplicationScriptFactory webAppFactory = new ApplicationScriptFactory( path ) ;
        nm.put( ServiceDef.MANAGER_BY_WEB_APP_FACTORY,webAppFactory ) ;
        LOG.info( "$$$ ApplicationScriptFactory .... [END]" ) ;
        
        // ScriptManagerを初期化.
        LOG.info( "$$$ ScriptManager .... [START]" ) ;
        HttpdScriptManager scripts = new HttpdScriptManager( path ) ;
        nm.put( ServiceDef.MANAGER_BY_APPLICATON_PAGE,scripts ) ;
        LOG.info( "$$$ ScriptManager .... [END]" ) ;
        
        ////////////////////////////////////////////////////////////////////////
        // HttpdEngineを初期化.
        // net起動モードか、Proxy起動モードのどちらかでのみ、起動が可能.
        ////////////////////////////////////////////////////////////////////////
        LOG.info( "$$$ HttpdEngine(NET) .... [START]" ) ;
        int max = getNumber( conf,NET_SECTION,"max-connect" ) ;
        int poolLen = getNumber( conf,NET_SECTION,"max-pool" ) ;
        int port = getNumber( conf,NET_SECTION,"server-port" ) ;
        InetAddress addr = getInetAddress( conf,NET_SECTION,"server-address" ) ;
        if( max <= 0 ) {
            max = HttpdDef.DEFAULT_NET_POOL ;
        }
        if( poolLen <= 0 ) {
            poolLen = HttpdDef.DEFAULT_NET_CONNECT ;
        }
        if( port <= 0 ) {
            port = HttpdDef.DEFAULT_PORT ;
        }
        // SSLオプションを生成.
        SslOption sslOpt = SslOption.create( conf.getConfig() ) ;
        LOG.info( "$$$ HttpdEngine(NET) .... [max:" + max + " pool:" + poolLen + " port:" + port + " addr:" + addr + "]" ) ;
        if( sslOpt == null ) {
            LOG.info( "$$$ HttpdEngine(NET) .... SSLは無効." ) ;
        }
        else {
            LOG.info( "$$$ HttpdEngine(NET) .... [SSL={"+sslOpt.toString()+"}]" ) ;
        }
        HttpdEngine engine = new HttpdEngine( sslOpt,max,poolLen,port,addr ) ;
        nm.put( ServiceDef.MANAGER_BY_HTTPD,engine ) ;
        LOG.info( "$$$ HttpdEngine(NET) .... [END]" ) ;
        
        // Cronを初期化.
        LOG.info( "$$$ Cron .... [START]" ) ;
        CronTiemrThread cron = new CronTiemrThread() ;
        nm.put( ServiceDef.CRON_TAB_MANAGER,cron ) ;
        LOG.info( "$$$ Cron .... [END]" ) ;
    }
    
    /**
     * HTTPDエンジンを破棄.
     * <BR><BR>
     * HTTPDエンジンを破棄します.
     */
    public static final void destroy() {
        // GlobalManagerを取得.
        GlobalManager nm = GlobalManager.getInstance() ;
        
        // HTTPEngineを破棄.
        LOG.info( "$$$ (Destroy) HttpdEngine .... [START]" ) ;
        HttpdEngine engine = ( HttpdEngine )nm.get( ServiceDef.MANAGER_BY_HTTPD ) ;
        if( engine != null ) {
            try {
                engine.destroy() ;
            } catch( Exception e ) {
            }
        }
        LOG.info( "$$$ (Destroy) HttpdEngine .... [END]" ) ;
        
        // Cronを終了化.
        LOG.info( "$$$ (Destroy) Cron .... [START]" ) ;
        CronTiemrThread cron = ( CronTiemrThread )nm.get( ServiceDef.CRON_TAB_MANAGER ) ;
        if( cron != null ) {
            cron.destroy() ;
        }
        LOG.info( "$$$ (Destroy) Cron .... [END]" ) ;
    }
    
    /**
     * 指定情報のタイムアウト値を取得.
     */
    protected static final long getTime( IniFile conf,String key ) {
        return ConvIniParam.getLong( conf.get( BASE_SECTION,key,0 ) ) ;
    }
    
    /**
     * 指定情報のタイムアウト値を取得.
     */
    protected static final long getTime( IniFile conf,String section,String key ) {
        return ConvIniParam.getLong( conf.get( section,key,0 ) ) ;
    }
    
    /**
     * 指定情報を数値に変換.
     */
    protected static final boolean getBoolean( IniFile conf,String key ) {
        return ConvIniParam.getBoolean( conf.get( BASE_SECTION,key,0 ) ) ;
    }
    
    /**
     * 指定情報を数値に変換.
     */
    protected static final boolean getBoolean( IniFile conf,String section,String key ) {
        return ConvIniParam.getBoolean( conf.get( section,key,0 ) ) ;
    }
    
    /**
     * 指定情報を数値に変換.
     */
    protected static final int getNumber( IniFile conf,String key ) {
        return ConvIniParam.getInt( conf.get( BASE_SECTION,key,0 ) ) ;
    }
    
    /**
     * 指定情報を数値に変換.
     */
    protected static final int getNumber( IniFile conf,String section,String key ) {
        return ConvIniParam.getInt( conf.get( section,key,0 ) ) ;
    }
    
    /**
     * 指定文字列をInetAddressに変換.
     */
    protected static final InetAddress getInetAddress( IniFile conf,String key ) {
        return ConvIniParam.getInetAddress( conf.get( BASE_SECTION,key,0 ) ) ;
    }
    
    /**
     * 指定文字列をInetAddressに変換.
     */
    protected static final InetAddress getInetAddress( IniFile conf,String section,String key ) {
        return ConvIniParam.getInetAddress( conf.get( section,key,0 ) ) ;
    }
    
}
