// (C) Copyright 2008 J. A. Hodge
// All Rights Reserved

var cols = [ ];
var dragging = [ ];
var placeholders = [ ];
var curz = 0;
var original_col;
var status_timeout = 0;
var win_width = 800;
var stock_width = 800;
var safety_margin = 16;
var ad_width = 122;
var dealbutton = null;
var cardsleft_span = null;
var total_moves = 0;
var decks0 = null;
var decks1 = [ ];
var heightlist =
{
	640: 68,
	800: 88,
	1024: 119,
	1280: 153,
	1600: 196
};

function resize_window()
{
	//
	// get window width

	win_width = document.viewport.getWidth();

	//
	// find lowest common denominator

	var reslist = [ 640, 800, 1024, 1280, 1600 ];

	stock_width = reslist[0];
	for(var t = reslist.length - 1; t >= 0; t--)
	{
		if(win_width >= reslist[t] - 6)	// 6 is the for the margin
		{
			stock_width = reslist[t];
			break;
		}
	}

	new Ajax.Request('/spider/',
	{
		asynchronous: true,
		method: 'post',
		parameters: { cmd: "r" },
		onSuccess: refresh_all,
		onFailure: stdfailure
	});
}

function autosave_c()
{
	this.timeout = null;
	this.pending = false;
}
autosave_c.prototype.set = function()
{
	this.pending = false;
	this.clear();
	this.timeout = setTimeout(
		function() { this.timeout = null; save(); }, 5000);
}
autosave_c.prototype.clear = function()
{
	if(this.timeout)
	{
		clearTimeout(this.timeout);
		this.timeout = null;
	}
}
var autosave = new autosave_c()


function completed_c()
{
	this.reset();
}
completed_c.prototype.set = function(deck, col, row)
{
	if(this.flags[deck][0])
		this.flags[deck][1] = [ col, row ];
	else
		this.flags[deck][0] = [ col, row ];
}
completed_c.prototype.reset = function()
{
	this.flushed = [ 26, 26, 26, 26 ];
	this.flags = [ [false, false], [false, false], [false, false], [false, false] ];
}
var completed = new completed_c();

function create_card(cardnum, x, y, card_col, card_idx, hidden)
{
	var e = document.getElementById("splash");
	var new_el = document.createElement('img');

	new_el.className = "card"
	new_el.src = '/static/c' + stock_width + '_' + cardnum + '.png';
	new_el.style.left = x + 'px';
	new_el.style.top = y + 'px';
	if(hidden)
		new_el.style.display = 'none';
	new_el.card_col = card_col;
	new_el.card_idx = card_idx;
	new_el.card_num = cardnum - 1;	// card_num=0 means ace of hearts
	e.parentNode.insertBefore(new_el, e);

	$(new_el).observe('mousedown', dragmany);
	return new_el;
}

function undo_man_c()
{
	//this.clear();
	this.moves = [ ];
}
undo_man_c.prototype.clear = function()
{
	$("undobutton").disabled = true;
	this.moves = [ ];
}
undo_man_c.prototype.save = function(fromcol, idx, tocol)
{
	this.moves.push([fromcol, idx, tocol]);
	$("undobutton").disabled = false;
}
undo_man_c.prototype.restore = function()
{
	if(this.moves.length)
	{
		var rst = this.moves.pop();

		if(!this.moves.length)
			$("undobutton").disabled = true;

		transfer_cards(rst[2], rst[0], rst[1]);
		total_moves++;
		autosave.set();
	}
}

var undo = new undo_man_c();

function transfer_cards(fromcol, tocol, idxfrom)
{
	while(cols[fromcol].length > idxfrom)
	{
		var l = cols[tocol].push(cols[fromcol].splice(idxfrom, 1)[0]) - 1;
		cols[tocol][l].card_col = tocol;
		cols[tocol][l].card_idx = l;
		cols[tocol][l].style.left = x_from_col(tocol) + "px";
		cols[tocol][l].style.top = y_from_row(l) + "px";
		cols[tocol][l].style.zIndex = ++curz;
	}
}

