package org.maachang.comet.httpd.engine.script.cache;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.script.ScriptContext;
import javax.script.SimpleBindings;

import org.maachang.comet.conf.ServiceDef;
import org.maachang.comet.httpd.engine.script.SrcScript;
import org.maachang.manager.GlobalManager;

/**
 * キャッシュスクリプト管理.
 * 
 * @version 2007/11/12
 * @author masahito suzuki
 * @since MaachangComet 1.00
 */
public class CacheScriptManager {
    
    /**
     * デフォルトキャッシュ.
     */
    private CacheDefaultScript defaultCache = null ;
    
    /**
     * Modelキャッシュ.
     */
    private CacheModelScript modelCache = null ;
    
    /**
     * キャッシュ情報格納オブジェクト.
     */
    private List<CacheScriptByDirectorys> cache = null ;
    
    /**
     * キャッシュスクリプトマネージャを取得.
     * <BR><BR>
     * キャッシュスクリプトマネージャを取得します.
     * <BR>
     * @return CacheScriptManager キャッシュスクリプトマネージャが返されます.
     */
    public static final CacheScriptManager getInstance() {
        return ( CacheScriptManager )GlobalManager.getInstance().get( ServiceDef.SCRIPT_CACHE_MANAGER ) ;
    }
    
    /**
     * コンストラクタ.
     */
    public CacheScriptManager() {
        this.defaultCache = new CacheDefaultScript() ;
        this.modelCache = new CacheModelScript() ;
        this.cache = Collections.synchronizedList( new ArrayList<CacheScriptByDirectorys>() ) ;
    }
    
    /**
     * デストラクタ.
     */
    protected void finalize() throws Exception {
        this.destroy() ;
    }
    
    /**
     * オブジェクト破棄.
     * <BR><BR>
     * オブジェクトを破棄します.
     */
    protected void destroy() {
        this.defaultCache = null ;
        this.modelCache = null ;
        this.cache = null ;
    }
    
    /**
     * リロード処理.
     * <BR><BR>
     * リロード処理を実施します.
     * <BR>
     * @exception Exception 例外.
     */
    public void reload() throws Exception {
        CacheTableWrapper wrapper = defaultCache.script() ;
        wrapper = modelCache.reload( wrapper ) ;
        int len = cache.size() ;
        for( int i = 0 ; i < len ; i ++ ) {
            CacheScriptByDirectorys cdir = cache.get( i ) ;
            cdir.reload( wrapper ) ;
        }
    }
    
    /**
     * 指定内容をリロード.
     * <BR><BR>
     * 指定された内容だけをリロードします.
     * <BR>
     * @param name リロード対象の条件を設定します.<BR>
     *             [null]の場合、全体をリロードします.
     * @exception Exception 例外.
     */
    public void reload( String name ) throws Exception {
        if( name == null || ( name = name.trim() ).length() <= 0 ) {
            this.reload() ;
        }
        else {
            if( "model".equals( name.toLowerCase() ) ) {
                CacheTableWrapper wrapper = defaultCache.script() ;
                wrapper = modelCache.reload( wrapper ) ;
            }
            else {
                int len = cache.size() ;
                for( int i = 0 ; i < len ; i ++ ) {
                    CacheScriptByDirectorys cdir = cache.get( i ) ;
                    if( name.equals( cdir.getName() ) ) {
                        CacheTableWrapper wrapper = defaultCache.script() ;
                        cdir.reload( wrapper ) ;
                        return ;
                    }
                }
            }
        }
    }
    
    
    /**
     * 新しいキャッシュを追加.
     * <BR><BR>
     * 新しいキャッシュを追加します.
     * <BR>
     * @param name 対象のキャッシュ名を設定します.
     * @exception Exceptino 例外.
     */
    public void add( String name ) throws Exception {
        CacheScriptByDirectorys cdir = new CacheScriptByDirectorys( name ) ;
        cache.add( cdir ) ;
    }
    
