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.conf.IniFile;
import org.maachang.comet.conf.ServiceDef;
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.WebAppScriptFactory;
import org.maachang.comet.httpd.engine.script.dao.DaoFactory;
import org.maachang.comet.httpd.engine.session.HttpdSessionManager;
import org.maachang.comet.net.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" ;
    
    /**
     * サーバ(Proxy)セクション名.
     */
    private static final String PROXY_SECTION = "proxy" ;
    
    /**
     * コンストラクタ.
     */
    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.
        // WebAppScriptFactory.
        // DaoFactory.
        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 ) ;
        
        // 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]" ) ;
        long time = getTime( conf,"session-timeout" ) ;
        HttpdSessionManager sessions = null ;
        if( time <= 0L ) {
            sessions = new HttpdSessionManager() ;
        }
        else {
            sessions = new HttpdSessionManager( time ) ;
        }
        // 以前のセッション情報をロード.
        try {
            sessions.loadSession( HttpdDef.SESSION_FILE_NAME ) ;
        } catch( Exception e ) {
            LOG.error( e ) ;
        }
        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( "$$$ WebAppScriptFactory .... [START]" ) ;
        WebAppScriptFactory webAppFactory = new WebAppScriptFactory( path ) ;
        nm.put( ServiceDef.MANAGER_BY_WEB_APP_FACTORY,webAppFactory ) ;
        LOG.info( "$$$ WebAppScriptFactory .... [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起動モードのどちらかでのみ、起動が可能.
        ////////////////////////////////////////////////////////////////////////
        boolean netFlag = getBoolean( conf,NET_SECTION,"flag" ) ;
        boolean proxyFlag = getBoolean( conf,PROXY_SECTION,"flag" ) ;
        if( netFlag == false && proxyFlag == false ) {
            netFlag = true ;
        }
        // Net単一モードで起動.
        if( netFlag == true ) {
            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 ) ;
            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]" ) ;
        }
        
        // DaoFactoryを初期化.
        LOG.info( "$$$ DaoFactory .... [START]" ) ;
        DaoFactory daoFactory = new DaoFactory() ;
        nm.put( ServiceDef.DAO_FACTORY,daoFactory ) ;
        LOG.info( "$$$ DaoFactory .... [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]" ) ;
        
        // SessionManagerを破棄.
        LOG.info( "$$$ (Destroy) SessionManager .... [START]" ) ;
        HttpdSessionManager sessions = ( HttpdSessionManager )nm.get( ServiceDef.MANAGER_BY_SESSION ) ;
        if( sessions != null ) {
            try {
                sessions.saveSession( HttpdDef.SESSION_FILE_NAME ) ;
            } catch( Exception e ) {
                LOG.error( "error",e ) ;
            }
            try {
                sessions.destroy() ;
            } catch( Exception e ) {
            }
        }
    }
    
    /**
     * 指定情報のタイムアウト値を取得.
     */
    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 ) ) ;
    }
    
}