function deal(event)
{
	event.stop();
	if(!cols[10].length)
	{
		alert("No more cards to deal!");
		return;
	}
	undo.clear();
	curz++;
	for(var t = 0; t < 10 && cols[10].length; t++)
	{
		if(cols[t].length)
		{
			var el = cols[10].shift();

			el.style.display = '';
			el.card_col = t;
			el.card_idx = cols[t].length;
			el.style.left = x_from_col(t) + 'px';
			el.style.top = y_from_row(cols[t].length) + 'px';
			el.style.zIndex = curz;

			cols[t].push(el);
		}
	}

	cardsleft_span.innerHTML = '' + cols[10].length;
	check_completed();
}

function unselectable(elname)
{
	var el = $(elname);

	el.onselectstart = function() {
		return false;
	};
	el.unselectable = "on";
	el.style.MozUserSelect = "none";
	el.style.cursor = "default";
}

function loaded()
{
	//
	// disable text selection, as it can be annoying

	unselectable("board_wrapper");
	unselectable("navbar");

	resize_window();
	setInterval("blinker()", 250);
	undo.clear();
}

function blinker()
{
	var bkg = 'url(/static/decks1_' + stock_width + '.png)';
	var bkghidden = 'url(/static/decks0_' + stock_width + '.png)';

	if(!decks1.length)
		return;

	if(this.clock)
		this.clock = false;
	else
		this.clock = true;

	for(var col = 0; col < 2; col++)
	{
		for(var row = 0; row < 4; row++)
		{
			var idx = row + col * 4;
			if(idx >= decks1.length)
				continue;
			var savedpos = decks1[idx].style.backgroundPosition;
			var shft = Math.floor(completed.flushed[row] / 13);
			var scol = col - shft;

			if(shft > col)
				decks1[idx].style.background = bkg;
			else
			{
				if(this.clock)
				{
					if(completed.flags[row][scol])
						decks1[idx].style.background = bkg;
					else
						decks1[idx].style.background = bkghidden;
				}
				else
					decks1[idx].style.background = bkghidden;
			}

			decks1[idx].style.backgroundPosition = savedpos;
		}
	}
}

function remove_cards()
{
	while(cols.length)
	{
		var c = cols.shift();

		while(c.length)
		{
			var el = c.shift();

			el.parentNode.removeChild(el);
		}
	}
	while(placeholders.length)
	{
		var el = placeholders.shift();

		el.parentNode.removeChild(el);
	}
	if(dealbutton)
	{
		dealbutton.parentNode.removeChild(dealbutton);
		dealbutton = null;
	}
	if(cardsleft_span)
	{
		cardsleft_span.parentNode.removeChild(cardsleft_span);
		cardsleft_span = null;
	}
	if(decks0)
	{
		decks0.parentNode.removeChild(decks0);
		decks0 = null;
	}
	while(decks1.length)
	{
		var el = decks1.shift();

		el.parentNode.removeChild(el);
	}
}

function new_game()
{
	new Ajax.Request('/spider/',
	{
		asynchronous: true,
		method: 'post',
		parameters: { cmd: "n" },
		onSuccess: function(transport) { undo.clear(); refresh_all(transport); },
		onFailure: stdfailure
	});
}

function cto()	// clear time-out
{
	if(status_timeout)
	{
		clearTimeout(status_timeout);
		status_timeout = null;
	}
}
function hide_status()
{
	$('statusmsg').innerHTML = '';
	cto();
}
function splash_status(msg)
{
	$('statusmsg').innerHTML = msg;
	cto();
	status_timeout = setTimeout(hide_status, 5000);
}

function save()
{
	var st = "";

	for(var col = 0; col < 11; col++)
	{
		st += String.fromCharCode(cols[col].length + 48)

		for(var t = 0; t < cols[col].length; t++)
			st += String.fromCharCode(cols[col][t].card_num + 1 + 48)
	}
	new Ajax.Request('/spider/',
	{
		asynchronous: true,
		method: 'post',
		parameters: { cmd: "s", state: st },
		onSuccess: function(transport)
		{
			if(transport.responseText != "OK")
				splash_status("<b>Error, game not saved</b>");
			else
			{
				autosave.clear();
				autosave.pending = false;
				splash_status("Game saved: " + transport.responseText);
			}
		},
		onFailure: stdfailure
	});
}

