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

import javax.script.ScriptException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.maachang.comet.conf.ServiceDef;
import org.maachang.comet.httpd.engine.script.cache.CacheScriptManager;
import org.maachang.manager.GlobalManager;
import org.maachang.util.StringUtil;

/**
 * スクリプト実行例外.
 * 
 * @version 2007/09/23
 * @author masahito suzuki
 * @since MaachangComet 1.00
 */
public class BaseScriptException extends Exception {
    private static final long serialVersionUID = -8407798868124851487L;
    
    /**
     * LOG.
     */
    private static final Log LOG = LogFactory.getLog( BaseScriptException.class ) ;
    
    /**
     * 行を指す開始情報.
     */
    private static final String START_LINE = "(" ;
    
    /**
     * 行を指す終了情報.
     */
    private static final String END_LINE = ")" ;
    
    /**
     * 出力行数.
     */
    private static final int OUTPUT_LINE_SIZE = 11 ;
    
    /**
     * ScriptException.
     */
    private ScriptException scriptException = null ;
    
    /**
     * スクリプトエラー情報.
     */
    private String errorScriptInfo = null ;
    
    /**
     * コンストラクタ.
     */
    private BaseScriptException() {
        
    }
    
    /**
     * コンストラクタ.
     * <BR><BR>
     * 情報を設定してオブジェクトを生成します.
     * <BR>
     * @param scriptException スクリプト例外を設定します.
     * @param script 対象のスクリプト情報を設定します.
     */
    public BaseScriptException( ScriptException scriptException ) {
        if( scriptException == null ) {
            return ;
        }
        this.scriptException = scriptException ;
        this.errorScriptInfo = convertErrorInfo( scriptException.getMessage() ) ;
    }
    
    /**
     * スクリプト例外を取得.
     * <BR><BR>
     * スクリプト例外を取得します.
     * <BR>
     * @return ScriptException スクリプト例外が返されます.
     */
    public ScriptException getScriptException() {
        return scriptException ;
    }
    
    /**
     * スクリプトエラー情報を取得.
     * <BR><BR>
     * スクリプトエラー情報を取得します.
     * <BR>
     * @return String スクリプトエラー情報が返されます.
     */
    public String getErrorScriptInfo() {
        return errorScriptInfo ;
    }
    
    /**
     * スクリプトエラー行数を取得.
     */
    private String convertErrorInfo( String msg ) {
        String name = null ;
        SrcScript src = null ;
        String[] scriptName = new String[ 1 ] ;
        scriptName[0] = "" ;
        int line = getErrorLine( scriptName,msg ) ;
        if( line == -1 ) {
            return "" ;
        }
        else {
            //if( scriptName[ 0 ].endsWith( ScriptDef.SCRIPT_BY_CONTROLLER ) ) {
            //    scriptName[ 0 ] = scriptName[ 0 ].substring( 0,scriptName[ 0 ].length()-ScriptDef.SCRIPT_BY_CONTROLLER.length() ) ;
            //}
            if( LOG.isDebugEnabled() ) {
                LOG.debug( "... errorScript:" + scriptName[ 0 ] ) ;
            }
            WebAppScriptFactory factory = getFactory() ;
            
            // アプリケーションスクリプト.
            try {
                Script script = factory.getApplication( scriptName[ 0 ] ) ;
                if( script != null ) {
                    src = script.getSrcScript() ;
                    name = script.getScriptName() ;
                }
                else {
                    src = null ;
                    name = null ;
                }
            } catch( Exception e ) {
                src = null ;
                name = null ;
            }
            if( src == null ) {
                // キャッシュデフォルトスクリプト.
                if( CacheScriptManager.getInstance().isCache( scriptName[ 0 ] ) == true ) {
                    src = CacheScriptManager.getInstance().getSrcScript( scriptName[ 0 ] ) ;
                    name = scriptName[ 0 ] ;
                }
            }
        }
        if( src == null ) {
            return "" ;
        }
        StringBuilder buf = new StringBuilder() ;
        buf.append( "<code>src&nbsp;&nbsp;:</code>&nbsp;" ) ;
        buf.append( name ) ;
        buf.append( "<BR>" ) ;
        buf.append( "<table width=100% cellpadding=0 cellspacing=0><tr><td bgcolor=#0000ff><img alt=\"\" width=1 height=2></td></tr></table>" ) ;
        int start = line - ( OUTPUT_LINE_SIZE / 2 ) ;
        for( int i = 0 ; i < OUTPUT_LINE_SIZE ; i ++ ) {
            String sc = src.get( i+start ) ;
            if( sc == null ) {
                continue ;
            }
            if( sc.length() > 0 ) {
                sc = StringUtil.changeString( sc," ","&nbsp;" ) ;
            }
            if( i+start == line ) {
                buf.append( "<font color=#cc0000>" ) ;
            }
            buf.append( (i+start) ) ;
            buf.append( "&nbsp;:&nbsp;" ) ;
            buf.append( sc ) ;
            if( i+start == line ) {
                buf.append( "</font>" ) ;
            }
            buf.append( "<BR>" ) ;
        }
        buf.append( "<table width=100% cellpadding=0 cellspacing=0><tr><td bgcolor=#0000ff><img alt=\"\" width=1 height=2></td></tr></table>" ) ;
        return buf.toString() ;
    }
    
    /**
     * エラー行数を取得.
     */
    private int getErrorLine( String[] script,String msg ) {
        int p = msg.indexOf( START_LINE ) ;
        if( p == -1 ) {
            return -1 ;
        }
        for( ;; ) {
            if( isErrorInfo( msg,p ) == true ) {
                int p1 = msg.indexOf( "#",p ) ;
                int e = msg.indexOf( END_LINE,p ) ;
                if( p1 == -1 || e == -1 ) {
                    return -1 ;
                }
                String str = msg.substring( p1+"#".length(),e ) ;
                int ret = -1 ;
                try {
                    ret = Integer.parseInt( str ) ;
                } catch( Exception ee ) {
                    ret = -1 ;
                }
                if( ret == -1 ) {
                    p = msg.indexOf( START_LINE,p+1 ) ;
                    if( p == -1 ) {
                        return -1 ;
                    }
                    continue ;
                }
                script[0] = msg.substring( p+START_LINE.length(),p1 ) ;
                if( script[0] != null ) {
                    script[0] = script[0].trim() ;
                }
                return ret ;
            }
            p = msg.indexOf( START_LINE,p+1 ) ;
            if( p == -1 ) {
                return -1 ;
            }
        }
    }
    
    /**
     * 指定位置のエラー情報が正しいかチェック.
     */
    private static final boolean isErrorInfo( String msg,int start ) {
        int p = msg.indexOf( END_LINE,start ) ;
        if( p == -1 ) {
            return false ;
        }
        int b = msg.lastIndexOf( "#",p ) ;
        if( b == -1 || b > p ) {
            return false ;
        }
        return true ;
    }
    
    /**
     * WebAppScriptFactoryを取得.
     */
    private static final WebAppScriptFactory getFactory() {
        return ( WebAppScriptFactory )GlobalManager.getValue(
            ServiceDef.MANAGER_BY_WEB_APP_FACTORY ) ;
    }
    
}
