package vra;

import java.util.*;
import java.util.regex.*;
import java.io.*;
import java.nio.*;
import vfs.*;

class Context {
    private static final boolean DEBUG = false;
    private static final String CES = "Shift_JIS";

    private ArrayList<Node> mNodeStack;
    private int mIndex;
    private ArrayList<String> mLines;

    Context() {
	mNodeStack = new ArrayList<Node>();
	mLines = new ArrayList<String>();
    }

    Node load(Vfs vfs, String relPath) throws VraException {
	try {
	    readLines(vfs, relPath);
	} catch(IOException e) {
	    throw new VraException("cannot read lines", e);
	}
	pushNode("vra", null);
	Node root = tos();
	parseContent();
	popNode();
	if(mNodeStack.size() != 0)
	    throw new VraException("node stack disordered");
	return root;
    }

    private void readLines(Vfs vfs, String relPath) throws IOException {
	// 入力側の準備
	ByteBuffer byteBuf1 = vfs.getBuffer(relPath);
	byte[] byteBuf2 = new byte[byteBuf1.capacity()];
	byteBuf1.get(byteBuf2);
	ByteArrayInputStream bais = new ByteArrayInputStream(byteBuf2);
	InputStreamReader isr = new InputStreamReader(bais);
	BufferedReader br = new BufferedReader(isr);

	// バッファ側の準備
	mIndex = 0;
	mLines.clear();

	Pattern leadingParen = Pattern.compile("[^()]*\\(.*");
	Pattern trailingParen = Pattern.compile(".*\\)[^()]*");

	boolean contFlag = false;
	String s;
	while((s = br.readLine()) != null) {
	    if(contFlag) {
		s = mLines.get(mLines.size() - 1) + s;
		mLines.set(mLines.size() - 1, s);
		if(trailingParen.matcher(s).matches())
		    contFlag = false;
	    } else {
		mLines.add(s);
		if(leadingParen.matcher(s).matches()
		   && !trailingParen.matcher(s).matches())
		    contFlag = true;
	    }
	}
    }

    private void parseContent() throws VraException {
	while(!eof()) {
	    Matcher m;
	    String s = gets();

	    m = Pattern.compile("\\s*\\{(\\w+)$").matcher(s);
	    if(m.matches()) {
		// 新しい子ノードの開始
		pushNode(m.group(1), tos());
		parseContent();
		popNode();
		continue;
	    }

	    m = Pattern.compile("\\s*\\}$").matcher(s);
	    if(m.matches()) {
		// 現ノードの終了
		break;
	    }

	    m = Pattern.compile("\\s*(\\(.*\\))[^()]*").matcher(s);
	    if(m.matches()) {
		// 属性の定義
		tos().addAttr(Attr.parse(m.group(1)));
		continue;
	    }

	    throw new RuntimeException("unrecognizable input: " + s);
	}
    }

    private void pushNode(String name, Node parent) {
	if(DEBUG)
	    System.out.println("pushNode: " + name);
	Node child = new Node(name, parent);
	if(parent != null)
	    parent.getChildren().add(child);
	mNodeStack.add(0, child);
    }

    private void popNode() {
	if(DEBUG)
	    System.out.println("popNode:  " + tos().getName());
	mNodeStack.remove(0);
    }

    private Node tos() {
	return mNodeStack.get(0);
    }

    private String gets() {
	return mLines.get(mIndex++);
    }

    private void unget() {
	--mIndex;
    }

    private boolean eof() {
	return mIndex >= mLines.size();
    }
}