function stdfailure()
{
	splash_error("<b>Unable to contact server</b>");
}

function refresh_all(transport)
{
	var e = $("splash");
	var col;

	$("windiv").style.display = '';

	remove_cards();
	cols = [ ];

	var t = 0;

	//
	// create placeholders

	for(col = 0; col < 10; col++)
	{
		var new_el = document.createElement('img');

		new_el.className = "card"
		new_el.src = '/static/placeholder_' + stock_width + '.png';
		new_el.style.top = y_from_row(0) + 'px';
		new_el.style.left = x_from_col(col) + 'px';
		placeholders[col] = e.parentNode.insertBefore(new_el, e);
		unselectable(placeholders[col]);	// doesn't seem to work
	}

	for(col = 0; col < 11; col++)
		cols[col] = new Array();

	for(col = 0; col < 11 && t < transport.responseText.length; col++)
	{
		var cnt = transport.responseText.charCodeAt(t) - 48;

		if(++t + cnt > transport.responseText.length)
		{
			alert("Error: t:" + t + " cnt:" + cnt + " col" + col)
			return;		// invalid data received
		}

		for(var i = 0; i < cnt; i++)
		{
			cols[col].push(
				create_card(transport.responseText.charCodeAt(t + i) - 48,
				x_from_col(col),
				y_from_row(i), col, i, col == 10));
		}
		t += cnt;
	}

	//
	// create deal button

	var leftmost = Math.floor(((win_width - ad_width) / 11) * 0.025);
	var new_el = document.createElement('img');

	new_el.className = "card"
	new_el.src = '/static/deal_' + stock_width + '.png';
//	new_el.onmousedown = function(event) {
//		prevent_default(event); deal(); }
	new_el.style.left = leftmost + 'px';
	new_el.style.top = '28px';
	new_el.style.cursor = 'pointer';
	dealbutton = e.parentNode.insertBefore(new_el, e);
	$(new_el).observe('mousedown', deal);

	var widthlist =
	{
		640: 44,
		800: 57,
		1024: 77,
		1280: 99,
		1600: 127
	};
	var heightlist2 =
	{
		640: 480,
		800: 600,
		1024: 768,
		1280: 1024,
		1600: 1280
	};

	var w = Math.floor(widthlist[stock_width] / 3);
	var stripes = $("stripes");

	stripes.style.top = (48 + heightlist[stock_width]) + 'px';
	stripes.style.left = w + 'px';
	stripes.style.width = w + 'px';
	stripes.style.height = (heightlist2[stock_width] -
		heightlist[stock_width] - 48) + 'px';

	new_el = document.createElement('span');
	new_el.className = "cardsleft"
	new_el.innerHTML = '' + cols[10].length;
	new_el.style.left = (parseInt(dealbutton.style.left) + 8) + 'px';
	new_el.style.top = (28 + heightlist[stock_width] - 26) + 'px';
	cardsleft_span = e.parentNode.insertBefore(new_el, e);

	//
	// create completed decks indicators

	new_el = document.createElement('img');
	new_el.className = "activedeck"
	new_el.src = '/static/decks0_' + stock_width + '.png';
	new_el.style.left = leftmost + 'px';
	new_el.style.top = (28 + heightlist[stock_width] + 10) + 'px';
	decks0 = e.parentNode.insertBefore(new_el, e);

	var nextleft = 0;
	var bkg = 'url(/static/decks1_' + stock_width + '.png)';
	var bkghidden = 'url(/static/decks0_' + stock_width + '.png)';

	for(var col = 1; col < 3; col++)
	{
		var left = nextleft;
		var nexttop = 0;

		nextleft = (col * widthlist[stock_width]) >> 1;

		for(var row = 1; row < 5; row++)
		{
			var top = nexttop;

			nexttop = (row * heightlist[stock_width]) >> 2;

			new_el = document.createElement('div');
			new_el.style.background = bkg;
			new_el.deckhidden = false;
			new_el.className = "activedeck";
			new_el.style.backgroundPosition = (-left) + 'px ' + (-top) + 'px';
			new_el.style.left = (leftmost + left) + 'px';
			new_el.style.top = (28 + heightlist[stock_width] + 10 +
				top) + 'px';
			new_el.style.width = (nextleft - left) + 'px';
			new_el.style.height = (nexttop - top) + 'px';
			new_el.style.cursor = 'pointer';
			new_el.deck = row - 1;
			decks1.push(e.parentNode.insertBefore(new_el, e));
			$(new_el).observe('mousedown', function(event) {
				var el = event.element();
				var coords = completed.flags[el.deck][0];

				if(coords)
				{
					var colnum = coords[0];
					var rownum = coords[1];

					for(var t = 0; t < 13; t++)
					{
						var el = cols[colnum][rownum + t];
						el.parentNode.removeChild(el);
					}
					cols[colnum].splice(rownum, 13);
					undo.clear();
					autosave.set();
					check_completed();
				}
			});
		}
	}
	check_completed();
}

