public abstract class state {
	public state below;
	protected int serial;
	public bool rejected = false;

	public Coordinate begin;
	public Coordinate end;

	abstract public string ToString(string indent);

	public state() {}

	protected state(state below, int serial) {
		System.Diagnostics.Debug.Assert(this != below);
		System.Diagnostics.Debug.Assert(serial >= 0);
		this.below = below;
		this.serial = serial;
		if (below != null) {
			this.begin = below.end;
		}
	}

	abstract public bool checkRejected();

	private object cachedAST;
	private bool cached = false;
	public object rewrite2AST() {
		if (!cached) {
			cached = true;
			cachedAST = _rewrite2AST();
			IHasCoordinate ihc = cachedAST as IHasCoordinate;
			if (ihc != null) {
				ihc.begin = begin;
				ihc.end = end;
			}
		}
		return cachedAST;
	}
	abstract public object _rewrite2AST();

	public virtual bool accepting { get { return false; } }

	abstract public void transitions(System.Collections.Queue wl, InputElement tok, int count);
	public virtual state shiftNonterm(string nonterm, int count, Coordinate end, string rule, state rightmost) {
		throw new System.Exception(nonterm+"== "+rule);
	}
}

public abstract class acceptingState : nonterminalState {
	public nonterminalState root;

	public acceptingState() {}

	protected acceptingState(state below, string rule, state rightmost, Coordinate end, bool rejected, int serial) : base(below, rule, rightmost, end, false, serial) {
		System.Diagnostics.Debug.Assert(!rejected);
		this.root = (nonterminalState) rightmost;
	}

	public override string ToString(string indent) {
		return root.ToString(indent);
	}

	public override bool accepting { get { return true; } }
}

public abstract class nonterminalState : state {
	public state rightmost;
	public string rule;
	public System.Collections.Queue queue;

	public void report() {
		if (queue != null) {
			System.Console.WriteLine("AMBIGUITY:");
			System.Console.WriteLine("> " + this.rule);
			foreach (nonterminalState s in queue) {
				System.Console.WriteLine("> " + s.rule);
			}
		}
	}

	public override bool checkRejected() {
		if (this.rejected) return true;
		if (this.rightmost == null) return false;
		this.rejected = this.rightmost.checkRejected();
		int total = 1;
		int numrejected = this.rejected ? 1 : 0;

		if (this.queue != null) {
			foreach (nonterminalState nt in queue) {
				bool tmp = nt.checkRejected();
				total += 1;
				numrejected += tmp ? 1 : 0;
			}
		}
		if (numrejected == 0) return false;
		if (numrejected == total) {
			this.queue = null;
			return true;
		}
		// at least one, but not all, rejected
		System.Diagnostics.Debug.Assert(queue != null);
		if (total - numrejected == 1) {
			if (this.rejected) {
				foreach (nonterminalState nt in this.queue) {
					if (!nt.rejected) {
						this.rule = nt.rule;
						this.rejected = nt.rejected;
						this.rightmost = this.rightmost;
						break;
					}
				}
			}
			this.queue = null;
		} else {
			System.Diagnostics.Debug.Assert(total - numrejected > 1);
			System.Collections.Queue tmp = new System.Collections.Queue();
			foreach (nonterminalState nt in this.queue) {
				if (!nt.rejected) {
					if (this.rejected) {
						this.rule = nt.rule;
						this.rejected = nt.rejected;
						this.rightmost = this.rightmost;
					} else {
						tmp.Enqueue(nt);
					}
				}
			}
			this.queue = tmp;
		}
		return false;
	}

	public virtual void add(nonterminalState state, int count) {
		if (!this.rejected) {
			if (state.rejected) {
				this.rejected = state.rejected;	// true;
				this.rightmost = state.rightmost;
				this.rule = state.rule;
				this.queue = null;
			} else {
				if (queue == null) {
					queue = new System.Collections.Queue();
				}
				queue.Enqueue(state);
			}
		}
	}

	public nonterminalState() {}

	protected nonterminalState(state below, string rule, state rightmost, Coordinate end, bool rejected, int serial) : base(below, serial) {
		this.rejected = rejected;
		this.rightmost = rightmost;
		this.rule = rule;
		this.end = end;
	}

	public override string ToString(string indent) {
		string s = indent
		+ "<" + begin.ToString() + "-->" + end.ToString() + ">"
		+ " RULE: "
		+ rule + "\n";
		// string s = indent + "RULE: " + rule + "\n";
		string tmp = "";
		for (state p = rightmost; p != below; p = p.below) {
			tmp = p.ToString(indent+". ") + tmp;
		}
		s += tmp;
		if (queue != null) {
			foreach (nonterminalState nt in queue) {
				s += indent + "ALTERNATE:\n";
				s += nt.ToString(indent);
			}
		}
		return s;
	}
}


public abstract class terminalState : state {
	public InputElement terminal;

	public terminalState() {}

	protected terminalState(state below, InputElement terminal, int serial) : base(below, serial) {
		this.terminal = terminal;
	}

	public override bool checkRejected() {
		// System.Diagnostics.Debug.Assert(this.below != null);
		// if (this.rejected) return true;
		// this.rejected = this.below.checkRejected();
		// return this.rejected;
		return false;
	}

	public override string ToString(string indent) {
		return indent + terminal.tag + "\n";
	}

}
