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

import org.maachang.comet.MaachangDef;
import org.maachang.comet.httpd.HttpdErrorDef;
import org.maachang.comet.httpd.HttpdStateException;
import org.maachang.comet.httpd.engine.script.ExecutionScript;
import org.maachang.comet.httpd.engine.script.Script;
import org.maachang.comet.httpd.engine.script.ScriptDef;
import org.maachang.comet.httpd.engine.script.SrcScript;
import org.maachang.comet.httpd.engine.script.js.InitJS;
import org.maachang.comet.httpd.engine.script.js.JsDef;
import org.maachang.comet.httpd.engine.script.taglib.AnalysisTagLib;
import org.maachang.util.FileUtil;

/**
 * Inner呼び出し用スクリプト情報.
 * 
 * @version 2007/11/08
 * @author masahito suzuki
 * @since MaachangComet 1.00
 */
public class InnerScript implements Script {
    
    /**
     * 対象パス.
     */
    protected String path = null ;
    
    /**
     * ファイル名.
     */
    protected String fileName = null ;
    
    /**
     * ファイル更新時間.
     */
    protected long updateTime = -1L ;
    
    /**
     * 実行スクリプトオブジェクト.
     */
    protected ExecutionScriptImpl executionScript = null ;
    
    /**
     * スクリプト内容.
     */
    private SrcScript srcScript = null ;
    
    /**
     * デフォルトパッケージ更新ID.
     */
    private int packageId = -1 ;
    
    /**
     * コンストラクタ.
     */
    private InnerScript() {
    }
    
    /**
     * コンストラクタ.
     * <BR><BR>
     * 条件を指定してオブジェクトを生成します.
     * <BR>
     * @param path 対象のパスを設定します.
     * @param currentDirectory カレントディレクトリを設定します.
     * @exception Exception 例外.
     */
    public InnerScript( String path,String currentDirectory )
        throws Exception {
        if( path == null || ( path = path.trim() ).length() <= 0 ) {
            throw new HttpdStateException( HttpdErrorDef.HTTP11_500,
                "指定パスは不正です" ) ;
        }
        if( path.endsWith( ScriptManager.SCRIPT_PLUS ) == false ) {
            path += ScriptManager.SCRIPT_PLUS ;
        }
        currentDirectory = ScriptDef.trimCurrentDirectory( currentDirectory ) ;
        String fileName = new StringBuilder().append( currentDirectory ).
            append( MaachangDef.DIRECTORY_APPLICATION ).
            append( ( ( path.startsWith("/" ) ) ? path.substring( 1,path.length() ) : path ) ).
            toString() ;
        if( FileUtil.isFileExists( fileName ) == false ) {
            throw new HttpdStateException( HttpdErrorDef.HTTP11_500,
                "対象インナーファイル[" + path + "]は存在しません" ) ;
        }
        this.path = path ;
        this.fileName = fileName ;
    }
    
    /**
     * 情報クリア.
     */
    protected void clear() {
        updateTime = -1L ;
        srcScript = null ;
        executionScript = null ;
    }
    
    /**
     * 基本スクリプトを取得.
     * <BR><BR>
     * 基本スクリプトを取得します.
     * <BR>
     * @return ExecutionScript 基本スクリプトが返されます.
     * @exception Exception 例外.
     */
    public synchronized ExecutionScript getScript() throws Exception {
        if( FileUtil.isFileExists( fileName ) == false ) {
            clear() ;
            throw new HttpdStateException( HttpdErrorDef.HTTP11_500,
                "対象インナーファイル[" + path + "]は存在しません" ) ;
        }
        else if( executionScript == null ||
            this.updateTime != FileUtil.getLastTime( fileName ) ||
            this.packageId != JsDef.getDefaultPackageId() ) {
            readScript() ;
        }
        return executionScript ;
    }
    
    /**
     * スクリプトパスを取得.
     * <BR><BR>
     * スクリプトパスを取得します.
     * <BR>
     * @return String スクリプトパスが返されます.
     */
    public synchronized String getPath() {
        return this.path ;
    }
    
    /**
     * スクリプトファイル名を取得.
     * <BR><BR>
     * スクリプトファイル名を取得します.
     * <BR>
     * @return String スクリプトファイル名が返されます.
     */
    public synchronized String getScriptName() {
        return this.fileName ;
    }
    
    /**
     * スクリプトタイプを取得.
     * <BR><BR>
     * スクリプトタイプを取得します.
     * <BR>
     * @return int スクリプトタイプが返されます.
     */
    public int getScriptType() {
        return ScriptManager.SCRIPT_TYPE_BY_INNER ;
    }
    
    /**
     * スクリプト内容を取得.
     * <BR><BR>
     * スクリプト内容を取得します.
     * <BR>
     * @return SrcScript スクリプト内容が返されます.
     */
    public synchronized SrcScript getSrcScript() {
        return srcScript ;
    }
    
    /**
     * スクリプトが利用可能かチェック.
     * <BR><BR>
     * スクリプトが利用可能かチェックします.
     * <BR>
     * @return boolean [true]の場合、利用可能です.
     */
    public synchronized boolean isScript() {
        return ( executionScript == null ) ? false : true ;
    }
    
    /**
     * スクリプト内容を読み込む.
     */
    protected void readScript()
        throws Exception {
        String script = FileUtil.getFileByString( fileName,CHARSET ) ;
        if( script == null ) {
            this.executionScript = null ;
            return ;
        }
        // ページキャッシュするか確認する.
        String[] sc = new String[]{script} ;
        long tm = PageCache.getInstance().analysisCacheMode( sc ) ;
        if( tm > 0L ) {
            script = sc[ 0 ] ;
            sc = null ;
            script = AnalysisTagLib.analysis( script ) ;
            script = TemplateScriptAnalysis.analysis( "_$cache$inner.ad",script ) ;
            StringBuilder buf = new StringBuilder() ;
            buf.append( "var _$cache$inner = new StrBuf() ;\n" ) ;
            buf.append( script ) ;
            buf.append( "var _$cache$inner$out = _$cache$inner.ts() ;\n_$cache$inner.clear();\n_$cache$inner=null;\n" ).
            append( "org.maachang.comet.httpd.engine.script.scripts.PageCache.getInstance().set( \"" ).append( "@inner@" ).
                append( path ).append( "\"," ).append( tm ).append( ",_$cache$inner$out ) ;\n" ).
            append( "httpPrint( _$cache$inner$out ) ;\n" ) ;
            script = buf.toString() ;
            buf = null ;
        }
        else {
            sc = null ;
            script = AnalysisTagLib.analysis( script ) ;
            script = TemplateScriptAnalysis.analysis( script ) ;
        }
        StringBuilder buf = new StringBuilder() ;
        this.packageId = JsDef.pushDefaultPackage( buf ) ;
        buf.append( InitJS.getInstance().get() ) ;
        buf.append( script ) ;
        script = buf.toString() ;
        buf = null ;
        this.srcScript = new SrcScript( script ) ;
        script = ReadScriptPlus.convert( true,script ) ;
        this.executionScript = new ExecutionScriptImpl(
            ScriptDef.ENGINE_JAVASCRIPT,getScriptType(),
            this.getPath(),script ) ;
        script = null ;
        this.updateTime = FileUtil.getLastTime( fileName ) ;
    }
    
}
