import java.util.*;

/**
 * SgfTree クラスは、SGFファイル内の全データから、手順データツリーを抽出します。
 * @author Jiro Suzuki
 */
public class SgfTree{

    private static String[] PROPERTY={"AN[","AP[","BH[","BR[","BT[","CP[","DT[","EV[","FF[","GC[","GM[","GN[","HA[","KO[","LKM[","NE[","OM[","ON[","PB[","PC[","PTM[","PW[","RE[","RO[","RU[","SO[","SZ[","TM[","TR[","US[","WH[","WR[","WT[","AB[","AE[","AR[","AW[","B[","BL[","C[","CR[","DD[","MA[","MK[","HL[","NF[","ID[","L[","LB[","LO[","LN[","M[","MA[","RT[","SL[","SQ[","ST[","TL[","TR[","W[","WL["};

    private Vector[] levelArray;
    private int cntParenthesisOpen;

    /**
     * 空のインスタンスを生成します。
     */
    SgfTree(){
        cntParenthesisOpen=0;
    }

    /**
     * SGF形式の手順を取得します。
     * @param str SGFファイル内の全データ(String形式)
     * @return SGF形式の手順データツリー(参考図含む)
     */
    public Vector getSgfTree(String str){

        //改行コードを消去する
        str=str.replaceAll("\\n", "");
        char[] charData=str.toCharArray();
        for(int i=0;i<charData.length;i++){
            //小括弧(開)を数えて、データツリーの深さを知る元情報にする
            if(charData[i]=='('){
              cntParenthesisOpen++;
            }
        }

        //char配列をStringに変換
        String strAll=new String(charData);

        //char配列をノード毎のStringに変換してVectorに保管
        Vector<Character> node=new Vector<Character>();
        boolean isMidParenthesisClosed=true;
        boolean isOutputChar;
        int currentLevel=-1;

        //レベル毎の配列を初期化
        levelArray=new Vector[cntParenthesisOpen/2+1];
        for(int i=0;i<cntParenthesisOpen/2+1;i++){
            levelArray[i]=new Vector();
        }
    
        for(int i=0;i<charData.length;i++){

            isOutputChar=true;
            //ブレーク処理
            if(isMidParenthesisClosed){

                //node追加判定
                switch(charData[i]){
                    case '(':
                    case ')':
                    case ';':
                        isOutputChar=false;
                        addNode(currentLevel,node);
                        node.clear();
                        break;
                    default:break;
                }

                //ArrayNode追加処理
                switch(charData[i]){
                    case '(':
                        currentLevel++;
                        clearLevelArray(currentLevel);
                        break;
                    case ')':
                        addArrayNode(currentLevel);
                        currentLevel--;
                        break;
                    default:break;
                }
            }

            //中括弧判定処理
            switch(charData[i]){
                case '[':
                    isMidParenthesisClosed=false;
                    break;
                case ']': //コメント内中括弧をClose判定しないための工夫
                          //ただし、"];"と"]("と"])"がコメント内に出現した時は対処できない。
                    if(isMatchProperty(strAll.substring(i+1)) | 
                       charData[i+1]==';' |
                       charData[i+1]=='(' |
                       charData[i+1]==')' ){
                           isMidParenthesisClosed=true;
                     }
                     break;
                 default:break;
            }

            //入力文字をnodeに追加 
            if(isOutputChar){
                node.add(new Character(charData[i]));
            }
        }

        //最後の1ノードをVectorに追加
        addNode(currentLevel,node);

        return levelArray[0];
    }

    //--------------------------------------------------------------
    //Vector(要素はchar)をStringに変換
    private String createStrWord(Vector node){
        char[] charWord=new char[node.size()];
        for(int i=0;i<node.size();i++){
            charWord[i]=((Character)node.get(i)).charValue();
        }
        return new String(charWord);
    }

    //--------------------------------------------------------------
    //プロパティ文字列確認処理
    private boolean isMatchProperty(String str){
        int match=0;
        for(int i=0;i<PROPERTY.length;i++){
            if(str.startsWith(PROPERTY[i])){
                match=1;
                i=PROPERTY.length;
            }
        }
        if(match==1){
            return true;
        }else{
            return false;
        }
    }

    //--------------------------------------------------------------
    private void clearLevelArray(int levelNum){
        levelArray[levelNum].clear();
    }

    private void addNode(int levelNum,Vector node){
        if(node.size()>0){
            levelArray[levelNum].add(createStrWord(node));
        }
    }

    private void addArrayNode(int levelNum){
        if(levelNum>0){
            levelArray[levelNum-1].add(levelArray[levelNum].clone());
        }
    }
}