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


/**
 * HTMLタグを無効な形に変換.
 * 
 * @version 2007/11/08
 * @author masahito suzuki
 * @since MaachangComet 1.00
 */
public class ConvertTag {
    
    /**
     * 変換対象タグ.
     */
    private static final String[] CONVERT = {
        "script","object"
    } ;
    
    /**
     * 指定タグを含む条件が存在するかチェック.
     * <BR><BR>
     * @param tags 変換対象のタグ群を設定します.
     * @param string 変換対象の文字列を設定します.
     * @return boolean [true]の場合、指定タグを含む条件が存在します.
     */
    public static final boolean isTag( String string ) {
        return isTag( CONVERT,string ) ;
    }
    
    /**
     * 指定タグを含む条件が存在するかチェック.
     * <BR><BR>
     * @param tags 変換対象のタグ群を設定します.
     * @param string 変換対象の文字列を設定します.
     * @return boolean [true]の場合、指定タグを含む条件が存在します.
     */
    public static final boolean isTag( String[] tags,String string ) {
        if( string == null || ( string = string.trim() ).length() <= 0 ) {
            return false ;
        }
        if( tags == null || tags.length <= 0 ) {
            return false ;
        }
        // 変換対象が存在するかチェック.
        boolean execFlag = false ;
        int len = tags.length ;
        String lower = string.toLowerCase() ;
        for( int i = 0 ; i < len ; i ++ ) {
            if( lower.indexOf( tags[ i ] ) != -1 ) {
                execFlag = true ;
                break ;
            }
        }
        lower = null ;
        
        // 変換対象が存在しない場合.
        if( execFlag == false ) {
            return false ;
        }
        
        int p = 0 ;
        for( ;; ) {
            int[] pos = getStartTagPos( string,p ) ;
            if( pos == null ) {
                return false ;
            }
            int[] tagPos = getTargetNamePos( string,pos ) ;
            if( tagPos == null ) {
                p = pos[ 1 ]+1 ;
            }
            String name = string.substring( tagPos[ 0 ],tagPos[ 1 ] ) ;
            if( isDirectTag( tags,name ) == true ) {
                return true ;
            }
            else {
                p = pos[ 1 ]+1 ;
            }
        }
    }
    
    /**
     * タグを含む内容を表示可能な形に変換.
     * <BR><BR>
     * @param string 変換対象の文字列を設定します.
     * @return String 変換された文字列が返されます.
     */
    public static final String convert( String string ) {
        return convert( CONVERT,string ) ;
    }
    
    /**
     * タグを含む内容を表示可能な形に変換.
     * <BR><BR>
     * @param tags 変換対象のタグ群を設定します.
     * @param string 変換対象の文字列を設定します.
     * @return String 変換された文字列が返されます.
     */
    public static final String convert( String[] tags,String string ) {
        if( string == null || ( string = string.trim() ).length() <= 0 ) {
            return "" ;
        }
        if( tags == null || tags.length <= 0 ) {
            return string ;
        }
        // 変換対象が存在するかチェック.
        boolean execFlag = false ;
        int len = tags.length ;
        String lower = string.toLowerCase() ;
        for( int i = 0 ; i < len ; i ++ ) {
            if( lower.indexOf( tags[ i ] ) != -1 ) {
                execFlag = true ;
                break ;
            }
        }
        lower = null ;
        
        // 変換対象が存在しない場合.
        if( execFlag == false ) {
            return string ;
        }
        
        int p = 0 ;
        StringBuilder buf = new StringBuilder() ;
        for( ;; ) {
            int[] pos = getStartTagPos( string,p ) ;
            if( pos == null ) {
                buf.append( string.substring( p ) ) ;
                break ;
            }
            int[] tagPos = getTargetNamePos( string,pos ) ;
            if( tagPos == null ) {
                buf.append( string.substring( p,pos[ 1 ]+1 ) ) ;
                p = pos[ 1 ]+1 ;
            }
            String name = string.substring( tagPos[ 0 ],tagPos[ 1 ] ) ;
            if( isDirectTag( tags,name ) == true ) {
                buf.append( string.substring( p,pos[ 0 ] ) ) ;
                p = pos[ 1 ]+1 ;
                String s = string.substring( pos[ 0 ],pos[ 1 ]+1 ) ;
                buf.append( JsDef.convertByViewHtml( false,s ) ) ;
            }
            else {
                buf.append( string.substring( p,pos[ 1 ]+1 ) ) ;
                p = pos[ 1 ]+1 ;
            }
        }
        
        return buf.toString() ;
    }
    
    /**
     * 指定文字列が動的タグ情報であるかチェック.
     */
    private static final boolean isDirectTag( String[] tags,String name ) {
        if( name == null || ( name = name.trim() ).length() <= 0 ) {
            return false ;
        }
        name = name.toLowerCase() ;
        int len = tags.length ;
        for( int i = 0 ; i < len ; i ++ ) {
            if( tags[ i ].equals( name ) ) {
                return true ;
            }
        }
        return false ;
    }
    
    /**
     * 指定位置からの開始タグ条件を取得.
     */
    private static final int[] getStartTagPos( String string,int pos ) {
        int p = getTargetPos( string,'<',pos ) ;
        if( p == -1 ) {
            return null ;
        }
        int p2 = getEndTagPos( string,p ) ;
        if( p2 == -1 ) {
            return null ;
        }
        return new int[]{p,p2} ;
    }
    
    /**
     * 指定開始位置からの有効な文字位置を取得.
     */
    private static final int[] getTargetNamePos( String string,int[] pos ) {
        if( pos == null ) {
            return null ;
        }
        int[] ret = null ;
        int len = string.length() ;
        int mode = 0 ;
        for( int i = pos[0]+1 ; i < len ; i ++ ) {
            if( mode != 1 && i >= pos[ 1 ] ) {
                break ;
            }
            char c = string.charAt( i ) ;
            if( mode == 0 ) {
                if( c == ' ' || c == '　' || c == '\r' ||
                    c == '\n' || c == '\t' || c == '/' ) {
                    continue ;
                }
                else {
                    ret = new int[ 2 ] ;
                    ret[ 0 ] = i ;
                    mode = 1 ;
                    continue ;
                }
            }
            else if( mode == 1 ) {
                if( ( c >= 'a' && c <= 'z' ) ||
                    ( c >= 'A' && c <= 'Z' ) ||
                    ( c >= '0' && c <= '9' ) ) {
                    continue ;
                }
                else {
                    ret[ 1 ] = i ;
                    mode = 2 ;
                    break ;
                }
            }
        }
        if( mode == 2 ) {
            return ret ;
        }
        return null ;
    }
    
    /**
     * 指定条件の位置を取得.
     */
    private static final int getTargetPos( String string,char target,int pos ) {
        int len = string.length() ;
        int cote = -1 ;
        for( int i = pos ; i < len ; i ++ ) {
            char c = string.charAt( i ) ;
            if( cote != -1 ) {
                if( c == cote ) {
                    cote = -1 ;
                    continue ;
                }
            }
            else {
                if( c == '\'' || c == '\"' ) {
                    cote = ( int )( c & 0x0000ffff ) ;
                    continue ;
                }
                if( c == target ) {
                    return i ;
                }
            }
        }
        return -1 ;
    }
    
    /**
     * この開始タグ条件の終了位置を取得.
     */
    public static final int getEndTagPos( String string,int pos ) {
        return getTargetPos( string,'>',pos ) ;
    }
}
