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

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.JsDef;
import org.maachang.util.FileUtil;

/**
 * スクリプト基底オブジェクト.
 * 
 * @version 2007/08/29
 * @author masahito suzuki
 * @since MaachangComet 1.00
 */
public abstract class AbstractScript implements Script {
    
    /**
     * 対象パス.
     */
    protected String path = null ;
    
    /**
     * ファイル名.
     */
    protected String fileName = null ;
    
    /**
     * ファイル更新時間.
     */
    protected long updateTime = -1L ;
    
    /**
     * 実行ファイルタイプ.
     */
    protected String type = null ;
    
    /**
     * スクリプト内容.
     */
    protected SrcScript srcScript = null ;
    
    /**
     * デフォルトパッケージ更新ID.
     */
    protected int packageId = -1 ;
    
    /**
     * 実行スクリプトオブジェクト.
     */
    protected ExecutionScript executionScript = null ;
    
    /**
     * 基本スクリプトを取得.
     * <BR><BR>
     * 基本スクリプトを取得します.
     * <BR>
     * @return ExecutionScript 基本スクリプトが返されます.
     * @exception Exception 例外.
     */
    public synchronized ExecutionScript getScript() throws Exception {
        if( FileUtil.isFileExists( fileName ) == false ) {
            throw new HttpdStateException( HttpdErrorDef.HTTP11_500,
                "対象"+type+"ファイル[" + path + "]は存在しません" ) ;
        }
        else if( executionScript == null ||
            this.updateTime != FileUtil.getLastTime( fileName ) ||
            this.packageId != JsDef.getDefaultPackageId() ) {
            readScript() ;
        }
        return executionScript ;
    }
    
    /**
     * 情報クリア.
     */
    protected void clear() {
        updateTime = -1L ;
        srcScript = null ;
        executionScript = null ;
    }
    
    /**
     * スクリプトパスを取得.
     * <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 abstract int getScriptType() ;
    
    /**
     * スクリプト内容を取得.
     * <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 ;
    }
    
    /**
     * Headerスクリプトを設定.
     */
    protected abstract String addHeaderScript() throws Exception ;
    
    /**
     * Footerスクリプトを設定.
     */
    protected abstract String addFooterScript() throws Exception ;
    
    /**
     * 指定条件で内容を生成.
     */
    protected void create( String type,String baseDirectory,String path,String currentDirectory )
        throws Exception {
        if( path == null || ( path = path.trim() ).length() <= 0 ) {
            clear() ;
            throw new HttpdStateException( HttpdErrorDef.HTTP11_404,type+"の指定パスは不正です" ) ;
        }
        if( path.endsWith( ScriptDef.SCRIPT_PLUS ) == false ) {
            path += ScriptDef.SCRIPT_PLUS ;
        }
        currentDirectory = ScriptDef.trimCurrentDirectory( currentDirectory ) ;
        String fileName = new StringBuilder().append( currentDirectory ).
            append( baseDirectory ).append( path ).toString() ;
        if( FileUtil.isFileExists( fileName ) == false ) {
            clear() ;
            throw new HttpdStateException( HttpdErrorDef.HTTP11_404,"対象"+type+"ファイル[" + path + "]は存在しません" ) ;
        }
        if( path.endsWith( ScriptDef.SCRIPT_PLUS ) == true ) {
            path = path.substring( 0,path.length()-ScriptDef.SCRIPT_PLUS.length() ) ;
        }
        this.path = path ;
        this.type = type ;
        this.fileName = fileName ;
    }
    
    /**
     * スクリプト内容を読み込む.
     */
    protected void readScript()
        throws Exception {
        String script = null ;
        String header = addHeaderScript() ;
        String footer = addFooterScript() ;
        if( header == null && footer == null ) {
            StringBuilder buf = new StringBuilder() ;
            this.packageId = JsDef.pushDefaultPackage( buf ) ;
            buf.append( FileUtil.getFileByString( fileName,CHARSET ) ) ;
            script = buf.toString() ;
        }
        else {
            StringBuilder buf = new StringBuilder() ;
            this.packageId = JsDef.pushDefaultPackage( buf ) ;
            if( header != null ) {
                buf.append( header ).append( "\n" ) ;
            }
            buf.append( FileUtil.getFileByString( fileName,CHARSET ) ) ;
            if( footer != null ) {
                buf.append( "\n" ).append( footer ) ;
            }
            script = buf.toString() ;
            buf = null ;
        }
        script = ReadScriptPlus.convert( true,script ) ;
        this.srcScript = new SrcScript( script ) ;
        this.executionScript = new ExecutionScriptImpl(
            ScriptDef.ENGINE_JAVASCRIPT,getScriptType(),this.getPath(),script ) ;
        script = null ;
        this.updateTime = FileUtil.getLastTime( fileName ) ;
    }
}
