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

import java.io.BufferedReader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;

import org.maachang.util.StringUtil;

/**
 * スクリプト情報.
 * 
 * @version 2007/09/23
 * @author masahito suzuki
 * @since MaachangComet 1.00
 */
public class SrcScript {
    
    /**
     * 特殊文字変換元.
     */
    public static final String[] SPECIAL_SRC = {
        "<",">"
    } ;
    
    /**
     * 特殊文字.
     */
    public static final String[] SPECIAL_DEST = {
        "&lt;","&gt;"
    } ;
    
    /**
     * スクリプト情報.
     */
    private String[] script = null ;
    
    /**
     * 行区切りセット.
     */
    private List<SrcScriptList> lists = null ;
    
    /**
     * コンストラクタ.
     */
    public SrcScript() {
        this.script = null ;
        this.lists = null ;
    }
    
    /**
     * コンストラクタ.
     * <BR><BR>
     * 情報を設定してオブジェクトを生成します.
     * <BR>
     * @param script 対象のスクリプト情報を設定します.
     * @exception Exception 例外.
     */
    public SrcScript( String script ) throws Exception {
        this.create( script ) ;
    }
    
    /**
     * 情報生成.
     * <BR><BR>
     * 情報を設定してオブジェクトを生成します.
     * <BR>
     * @param script 対象のスクリプト情報を設定します.
     * @exception Exception 例外.
     */
    public synchronized void create( String script )
        throws Exception {
        if( script == null || ( script = script.trim() ).length() <= 0 ) {
            this.script = new String[ 0 ] ;
        }
        else {
            ArrayList<String> scs = new ArrayList<String>() ;
            BufferedReader sr = new BufferedReader( new StringReader( script ) ) ;
            int len = SPECIAL_SRC.length ;
            for( ;; ) {
                String line = sr.readLine() ;
                if( line == null ) {
                    break ;
                }
                if( line.length() > 0 ) {
                    for( int i = 0 ; i < len ; i ++ ) {
                        line = StringUtil.changeString( line,SPECIAL_SRC[ i ],SPECIAL_DEST[ i ] ) ;
                    }
                }
                scs.add( line ) ;
            }
            sr.close() ;
            if( scs.size() <= 0 ) {
                this.script = new String[ 0 ] ;
            }
            else {
                len = scs.size() ;
                this.script = new String[ len ] ;
                for( int i = 0 ; i < len ; i ++ ) {
                    this.script[ i ] = scs.get( i ) ;
                }
            }
        }
    }
    
    /**
     * 情報クリア.
     */
    public synchronized void clear() {
        this.script = null ;
        this.lists = null ;
    }
    
    /**
     * 指定行数の内容を取得.
     * <BR><BR>
     * 指定行数の内容を取得します.
     * <BR>
     * @param line 対象の行数を設定します.
     * @return String 指定行数の情報が返されます.
     */
    public synchronized String get( int line ) {
        if( line <= 0 || line > this.script.length ) {
            return null ;
        }
        return this.script[ line-1 ] ;
    }
    
    /**
     * 指定行のSrcScriptListオブジェクトを取得.
     * @param line 行番号を設定します.
     * @return SrcScriptList 行番号に対するSrcScriptListオブジェクトが返されます.
     */
    public synchronized SrcScriptList getLineBySrcScriptList( int line ) {
        if( this.lists == null ) {
            return null ;
        }
        int len = lists.size() ;
        for( int i = 0 ; i < len ; i ++ ) {
            SrcScriptList o = lists.get( i ) ;
            if( line >= o.getStart() && line <= o.getEnd() ) {
                return o ;
            }
        }
        return null ;
    }
    
    /**
     * SrcScriptListを追加.
     * @param srcScriptList 対象のSrcScriptListを設定します.
     * @exception Exception 例外.
     */
    public synchronized void setSrcScriptList( SrcScriptList srcScriptList )
        throws Exception {
        if( srcScriptList == null || srcScriptList.getName() == null ) {
            throw new IllegalArgumentException( "引数は不正です" ) ;
        }
        if( this.lists == null ) {
            this.lists = new ArrayList<SrcScriptList>() ;
        }
        this.lists.add( srcScriptList ) ;
    }
    
    /**
     * SrcScriptListを取得.
     * @param no 対象の項番を設定します.
     * @return SrcScriptList SrcScriptListが返されます.
     */
    public SrcScriptList getSrcScriptList( int no ) {
        if( lists == null || no < 0 || no >= lists.size() ) {
            return null ;
        }
        return lists.get( no ) ;
    }
    
    /**
     * SrcScriptList数を取得.
     * @return int SrcScriptList数が返されます.
     */
    public synchronized int getSrcScriptListSize() {
        if( lists == null ) {
            return 0 ;
        }
        return lists.size() ;
    }
    
    /**
     * 総行数を取得.
     * <BR><BR>
     * 総行数を取得します.
     * <BR>
     * @return int 総行数が返されます.
     */
    public synchronized int lines() {
        return this.script.length ;
    }
    
    /**
     * 文字列出力.
     * <BR><BR>
     * 文字列で出力します.
     * <BR>
     * @return String 文字列で出力します.
     */
    public synchronized String toString() {
        if( script != null ) {
            StringBuilder buf = new StringBuilder() ;
            int len = script.length ;
            for( int i = 0 ; i < len ; i ++ ) {
                buf.append( i ).append( ":" ).append( script[ i ] ) ;
            }
            return buf.toString() ;
        }
        return "" ;
    }
    
    /**
     * 指定スクリプト内容の行数を取得.
     * @param script 対象のスクリプト情報を設定します.
     * @return int 行数が返されます.
     * @exception Exception 例外.
     */
    public static final int getScriptList( String script )
        throws Exception {
        if( script == null || script.length() <= 0 ) {
            return 0 ;
        }
        int ret = 0 ;
        BufferedReader br = null ;
        try {
            br = new BufferedReader( new StringReader( script ) ) ;
            while( true ) {
                String s = br.readLine() ;
                if( s == null ) {
                    break ;
                }
                ret ++ ;
            }
            br.close() ;
            br = null ;
        } finally {
            if( br != null ) {
                try {
                    br.close() ;
                } catch( Exception e ) {
                }
            }
        }
        return ret ;
    }
}
