package hiro.yoshioka.ast.sql;

import hiro.yoshioka.ast.sql.util.ASTAssist;
import hiro.yoshioka.util.StringUtil;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public abstract class AbsSimpleNode {
	protected static final AbsSimpleNode[] EMPTY_ARRAY = new AbsSimpleNode[0];
	protected Log log = LogFactory.getLog(getClass());
	private static String[] ERROR_KEYS = { "ERROR", "EXPECTED" };

	private static String[] KEYS = { "FIRST", "SECOND", "THIRD", "LAST" };

	public boolean containErrorNode;

	protected int id;

	protected AbsSQLParser parser;

	public ASTAssist fASTAssist;

	public String _string = StringUtil.EMPTY_STRING;

	protected IToken first, last, second, third;

	public AbsSimpleNode(int i) {
		this.id = i;
	}

	public NodeInfomation fInfomation;

	public AbsSimpleNode(AbsSQLParser p, int i) {
		this(i);
		this.parser = p;
	}

	// ----------------------------------------------------------------------------
	// EDIT FROM HERE ...
	// ----------------------------------------------------------------------------
	public abstract void dump(String prefix);

	public abstract void dump2(String prefix);

	public IToken getFirstToken() {
		return this.first;
	}

	public IToken getSecondToken() {
		return this.second;
	}

	public IToken getThirdToken() {
		return this.third;
	}

	public IToken getLastToken() {
		return this.last;
	}

	public int getID() {
		return this.id;
	}

	public abstract AbsSimpleNode getChild(int i);

	public abstract AbsSimpleNode[] getChildren();

	/**
	 * 本ノードに含む？
	 * 
	 * @param point
	 *            行,列
	 * @return true:含む
	 */
	public boolean contain(RowColumn point) {
		if (getLastToken() == null || getFirstToken() == null) {
			throw new IllegalStateException(
					"maybe undefined SimpeNode's jjtOpen");
		}

		if (getFirstToken().getBeginLine() > point._row
				|| getLastToken().getEndLine() < point._row) {
			return false;
		} else if (getFirstToken().getBeginLine() == point._row
				&& getFirstToken().getBeginColumn() > point._column) {
			return false;
		} else if (getLastToken().getEndLine() == point._row
				&& getLastToken().getEndColumn() < point._column) {
			return false;
		}
		return true;
	}

	/**
	 * 本ノードよりも後？
	 * 
	 * @param point
	 *            行,列
	 * @return true:後
	 */
	public boolean past(RowColumn point) {
		if (getLastToken().getEndLine() < point._row) {
			return true;
		}
		if (getLastToken().getEndLine() == point._row
				&& getLastToken().getEndColumn() <= point._column) {
			return true;
		}
		return false;
	}

	protected abstract String[] getNodeNames();

	public String getNodeName() {
		return getNodeNames()[id];
	}

	public String toString() {
		if (fASTAssist == null) {
			return getNodeName();
		} else {
			return getNodeName() + "<" + fASTAssist + ">";
		}
	}

	public String toString(String prefix) {
		return prefix + toString() + " [" + getFirstToken() + "/"
				+ getLastToken() + "]";
	}

	public String toString2(String prefix) {
		return prefix + toString() + " [" + informToken(getFirstToken()) + "/"
				+ informToken(getLastToken()) + "]";
	}

	public String informToken(IToken t) {
		if (t == null || t.getSpecialToken() == null) {
			return " [" + t + "] BEGIN[" + t.getBeginLine() + "/"
					+ t.getBeginColumn() + "] END[" + +t.getEndLine() + "/"
					+ t.getEndColumn() + "]";
		} else {
			return " [" + t + "] BEGIN[" + t.getBeginLine() + "/"
					+ t.getBeginColumn() + "] END[" + +t.getEndLine() + "/"
					+ t.getEndColumn() + "] SP["
					+ t.getSpecialToken().getImage().replaceAll("[\r\n]", "")
					+ "]";
		}
	}

	public void setAssist(ASTAssist assist) {
		this.fASTAssist = assist;
	}

	public abstract AbsSimpleNode getParent();

	public String getErrorString() {
		if (fInfomation != null) {
			String line = StringUtil.nvl(fInfomation.getLineMessage())
					.replaceAll("\r", "\n");
			line = line.replaceAll("\n+", ", ");
			return line;
		}
		return null;
	}

	public String getExpectedString() {
		if (fInfomation != null) {
			return fInfomation.exception.getExpectedTokenList().toString();
		}
		return null;
	}

	public Object getPropertyValue(Object id) {

		if ("ERROR".equals(id)) {
			return fInfomation.getLineMessage();
		} else if ("EXPECTED".equals(id)) {
			return fInfomation.exception.getExpectedTokenList();
		} else if ("FIRST".equals(id)) {
			return informToken(getFirstToken());
		} else if ("SECOND".equals(id)) {
			return informToken(getSecondToken());
		} else if ("THIRD".equals(id)) {
			return informToken(getThirdToken());
		} else if ("LAST".equals(id)) {
			return informToken(getLastToken());
		}
		return "";
	}

	public boolean isPropertySet(Object id) {
		return false;
	}

	public void resetPropertyValue(Object id) {
	}

	public void setPropertyValue(Object id, Object value) {
	}

	public Object getEditableValue() {
		return null;
	}
}
