var evalN = 0;

function Constant()
{
	;
}

function EditThunk(rc)
{
	return function() {
		var cell = cells[rc];
		return parseFloat(cell.input.value);
	}
}

function Cell(id, val, expr)
{
	this.elt = document.getElementById(id);
	this.input = document.getElementById("input_" + id);
	this.v = val;
	this.expr = expr;
}

Cell.prototype.Eval = function ()
{
	if (this.expr == Constant) {
		return 0;
	}
		var newv = this.expr();
		if (typeof newv == "string") {
			if (this.label == newv) {
				return 0;
			}
			var label;
			label = newv.replace(/&/g,"&amp;");
			label = label.replace(/</g,"&lt;");
			label = label.replace(/>/g,"&gt;");
			label = label || "&nbsp;";
			this.elt.innerHTML = label;
			this.label = newv;
			this.v = 0;
			return 1;
		} else if (newv != this.v || evalN == 0) {
			this.v = newv;
			if (!this.input) {
				this.elt.innerHTML = newv.toFixed(2);
			}
			return 1;
		} else {
			return 0;
		}
	try {
	} catch (err) {
		this.elt.innerHTML= "#ERR";
		this.v = 0;
		return 0;
	}
}

var letterA = 'A';
letterA = letterA.charCodeAt(0);

function Col2Num(c)
{
	if (c.length == 2) {
		return (c.charCodeAt(0) - letterA) * 26 + c.charCodeAt(1);
	} else {
		return (c.charCodeAt(0) - letterA);
	}
}

function Num2Col(c)
{
	if (c >= 26) {
		return String.fromCharCode(letterA + (c / 26), letterA + (c % 26));
	} else {
		return String.fromCharCode(letterA + c);
	}
}

function Range(c1, r1, c2, r2)
{
	this.c1 = Col2Num(c1);
	this.c2 = Col2Num(c2);
	if (this.c1 > this.c2) {
		var tmp = this.c2;
		this.c2 = this.c1;
		this.c1 = tmp;
	}
	this.r1 = r1;
	this.r2 = r2;
	if (this.r1 > this.r2) {
		var tmp = this.r2;
		this.r2 = this.r1;
		this.r1 = tmp;
	}
}

Range.prototype.Iterate = function(f, state)
{
	for (c = this.c1; c <= this.c2; ++c) {
		for (r = this.r1; r <= this.r2; ++r) {
			var cr = Num2Col(c) + r;
				f(state, cr, cells[cr]);
			try {
			} catch (e) {
				;
			}
		}
	}
}

function sc_if(cond, a, b)
{
	return cond ? a : b;
}

function sc_sum_f(state, cr, cell)
{
	state.v += cell.v;
}

function sc_sum(range)
{
	state = new Array();
	state.v = 0;
	range.Iterate(sc_sum_f, state);
	return state.v;
}

function EvalAll() {
	var count = 0, max = 10;
	while (EvalAllOnce())
		if (++count == max) {
			alert("Values didn't settle after "+max+" evaluations.");
			return;
		}
}

function EvalAllOnce()
{
	var again = 0;
	for (c in cells) {
		again += cells[c].Eval();
	}
	evalN++;
	return again;
}

function SetVal(rc, elt)
{
	setTimeout('EvalAll()', 10);
}