    /**
     * １つのレスポンス終了処理時に実行.
     * <BR><BR>
     * １つのレスポンス終了処理時に実行します.
     * <BR>
     * @exception Exception 例外.
     */
    public void executionByExitRequest()
        throws Exception {
        CacheTableWrapper wrapper = defaultCache.script() ;
        if( wrapper != null ) {
            wrapper.clearThread() ;
        }
    }
    
    /**
     * スクリプトキャッシュを取得.
     * <BR><BR>
     * スクリプトキャッシュを取得します.
     * <BR>
     * @param ctx 取得対象のスクリプトコンテキストを設定します.
     * @exception Exception 例外.
     */
    public void script( ScriptContext ctx ) throws Exception {
        CacheTableWrapper wrapper = defaultCache.script() ;
        wrapper = modelCache.script( wrapper ) ;
        int len = cache.size() ;
        for( int i = 0 ; i < len ; i ++ ) {
            CacheScriptByDirectorys cdir = cache.get( i ) ;
            cdir.script( wrapper ) ;
        }
        ctx.setBindings( new SimpleBindings( wrapper ),ScriptContext.ENGINE_SCOPE ) ;
    }
    
    /**
     * 指定パスのソーススクリプトを取得.
     * <BR><BR>
     * 指定パスのソーススクリプトを取得します.
     * <BR>
     * @param path 対象のパス名を設定します.
     * @return SrcScript 対象のソーススクリプトが返されます.
     */
    public SrcScript getSrcScript( String path ) {
        if( path == null || ( path = path.trim() ).length() <= 0 ) {
            return null ;
        }
        if( defaultCache.isCache( path ) == true ) {
            return defaultCache.getSrcScript( path ) ;
        }
        if( modelCache.isCache( path ) == true ) {
            return modelCache.getSrcScript() ;
        }
        int len = cache.size() ;
        for( int i = 0 ; i < len ; i ++ ) {
            CacheScriptByDirectorys cdir = cache.get( i ) ;
            if( cdir.isCache( path ) ) {
                return cdir.getSrcScript( path ) ;
            }
        }
        return null ;
    }
    
    /**
     * 指定パスの内容が存在するかチェック.
     * <BR><BR>
     * 指定パスの内容が存在するかチェックします.
     * <BR>
     * @param path 対象のパス名を設定します.
     * @return boolean [true]の場合、存在します.
     */
    public boolean isCache( String path ) {
        if( path == null || ( path = path.trim() ).length() <= 0 ) {
            return false ;
        }
        if( defaultCache.isCache( path ) == true ||
            modelCache.isCache( path ) == true ) {
            return true ;
        }
        int len = cache.size() ;
        for( int i = 0 ; i < len ; i ++ ) {
            CacheScriptByDirectorys cdir = cache.get( i ) ;
            if( cdir.isCache( path ) ) {
                return true ;
            }
        }
        return false ;
    }
    
    /**
     * 読み込み名一覧を取得.
     * <BR><BR>
     * 現在読み込んでいる名前一覧を取得します.
     * <BR>
     * @return String[] 読み込み名一覧が返されます.
     */
    public String[] getNames() {
        int len = cache.size() ;
        if( len > 0 ) {
            String[] ret = new String[ len ] ;
            for( int i = 0 ; i < len ; i ++ ) {
                CacheScriptByDirectorys cdir = cache.get( i ) ;
                ret[ i ] = cdir.getName() ;
            }
            return ret ;
        }
        return null ;
    }
    
    /**
     * キャッシュWrapperを取得.
     * <BR><BR>
     * キャッシュWrapperを取得します.
     * <BR>
     * @return CacheTableWrapper キャッシュWrapperが返されます.
     * @exception Exception 例外.
     */
    public CacheTableWrapper getWrapper()
        throws Exception {
        return defaultCache.script() ;
    }
}

