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.HttpdDef;
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;

/**
 * MHTMLスクリプト情報.
 * 
 * @version 2007/08/29
 * @author masahito suzuki
 * @since MaachangComet 1.00
 */
public class MhtmlScript implements Script {
    
    /**
     * 対象パス.
     */
    protected String path = null ;
    
    /**
     * ファイル名.
     */
    protected String fileName = null ;
    
    /**
     * ファイル更新時間.
     */
    protected long updateTime = -1L ;
    
    /**
     * スクリプト内容.
     */
    private SrcScript srcScript = null ;
    
    /**
     * 実行スクリプトオブジェクト.
     */
    protected ExecutionScriptImpl executionScript = null ;
    
    /**
     * デフォルトパッケージ更新ID.
     */
    private int packageId = -1 ;
    
    /**
     * コンストラクタ.
     */
    private MhtmlScript() {
    }
    
    /**
     * コンストラクタ.
     * <BR><BR>
     * 条件を指定してオブジェクトを生成します.
     * <BR>
     * @param path 対象のパスを設定します.
     * @param currentDirectory カレントディレクトリを設定します.
     * @exception Exception 例外.
     */
    public MhtmlScript( String path,String currentDirectory )
        throws Exception {
        if( path == null || ( path = path.trim() ).length() <= 0 ) {
            throw new HttpdStateException( HttpdErrorDef.HTTP11_500,
                "mhtmlの指定パスは不正です" ) ;
        }
        if( path.endsWith( ScriptDef.SCRIPT_HTML_PLUS ) == false ) {
            path += ScriptDef.SCRIPT_HTML_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,
                "対象mhtmlファイル[" + path + "]は存在しません" ) ;
        }
        this.path = path ;
        this.fileName = fileName ;
    }
    
    /**
     * 基本スクリプトを取得.
     * <BR><BR>
     * 基本スクリプトを取得します.
     * <BR>
     * @return ExecutionScript 基本スクリプトが返されます.
     * @exception Exception 例外.
     */
    public synchronized ExecutionScript getScript() throws Exception {
        if( FileUtil.isFileExists( fileName ) == false ) {
            throw new HttpdStateException( HttpdErrorDef.HTTP11_500,
                "対象mhtmlファイル[" + 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 ScriptDef.SCRIPT_TYPE_BY_HTML ;
    }
    
    /**
     * スクリプト内容を取得.
     * <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 ;
        }
        script = TemplateScriptAnalysis.analysis( script ) ;
        StringBuilder buf = new StringBuilder() ;
        this.packageId = JsDef.pushDefaultPackage( buf ) ;
        buf.append( "setContentType(\"" ).append( HttpdDef.MHTML_MIME_TYPE ).append( "\");" ).append( "\n" ) ;
        buf.append( ScriptDef.ADD_SCRIPT ) ;
        buf.append( script ) ;
        buf.append( "_exit(" ).append( "\"exit-script\"" ).append( ") ;" ).append( "\n" ) ;
        script = buf.toString() ;
        buf = null ;
        
        script = ReadScriptPlus.convert( false,script ) ;
        this.srcScript = new SrcScript( script ) ;
        this.executionScript = new ExecutionScriptImpl(
            ScriptDef.ENGINE_JAVASCRIPT,getScriptType(),
            this.getPath(),script ) ;
        script = null ;
        this.updateTime = FileUtil.getLastTime( fileName ) ;
    }
    
}