function x_from_col(col)
{
	var cardskip = (win_width - (ad_width + safety_margin)) / 11;
	return(Math.floor(col * cardskip + cardskip));
}

function y_from_row(row)
{
	return(Math.floor(row * stock_width / 42 + 28));
}

function dragmany(event)
{
	var t;
	var tgt = event.element();

	if(!check_seq(tgt.card_col, tgt.card_idx))
	{
		event.stop();
		return;
	}

	if(autosave.timeout)
		autosave.pending = true;
	autosave.clear();

	//
	// move the cards to the dragging array

	original_col = tgt.card_col;
	dragging = dragging.concat(cols[tgt.card_col].splice(tgt.card_idx,
		cols[tgt.card_col].length - tgt.card_idx))
	for(t = 0; t < dragging.length; t++)
		dragging[t].style.zIndex = ++curz;
	mouse_down(event);
}

function check_seq(card_col, card_idx)
{
	var t;

	for(t = card_idx + 1; t < cols[card_col].length; t++)
	{
		var cur_card = cols[card_col][t].card_num;
		var prv_card = cols[card_col][t - 1].card_num;

		if((cur_card != prv_card - 1 &&
			(cur_card % 13 != 12 || prv_card % 13 != 0)) ||
			Math.floor(cur_card / 13) != Math.floor(prv_card / 13))
		{
			return(false);
		}
	}
	return(true);
}

var valid_ontop = [ 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
	25, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
	38, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
	51, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50 ];

function check_completed()
{
	// 0-12  (hearts)
	// 13-25 (clubs)
	// 26-38 (diamonds)
	// 39-51 (spades)

	completed.reset();

	//
	// count the decks

	for(var col = 0; col < cols.length; col++)
		for(var row = cols[col].length - 1; row >= 0; row--)
			completed.flushed[Math.floor(cols[col][row].card_num / 13)]--;

	//
	// check winning condition

	if(completed.flushed[0] == 26 && completed.flushed[1] == 26 &&
		completed.flushed[2] == 26 && completed.flushed[3] == 26)
	{
		$("windiv").style.display = 'block';
		$("windiv").style.left = ((stock_width - 400) >> 1) + 'px';
		$("windiv").style.top = (60 + heightlist[stock_width]) + 'px';
	}

	//
	// check completed sequences

	for(var col = 0; col < cols.length; col++)
	{
		var consecutives = 0;
		var prvcard = -2;

		if(cols[col].length < 13)
			continue;		// don't bother

		for(var row = cols[col].length - 1; row >= 0; row--)
		{
			var thiscard = cols[col][row].card_num;

			if(prvcard != valid_ontop[thiscard] && consecutives)
				break;
			prvcard = thiscard;

			if(++consecutives == 13)
			{
				completed.set(Math.floor(thiscard / 13), col, row);
				consecutives = 0;
			}
		}
	}
}
