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

import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.SimpleScriptContext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.maachang.comet.MaachangDef;
import org.maachang.comet.httpd.engine.script.BaseModel;
import org.maachang.comet.httpd.engine.script.BaseModelImpl;
import org.maachang.comet.httpd.engine.script.ScriptDef;
import org.maachang.comet.httpd.engine.script.cache.CacheScriptManager;
import org.maachang.manager.GlobalManager;
import org.maachang.util.FileUtil;
import org.maachang.util.StringUtil;

/**
 * クーロン(スケジューリング実行)スクリプトを実行.
 * 
 * @version 2008/07/01
 * @author masahito suzuki
 * @since MaachangComet 1.1F
 */
public class CronScript {
    
    /**
     * LOG.
     */
    private static final Log LOG = LogFactory.getLog( CronScript.class ) ;
    
    /**
     * スクリプトエンジン名.
     */
    protected static final String ENGINE_NAME = "js" ;
    
    /**
     * スクリプト詳細名.
     */
    protected static final String DETAIL_NAME = "cron" ;
    
    /**
     * スタートアップ名.
     */
    protected static final String CRON_NAME = "Cron" ;
    
    /**
     * コンストラクタ.
     */
    private CronScript() {
        
    }
    
    /**
     * 指定Cronスクリプトを実行.
     * @param name 実行スクリプト名を設定します.
     * @exception Exception 例外.
     */
    public static final void execution( String name ) throws Exception {
        if( name == null || ( name = name.trim() ).length() <= 0 ) {
            throw new IllegalArgumentException( "引数は不正です" ) ;
        }
        if( name.endsWith( ScriptDef.SCRIPT_PLUS ) ) {
            name = name.substring( 0,name.length() - ScriptDef.SCRIPT_PLUS.length() ) ;
        }
        if( name.endsWith( CRON_NAME ) ) {
            name = name.substring( 0,name.length() - CRON_NAME.length() ) ;
        }
        executionScript( getScriptEngine(),name+CRON_NAME+ScriptDef.SCRIPT_PLUS ) ;
    }
    
    /**
     * １つの指定スクリプトを実行.
     */
    private static final boolean executionScript( ScriptEngine engine,String name )
        throws Exception {
        if( name == null || ( name = name.trim() ).length() <= 0 ) {
            return false ;
        }
        if( name.startsWith( "/" ) || name.startsWith( "\\" ) ) {
            name = name.substring( 1 ) ;
        }
        name = StringUtil.changeString( name,"\\","/" ) ;
        name = "/" + MaachangDef.DIRECTORY_CRON + name ;
        String file = FileUtil.getFullPath( "."+name ) ;
        if( FileUtil.isFileExists( file ) == false || FileUtil.isRead( file ) == false ) {
            return false ;
        }
        String script = FileUtil.getFileByString( file,"UTF8" ) ;
        engine.put( ScriptEngine.FILENAME,name ) ;
        BaseModel baseModel = null ;
        boolean errorFlag = false ;
        try {
            SimpleScriptContext ctx = new SimpleScriptContext() ;
            CacheScriptManager.getInstance().script( ctx ) ;
            Bindings bindings = putBindings( ctx ) ;
            baseModel = new BaseModelImpl() ;
            bindings.put( ScriptDef.SCRIPT_BY_MODEL,baseModel ) ;
            bindings.put( ScriptDef.SCRIPT_BY_CTX,ctx ) ;
            bindings.put( ScriptDef.SCRIPT_BY_ENGINE,engine ) ;
            engine.eval( script,bindings ) ;
        } catch( Exception e ) {
            errorFlag = true ;
            throw e ;
        } finally {
            if( baseModel != null && baseModel.isCreate() == true ) {
                try {
                    if( errorFlag == true ) {
                        baseModel.rollback() ;
                    }
                    else {
                        baseModel.commit() ;
                    }
                } catch( Exception ee ) {
                }
            }
            try {
                CacheScriptManager.getInstance().executionByExitRequest() ;
            } catch( Exception ee ) {
            }
        }
        return true ;
    }
    
    /**
     * スクリプトエンジンを生成.
     */
    private static final ScriptEngine getScriptEngine() {
        ScriptEngineManager manager = new ScriptEngineManager() ;
        ScriptEngine engine = manager.getEngineByName( ENGINE_NAME ) ;
        return engine ;
    }
    
    /**
     * デフォルトのBindings条件を設定.
     */
    private static final Bindings putBindings( ScriptContext ctx )
        throws Exception {
        Bindings bindings = ctx.getBindings( ScriptContext.ENGINE_SCOPE ) ;
        bindings.put( ScriptDef.CURRENT_SCRIPT,DETAIL_NAME ) ;
        bindings.put( ScriptDef.SCRIPT_MODE,ScriptDef.MODE_NOT_COMET ) ;
        bindings.put( ScriptDef.SCRIPT_DETAIL,DETAIL_NAME ) ;
        bindings.put( ScriptDef.MANAGER,GlobalManager.getInstance() ) ;
        bindings.put( ScriptDef.SCRIPT_BY_LOG,LOG ) ;
        return bindings ;
    }
    
}
