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

import org.maachang.comet.httpd.engine.HttpdDef;
import org.maachang.comet.httpd.engine.script.ScriptDef;

/**
 * 読み込みスクリプトに対して基本追加する条件.
 * 
 * @version 2008/05/21
 * @author masahito suzuki
 * @since MaachangComet 1.16
 */
public class ReadScriptPlus {
    
    private ReadScriptPlus() {
    }
    
    /**
     * cacheに対するexitチェック.
     */
    private static final String[] CACHE_BY_EXIT = {
        "catch","{","_isExitTo();" } ;
    
    /**
     * 読み込まれたスクリプトを設定.
     * @param comment [false]の場合、コメント除外処理は実施しません.
     * @param script 対象のスクリプトを設定します.
     * @return String 変換された情報が返されます.
     * @exception Exception 例外.
     */
    public static final String convert( boolean comment,String script ) throws Exception {
        if( script == null || ( script = script.trim() ).length() <= 0 ) {
            return "" ;
        }
        if( comment == true ) {
            script = cutComment( script ) ;
        }
        // cacheに対するexitチェックを行う処理を付加.
        script = add( script,CACHE_BY_EXIT[0],CACHE_BY_EXIT[1],CACHE_BY_EXIT[2] ) ;
        return script ;
    }
    
    /**
     * コメント行を省いた情報を取得.
     */
    protected static final String cutComment( String script ) throws Exception {
        if( script == null || ( script = script.trim() ).length() <= 0 ) {
            return "" ;
        }
        StringBuffer buf = new StringBuffer() ;
        int len = script.length() ;
        int cote = -1 ;
        int commentType = -1 ;
        int bef = -1 ;
        for( int i = 0 ; i < len ; i ++ ) {
            if( i != 0 ) {
                bef = script.charAt( i-1 ) ;
            }
            char c = script.charAt(i) ;
            // シングル／ダブルコーテーション内の処理.
            if( cote != -1 ) {
                if( c == cote ) {
                    if( ( char )bef != '\\' ) {
                        cote = -1 ;
                    }
                }
                buf.append( c ) ;
                continue ;
            }
            // コメント内の処理.
            else if( commentType != -1 ) {
                if( commentType == 1 ) {
                    if( c == '\n' || c == '\r' ) {
                        if( c == '\r' ) {
                            if( len > i + 1 && script.charAt( i+1 ) == '\n' ) {
                                i ++ ;
                                buf.append( "\r\n" ) ;
                            }
                            else {
                                buf.append( c ) ;
                            }
                        }
                        else {
                            buf.append( c ) ;
                        }
                        commentType = -1 ;
                    }
                }
                else if( commentType == 2 ) {
                    if( c == '*' ) {
                        if( len > i + 1 && script.charAt( i+1 ) == '/' ) {
                            i ++ ;
                            commentType = -1 ;
                        }
                    }
                }
                continue ;
            }
            // それ以外の処理.
            else {
                if( c == '/' ) {
                    if( len <= i + 1 ) {
                        buf.append( c ) ;
                        continue ;
                    }
                    char c2 = script.charAt( i+1 ) ;
                    if( c2 == '*' ) {
                        commentType = 2 ;
                        continue ;
                    }
                    else if( c2 == '/' ) {
                        commentType = 1 ;
                        continue ;
                    }
                }
                else if( c == '\'' || c == '\"' ) {
                    cote = ( int )( c & 0x0000ffff ) ;
                }
                buf.append( c ) ;
            }
        }
        return buf.toString() ;
    }
    
    /**
     * コーテーション以外での、指定文字列が一致する条件に対して、
     * 条件を付加.
     */
    private static final String add( String script,String main,String sub,String inc )
        throws Exception {
        if( script == null || ( script = script.trim() ).length() <= 0 ) {
            return "" ;
        }
        StringBuffer buf = new StringBuffer() ;
        int len = script.length() ;
        int cote = -1 ;
        int startPos = -1 ;
        boolean target = false ;
        char[] mainChars = main.toCharArray() ;
        char[] subChars = null ;
        if( sub != null && sub.length() > 0 ) {
            subChars = sub.toCharArray() ;
        }
        int bef = -1 ;
        for( int i = 0 ; i < len ; i ++ ) {
            if( i != 0 ) {
                bef = script.charAt( i-1 ) ;
            }
            char c = script.charAt(i) ;
            // シングル／ダブルコーテーション内の処理.
            if( cote != -1 ) {
                if( c == cote ) {
                    if( ( char )bef != '\\' ) {
                        cote = -1 ;
                    }
                }
                buf.append( c ) ;
                startPos = -1 ;
                continue ;
            }
            // チェックターゲットの処理.
            else if( target == true ) {
                if( subChars == null ) {
                    buf.append( inc ) ;
                    buf.append( c ) ;
                    startPos = -1 ;
                    target = false ;
                    continue ;
                }
                // コメント開始.
                else if( c == '\'' || c == '\"' ) {
                    cote = ( int )( c & 0x0000ffff ) ;
                    buf.append( c ) ;
                    startPos = -1 ;
                    continue ;
                }
                // sub開始チェック.
                else if( startPos == -1 ) {
                    if( subChars[ 0 ] == c ) {
                        startPos = 1 ;
                        if( startPos >= subChars.length ) {
                            buf.append( c ) ;
                            buf.append( inc ) ;
                            startPos = -1 ;
                            target = false ;
                            continue ;
                        }
                    }
                }
                // sub開始チェック後のチェック.
                else {
                    if( subChars[ startPos ] == c ) {
                        startPos ++ ;
                        if( startPos >= subChars.length ) {
                            buf.append( c ) ;
                            buf.append( inc ) ;
                            startPos = -1 ;
                            target = false ;
                            continue ;
                        }
                    }
                    else {
                        startPos = -1 ;
                    }
                }
                buf.append( c ) ;
            }
            // 通常のチェック処理.
            else {
                // コメント開始.
                if( c == '\'' || c == '\"' ) {
                    cote = ( int )( c & 0x0000ffff ) ;
                    buf.append( c ) ;
                    startPos = -1 ;
                    continue ;
                }
                // main開始チェック.
                if( startPos == -1 ) {
                    if( mainChars[ 0 ] == c ) {
                        startPos = 1 ;
                        if( startPos >= mainChars.length ) {
                            startPos = -1 ;
                            target = true ;
                        }
                    }
                }
                // main開始チェック後のチェック.
                else {
                    if( mainChars[ startPos ] == c ) {
                        startPos ++ ;
                        if( startPos >= mainChars.length ) {
                            startPos = -1 ;
                            target = true ;
                        }
                    }
                    else {
                        startPos = -1 ;
                    }
                }
                buf.append( c ) ;
            }
        }
        return buf.toString() ;
    }
    
    /**
     * MHTML用追加情報.
     * @param buf 対象のスクリプトバッファを設定します.
     * @param script 対象のスクリプトを設定します.
     * @param path 対象のパスを設定します.
     * @exception Exception 例外.
     */
    public static final void addMHTML( StringBuilder buf,String script,String path ) throws Exception {
        buf.append( ScriptDef.SCRIPT_LAST_MHTML ).append( "=\"" ).append( path ).append( "\";\n" ) ;
        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" ) ;
    }
    
}
