/*

NOTICE:  This code is the property of TableBrain.  It may NOT be used, copied, modified, published, retransmitted, etc for any purpose other than those permitted by TableBrain.

 */


/*

navigator.userAgent // to get the user agent string, like:
Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/XX (KHTML, like Gecko) Version/ZZ Mobile/WW Safari/YY

we want "Safari/525" or newer to do css animation
better still, see if an element has a webkitTransform() method on it's style property

 */

if (window.addProgress(5)) window.addProgress(5);

// {"name":"leonski","loggedIn":true,"cookieValue":"1487f..."}
// {"loggedIn":false,"cookieValue":"1487f..."}

if (1) {
    var rootDomain = 'tablewinner.com';
    var primaryDomain = 'www.' + rootDomain;
    var primaryURL = 'http://' + primaryDomain + '';
} else {
    var rootDomain = 'stankowski.webhop.org';
    var primaryDomain = 'www.' + rootDomain;
    var primaryURL = 'http://' + primaryDomain + ':1080';
}

var cookies = new BrainCookies({ domain: rootDomain, path: '/' });

var imagePath = '/images/';
var serverAPI = '/ws/api3.php';

var titleButtonsSpace = 160;
var titleCharWidth = 10.5;
var toolBarButtonWidth = 64;
var titleBarHeight = 40;
var menuBarHeight = 48;

var currentTime = 0;
var currentWidth = 0;
var currentHeight = 0;
var currentOrientation = null;


try {
    addEventListener('load', function() { controller.init(); }, false);
} catch (e) {
    attachEvent('onload', function() { controller.init(); });
}


window.onBeforeUnload = function() { return 'Are you sure you want to leave?'; };


var isIPhone = Prototype.Browser.iPhone;
var isIE =     Prototype.Browser.IE;
var isOpera =  Prototype.Browser.Opera;
var isGecko =  Prototype.Browser.Gecko;
var isWebKit = Prototype.Browser.WebKit;


try {
    console.log('started');
} catch (e) {
    var console = {
	log: function(msg) { alert('console.log: ' + msg); }
    };
}


var controller = {
    loggedIn: null,
    panelsContainerEl: null,
    playInfos: {},
    playInfo: null,
    playPanels: {},
    playPanel: null,
    oldScroll: 1,

    init: function() {
	document.body.setAttribute('iPhone', isIPhone ? 'T' : 'F');
	document.body.setAttribute('IE',     isIE     ? 'T' : 'F');
	document.body.setAttribute('Opera',  isOpera  ? 'T' : 'F');
	document.body.setAttribute('Gecko',  isGecko  ? 'T' : 'F');
	document.body.setAttribute('WebKit', isWebKit ? 'T' : 'F');

	setTimeout(function() { controller.updatePeriodic(); }, 0);
	setInterval(function() { controller.updatePeriodic(); }, 400);

	this.playInfos['play'] = new PlayInfo('play', 60000);      // once a minute
	this.playInfos['replay'] = new PlayInfo('replay', 600000); // once every 10 minutes

	panels.init();
	messageBoxes.init();

	this.panelsContainerEl = $('panelsContainer'); 
	this.panelsContainerEl.show();

	joinedTables.init();

	this.getContent('_msgWelcome');
	if (0) { ///// LEON LEON LEON
	    setTimeout(function() { controller.getSession(); }, 200);
	} else {
	    cookies.discard('HWSESSION');
	    setTimeout(function() { controller.getContent('accessCodeMenu'); }, 200);
	}

	//setTimeout(function() { menuButtons.requestUpdate(); }, 400);
	//setTimeout(function() { window.scrollTo(0, 1); }, 2000);
    },
    _gotSession: function() {
	window.scrollTo(0, 1);
	menuButtons.requestUpdate();
    },
    _gotMenus: function() {
	setTimeout(function() { window.scrollTo(0, 1); }, 50);	
    },
    updatePeriodic: function() {
	currentTime = (new Date()).getTime();
	var windowWidth = window.innerWidth;
	if (windowWidth === undefined) windowWidth = document.body.clientWidth;
	if (currentWidth != windowWidth) {
	    currentWidth = windowWidth;
	    if (currentWidth <= 320) {
		currentHeight = 416;
		currentOrientation = 'portrait';
	    } else {
		currentHeight = 268;
		currentOrientation = 'landscape';
	    }
	    document.body.setAttribute("orient", currentOrientation);
	    menuButtons.updateLayout();
	    panels.updateLayout();
	    setTimeout(function() { window.scrollTo(0, 1); }, 100);
	} else {
	    if (menuButtons.needLayout) menuButtons.updateLayout();
	    if (panels.needLayout) panels.updateLayout();
	}
	formManager.monitor();
	messageBoxes.updateLayout();
	joinedTables.checkStatus();
    },
    addPlayPanel: function(infoRef, action, panel) {
	this.playPanels[action] = panel;
	panel.playInfo = (typeof infoRef === 'string') ? this.playInfos[infoRef] : infoRef;
	panel.onShow = this.onPlayShow.bindAsEventListener(this);
	panel.onHide = this.onPlayHide.bindAsEventListener(this);
    },
    onPlayShow: function(panel) {
	this.playPanel = panel;
	var playInfo = panel.playInfo;
	if (this.playInfo != playInfo) {
	    this.playInfo = playInfo;
	    playInfo.getContent();
	    //console.log('controller.onPlayShow(' + panel.ref + ') playInfo changed');
	}
    },
    onPlayHide: function(panel) {
	if (this.playPanel === panel) {
	    this.playPanel = null;
	    this.playInfo = null;
	    //console.log('controller.onPlayHide(' + panel.ref + ') playInfo now null');
	}
    },
    getContent: function(ref, last) {
	var myDate = new Date();
	var query = '';
	//var last = 0;
	if (ref) {
	    query += 'ref=' + ref + '&';
	    if (ref.substr(0, 1) != '_') {
		var panel = panels[ref];
		if (panel) last = panel.lastUpdate;
	    }
	}
	if (last) query += 'last=' + last + '&';
	new Ajax.Request('/ws/getContent.php?' + query + 'n=' + myDate.getTime(), {
	    onSuccess: this.contentGot,
	    onFailure: this.contentFailed
	});
    },
    contentGot: function(response) {
	var ref = response.getHeader('myRef');
	if (ref && response.getHeader('Content-Type').match(/html/)) {
	    if (ref.substr(0, 1) == '_') {
		if (ref.substr(0, 4) == '_msg') {
		    messageBoxes.add(response.responseText);
		} else {
		    console.log('what to do with "' + ref + '" ?');
		}
	    } else {
		var lastUpdate = response.getHeader('myLast');
		panels.setContents(ref, response.responseText, lastUpdate);
	    }
	}
    },
    contentFailed: function(xhr) {
	console.log("contentGot() failed!");
    },
    startGame: function(title, url) {
	joinedTables.start(title, url);
    },
    login: function(json) {
	//if (this.loggedIn != json) {
	this.loggedIn = json;
	if (json.handle) {
	    messageBoxes.add('<h1>Successful Login</h1><div>Welcome ' + json.handle + '</div>');
	} else {
	    messageBoxes.add('<h1>Welcome Back</h1><div>Welcome back ' + json.name + '</div>');
	}
	//alert('login: need login / logout button update');
	panels.setForwardAction(null, true);
	//}
    },
    logout: function() {
	this.loggedIn = null;
	panels.setForwardAction(null, true);
    },
    sessionGot: function(response) {
	var json = null;
	if (response.getHeader) {
	    try {
		//console.log(response.getHeader('X-JSON'));
		json = eval('(' + response.getHeader('X-JSON') + ')');
	    } catch (ex) { console.log('controller.sessionGot() error: ' + ex.message); }

	    if (json) {
		if (json.loggedIn) controller.login(json);
		controller._gotSession();
		return;
	    }
	}

	console.log('something went wrong with getting a session... what to do about it?');
    },
    getSession: function() {
	new Ajax.Request(serverAPI, {
		parameters: 'wsmethod=' + encodeURIComponent('hw.cookieCheck'),
		onSuccess: this.sessionGot,
		onFailure: this.sessionGot
	    });
    }
};


var properGameNames = {
    DHLD: "Double Hold'em",
    DLRC: "Dealer's Choice",
    HLDM: "Texas Hold'em"
};

var properLimitNames = {
    LI: "Limit",
    NL: "No Limit",
    PL: "Pot Limit"
};

function PlayInfo(ref, refresh) {
    this.ref = ref;
    this.source = ref;
    this.refresh = refresh;
    this.json = null;
    this.last = 0;
    this.ajax = null;
    this.timer = null;
}

PlayInfo.prototype.newContent = function(json) {
    this.json = json;
    var panel = controller.playPanel;
    if (controller.playInfo === this && panel) { // otherwise nothing needs to be painted
	var c = [];
	var entry;
	var URLs = json.URLs;
	var tables = json.tables;
	if (URLs && tables) {
	    try {
		for (var gameName in tables) {
		    var game = tables[gameName];
		    var properGameName = properGameNames[gameName];

		    for (var limitName in game) {
			var limit = game[limitName];
			var properLimitName = properLimitNames[limitName];

			entry = {ref: gameName, title: properGameName, subTitle: [properLimitName], heading: 1};
			c.push(entry);

			for (var stakesName in limit) {
			    var stakes = limit[stakesName];
			    for (var seatCountName in stakes) {
				var seatCount = stakes[seatCountName];
				for (var tableName in seatCount) {
				    var table = seatCount[tableName];
				    table.game = gameName;
				    table.limit = limitName;
				    table.stakes = parseFloat(stakesName.replace('/', '.'));
				    table.stakesText = stakesName;
				    table.seatCount = seatCountName;

				    //var url = 'play:' + URLs[table.URL].replace(/%Unm%/, table.Unm);
				    var url = 'play:' + URLs[table.URL].replace(/%{Unm}/, table.Unm);
				    //console.log(url);

				    entry = { ref: url,
					      title: tableName,
					      subTitle: [(table.stakes ? '$' : '') + stakesName,
							 table.plc + '/' + seatCountName,
							 '$' + Math.floor(table.avp) + 'avg',
							 table.hph + 'h/h'],
					      table: table };
				    c.push(entry);
				}
			    }
			}
		    }
		}
	    } catch (e) { console.log('PlayInfo.newContent() table data confused: ' + e.message); };
	}
	panel.setContents(c, this.last);
    }
};


PlayInfo.prototype.getContent = function() {
    if (this.timer) return;
    if (controller.playInfo === this && ! this.ajax) {
	var query = 'ref=' + this.ref;
	if (this.last) query += '&last=' + this.last;
	new Ajax.Request('/ws/getPlayInfo.php?' + query, {
	    onSuccess: this.contentGot.bind(this),
	    onFailure: this.contentFailed.bind(this)
	});
    }
};

PlayInfo.prototype.getContentAgain = function() {
    this.timer = null;
    this.getContent();
};

PlayInfo.prototype.contentGot = function(response) {
    this.ajax = null;

    var last = response.getHeader('myLast');
    if (last) this.last = last;

    //console.log('PlayInfo.contentGot() do something with the content...');
    try {
	var json = eval('(' + response.responseText + ')');
	if (json) {
	    if (json.error) {
		// oopsy... let's assume temporary unavailabilty
		if ( ! this.json) {
		    this.newContent({});
		}
	    } else if (json.noChange) {
		// no change... so do nothing
	    } else {
		// new content... do the heavy lifting
		this.newContent(json);
	    }
	} else {
	    console.log('PlayInfo.contentGot() empty json received');
	}
    } catch(e) { console.log('PlayInfo.contentGot() garbage json received'); }
    
    this.timer = setTimeout(this.getContentAgain.bind(this), this.refresh);
};

PlayInfo.prototype.contentFailed = function(xhr) {
    this.ajax = null;

    console.log('PlayInfo.contentFailed() do something with the error condition?');
    
    this.timer = setTimeout(this.getContentAgain.bind(this), this.refresh);
};


var joinedTables = {
    maxCurrent: 3000,
    maxRecent: 120000,
    tables: {},
    init: function() {
	this.checkStatus(true);
    },
    checkStatus: function(initial) {

	return;

	var tables = this.tables;
	var dropList = [];
	var myCookies = cookies.getAll();
	for (var cookieName in myCookies) {
	    // table:name = status,lastUpdate
	    var nameParts = cookieName.split(':');
	    if (nameParts.length > 1) {
		if (nameParts[0] == 'table') {
		    var tableName = nameParts[1];
		    var table = tables[tableName];
		    var cookieValue = myCookies[cookieName];
		    var values = cookieValue.split(',');
		    var status = values[0];
		    var timeStamp = values[1];
		    var age = currentTime - timeStamp;
		    if (table) {
			if (age < this.maxRecent) {
			    if (age < this.maxCurrent) {
				// A-OK, leave it alone
			    } else {
				// gone bad?
			    }
			    table.timeStamp = timeStamp;
			    table.status = status;
			} else {
			    // definitely bad... clean it up
			}
			if (status === 'quit') {
			    // done... clean it up
			}
		    } else if (initial) {
			if (age < this.maxRecent && status === '') {
			}
		    } else {
			// tables being joined after we (this lobby) started
			if (age < this.maxRecent) {
			    
			}
		    }
		    ;
		    ;
		    ;
		}
	    }
	}
	// looks at cookies for tables
	// if they are current then make Table for each one
	// if they are recent then offer to take user to them (erase otherwise)
	// if out of date erase them




	for (var tableTitle in tables) {
	    var table = tables[tableTitle];
	    if ( ! table.checkStatus()) dropList.push(tableTitle);
	}
	var dropListLength = dropList.length;
	for (var i = 0; i < dropListLength; ++i)
	    delete tables[dropList[i]];
    },
    start: function(title, url) {
	var tables = this.tables;
	var table = tables[title];
	if ( ! table) table = new Table(title);
	if (table.start(url)) {
	    this.tables[title] = table;
	} else {
	    alert('sorry, there is a problem starting that table');
	}
    }
};

function Table(title) {
    this.status = null;
    this.windowHandle = null;
    this.title = title;
}

Table.prototype.start = function(url) {
    // if window already exists
    //   and is active then give it focus
    //   is not active then
    // create window
    // set initial cookie for window

    var w = window.open(url, this.title,
			'status=no,toolbar=no,menubar=no,location=no,resizable=no,scrollbars=no' +
			(( ! isIPhone) ? ',height=490,width=400' : ''));
    this.windowHandle = w;
    if (w) w.focus();
    return w ? true : false;
};

Table.prototype.checkStatus = function() {
    gameStatus = cookies.get('gameInfo');
    if (gameStatus == 'finished') {
	cookies.set('gameInfo', 'none');
	controller.putBack();
    }
};


var messageBoxes = {
    el: null,
    contentEl: null,
    okEl: null,
    waitingEl: null,
    waitingContentEl: null,
    darkenEl: null,
    showing: false,
    showingWaiting: false,
    messageQueue: [],
    lastMargin: null,

    init: function() {
	this.el = $("messageBox");
	this.contentEl = $('messageBoxContent');
	this.darkenEl = $('darken');
	this.okEl = $('messageBoxOK');

	this.waitingEl = $('messageWaiting');
	this.waitingContentEl = $('messageWaitingContent');

	this.el.hide();
	this.okEl.show();

	this.okEl.observe('click', function() { messageBoxes.done(); });
    },
    _show: function(message) {
	this.contentEl.innerHTML = message;
	//BrainEffect.Appear(this.el, { duration: 0.5 });
	this.el.show();
	this.darkenEl.show();
	this.showing = true;
    },
    _hide: function() {
	this.el.hide();
	if ( ! this.showingWaiting) this.darkenEl.hide(); 
	this.showing = false;
    },
    updateHeight: function(newHeight) {
	//console.log(newHeight);
	this.darkenEl.style.height = newHeight + 'px';
    },
    updateLayout: function() {
	if (this.showing || this.showingWaiting) {
	    var offsets = document.viewport.getScrollOffsets();
	    var margin = offsets.top;
	    if (this.lastMargin != margin) {
		this.lastMargin != margin;
		if (this.showing) this.el.style.marginTop = margin + 'px';
		if (this.showingWaiting) this.waitingEl.style.marginTop = margin + 'px';
	    }
	}
    },
    add: function(message) {
	if (this.showing) {
	    this.messageQueue.push(message);
	} else {
	    this._show(message);
	}
    },
    done: function() {
	this._hide();
	var message = this.messageQueue.pop();
	if (message) this._show(message);
    },
    waiting: function(message) {
	this.waitingContentEl.innerHTML = message;
	this.waitingEl.show();
	this.darkenEl.show();
	this.showingWaiting = true;
    },
    doneWaiting: function() {
	mb = messageBoxes;
	mb.waitingEl.hide();
	if ( ! mb.showing) mb.darkenEl.hide();
	mb.showingWaiting = false;
    }
};

if (window.addProgress(5)) window.addProgress(5);

var menuButtons = {
    menuButtons: [],
    moreMenuButton: null,
    moreMenuButtonEl: null,
    el: null,
    containerEl: null,
    morePanel: null,
    selectedButton: null,
    lastUpdate: 0,
    needLayout: false,

    init: function(morePanel) {
	this.morePanel = morePanel;
	this.containerEl = $('panelMenuButtons');
	this.el = $('menuButtonBar');
	this.add('more', 'More', 'more');
	this.needLayout = true;
    },
    add: function(ref, title, icon) {
	var menuButtons = this.menuButtons;
	var menuButtonsLen = menuButtons.length;
	var menuButton;
	for (var i = 0; i < menuButtonsLen; ++i) {
	    menuButton = menuButtons[i];
	    if (menuButton.ref == ref) return;
	}
	menuButton = new MenuButton(ref, title, icon);
	if (ref == 'more') {
	    this.moreMenuButton = menuButton;
	    this.moreMenuButtonEl = menuButton.el;
	} else {
	    this.menuButtons.push(menuButton);
	    this.needLayout = true;
	}
    },
    remove: function(ref) {
	var menuButton = this.menuButtons[ref];
	if (menuButton) {
	    menuButton.remove();
	    delete this.menuButtons[ref];
	}
    },
    removeAll: function() {
	this.selectedButton = null;
	var menuButtons = this.menuButtons;
	var menuButtonsLen = menuButtons.length;
	for (var i = 0; i < menuButtonsLen; ++i)
	    menuButtons[i].remove();
	this.menuButtons = [];
	this.needLayout = true;
    },
    updateLayout: function() {
	if (currentWidth > 0) {
	    this.needLayout = false;

	    var menuButtons = this.menuButtons;
	    var max = Math.floor(currentWidth / toolBarButtonWidth);
	    var menuButtonsLen = menuButtons.length;
	    var tooMany = menuButtonsLen > max;
	    if (tooMany) {
		this.moreMenuButton.show();
		--max;
	    } else {
		this.moreMenuButton.hide();
		max = menuButtonsLen;
	    }

	    var moreEntries = [];
	    for (var i = 0; i < menuButtonsLen; ++i) {
		var menuButton = menuButtons[i];
		if (i < max) {
		    menuButton.show();
		} else {
		    menuButton.hide();
		    moreEntries.push(menuButton);
		}
	    }
	    
	    this.morePanel.setContents(moreEntries, 0);

	    if (( ! this.selectedButton) && menuButtonsLen) {
		var mb = menuButtons[0];
		mb.select(); //{ observee: mb });
	    }
	}
    },
    select: function(ref) {
	var menuButtons = this.menuButtons;
	var menuButtonsLen = menuButtons.length;
	for (var i = 0; i < menuButtonsLen; ++i) {
	    var menuButton = menuButtons[i];
	    if (menuButton.ref == ref) {
		menuButton.select();
		return;
	    }
	}
    },
    requestUpdate: function() {
	controller.getContent(null, this.lastUpdate);
	//{ onSuccess: this.scheduleUpdate, onFailure: this.scheduleUpdate });
    },
    scheduleUpdate: function() {
	setTimeout(function() { menuButtons.requestUpdate(); }, 60000);
    }
};


function MenuButton(ref, title, icon) {
    this.ref = ref;
    var id = ref + '_menuButton';
    this.id = id;
    this.title = title || ref.capitalize();
    this.icon = icon;
    this.isMore = (ref == 'more');

    var el = document.createElement('div');
    el.setAttribute('id', id);
    //el.me = this;
    menuButtons.el.insertBefore(el, menuButtons.moreMenuButtonEl);
    el = $(id);

    var html = (icon ? ('<img id="' + id + '_img" src="' + imagePath + icon + '.n.png" /><br />') : '');
    html += this.title;
    el.innerHTML = html;

    this.imgEl = $(id + '_img');
    this.el = el;

    el.observe('click', this.select.bindAsEventListener(this));
    //el.observe('click', this.select);
}

MenuButton.prototype.remove = function() { 
    this.el.stopObserving('click');
    menuButtons.el.removeChild(this.el);
};

MenuButton.prototype.select = function(e) {
    var old = menuButtons.selectedButton;
    if (old != this) {
	if (old) old.unselect();

	this.el.addClassName('menuSelected');
	if (this.imgEl) this.imgEl.src = imagePath + this.icon + '.y.png';
	menuButtons.selectedButton = this;
    }
    panels.select(this.ref, this.title, 'menu');
};

MenuButton.prototype.unselect = function(e) {
    this.el.removeClassName('menuSelected');
    if (this.imgEl) this.imgEl.src = imagePath + this.icon + '.n.png';
};

MenuButton.prototype.show = function() { this.el.show(); };
MenuButton.prototype.hide = function() { this.el.hide(); };


var panels = {
    panels: {},
    titleEl: null,
    backEl: null,
    forwardEl: null,
    containerEl: null,
    containerSliderEl: null,
    panelEls: [],
    currentIndex: null,
    currentPanel: null,
    currentHeight: -1,
    isSliding: false,

    init: function() {
	this.titleEl = $('panelTitle');
	this.containerEl = $('panelsCenter');
	this.containerSliderEl = $('centerSlider');
	this.panelEls[0] = $('panel0');
	this.panelEls[1] = $('panel1');
	this.currentIndex = 0;

	var button;
	button = $('buttonBack');
	button.observe('click', function(e) { panels.select(); } );
	this.backEl = button;

	button = $('buttonForward');
	button.observe('click', function(e) { panels.goForward(); } );
	this.forwardEl = button;

	var panel;
	panel = this.add('login', 'Login', null, 'register');
	panel = this.add('register', 'Register', null, null);
	panel = this.add('account', 'Account', null, null);

	panel = this.add('play', 'Play');
	controller.addPlayPanel('play', 'play', panel);

	panel = this.add('replay', 'Replay');
	controller.addPlayPanel('replay', 'replay', panel);

	this.add('more', 'More');
	menuButtons.init(this.panels.more);
    },
    add: function(ref, title, icon, forwardAction) {
	var panel = this.panels[ref];
	if ( ! panel) {
	    panel = new Panel(ref, title, forwardAction);
	    this.panels[ref] = panel;
	    if (icon) menuButtons.add(ref, title, icon);
	}
	return panel;
    },
    get: function(ref) {
	return this.panels[ref];
    },
    setContents: function(ref, contents, lastUpdate) {
	var panel = this.panels[ref];
	if (panel) panel.setContents(contents, lastUpdate);
    },
    showTitle: function() {
	if (this.currentPanel) {
	    //console.log('showTitle');
	    var title = this.currentPanel.title;
	    var available = (currentWidth - titleButtonsSpace) / titleCharWidth;
	    if (title.length > available) title = title.substr(0, available - 2) + '...';
	    this.titleEl.innerHTML = title;
	}
    },
    buttonSetTitle: function(el, title) {
	var available = 8;
	if (title.length > available) title = title.substr(0, available - 2) + '...';
	el.innerHTML = title;
    },
    buttonTransition: function(el, oldTitle, newTitle, newIsRound) {
	if (oldTitle) {
	    if (newTitle) {
		BrainEffect.Fade(el, {
		    duration: 0.25,
		    title: newTitle,
		    atFinish: function(e) {
			panels.buttonSetTitle(e.el, e.extra.title);
			BrainEffect.Appear(e.el, { duration: 0.25 });
		    }
	        });

	    } else {
		BrainEffect.Fade(el, { duration: 0.5 });
	    }
	} else {
	    panels.buttonSetTitle(el, newTitle);
	    BrainEffect.Appear(el, { duration: 0.5 });
	}
    },
    goForward: function() {
	var action = this.forwardAction;
	if (this.forwardAction == 'login_account') {
	    action = controller.loggedIn ? 'account' : 'login';
	}
	this.select(action);
    },
    setForwardAction: function(panel) {
	if ( ! panel) panel = this.currentPanel;
	var action = panel.forwardAction;
	var oldForward = this.forwardAction; // currentPanel ? currentPanel.forwardAction : null;
	if (oldForward != action) {
	    var newTitle = null;
	    switch (action) {
	    case 'login_account':
		newTitle = controller.loggedIn ? 'Account' : 'Login+';
		break;
	    case 'register':
		newTitle = 'Register';
		break;
	    }
	    this.buttonTransition(this.forwardEl, oldForward, newTitle);
	    this.forwardAction = action;
	}
    },
    selectE: function(ref, title) {
	this.select(ref, title, 'entry');
    },

    select: function(ref, title, source) {
	var currentPanel = this.currentPanel;
	var oldForward = this.forwardAction; // currentPanel ? currentPanel.forwardAction : null;
	var panel;

	if (this.isSliding) return;

	formManager.stop();

	if (ref) { // forward
	    var newRef = ref;
	    if (ref.substr(0, 5) == 'play:')   newRef = ref.substr(5);
	    if (ref.substr(0, 7) == 'replay:') newRef = ref.substr(7);
	    if (ref !== newRef) {
		controller.startGame(title, newRef);
		return;
	    }

	    panel = this.panels[ref];
	    if ( ! panel) {
		panel = this.add(ref, title);
		var playPanel = currentPanel ? currentPanel.playPanel : false;
		if (source === 'entry' && playPanel) controller.addPlayPanel(playPanel, ref, panel);
	    }

	    if (currentPanel === panel) return;

	    if (source === 'menu') { // pop forward
		var el = this.panelEls[this.currentIndex];

		if (this.currentPanel) this.currentPanel.freeEl();
		this.backEl.hide();
		this.currentPanel = panel;
		//this.showTitle();
		window.scrollTo(0, 1);
		el.show();
		panel.setEl(el);
		//this.needLayout = true;
	    
	    } else { // slide forward
		panel.backPanel = this.currentPanel;
		this.currentIndex = 1 - this.currentIndex;
		panel.setEl(this.panelEls[this.currentIndex]);
		this.slideLeft(panel);
	    }
	} else { // slide back
	    panel = this.currentPanel.backPanel;
	    this.currentIndex = 1 - this.currentIndex;
	    panel.setEl(this.panelEls[this.currentIndex]);
	    this.slideRight(panel);
	}

	this.setForwardAction(panel);
    },
    updateLayout: function() {
	//console.log('updateLayout');
	this.showTitle();

	var panelEl = this.panelEls[this.currentIndex];
	var height = 0;
	if (panelEl) {
	    if (document.defaultView) {
		var style = document.defaultView.getComputedStyle(panelEl, "");
		height = parseInt(style.getPropertyValue("height"));
	    } else {
		height = panelEl.offsetHeight;
		//alert(height);
	    }
	}
	if (height > 0) {
	    ; // nothing (special case for ignoring NaN and a real value)
	} else {
	    height = currentHeight - titleBarHeight - menuBarHeight;
	}
	if (this.currentHeight != height && isIPhone)
	    messageBoxes.updateHeight(height + titleBarHeight + menuBarHeight);

	if (this.currentHeight != height || this.needLayout) {
	    this.currentHeight = height;
	    this.containerEl.style.height = height + "px";

	    if (isIPhone) {
		var top = titleBarHeight + height;
		var showing = currentHeight - top;
		//var yScrolled = window.pageYOffset;
		if (showing <= 0) { // none
		    BrainEffect.Move(menuButtons.containerEl, { x: 0, y: currentHeight }, {
			startAt: { x: 0, y: currentHeight - menuBarHeight },
			duration: 0.5,
			postY: top,
			atFinish: function(e) { e.el.style.top = e.extra.postY + "px"; }
		    });
		} else if (showing < menuBarHeight) { // partial
		    BrainEffect.Move(menuButtons.containerEl, { x: 0, y: top }, {
			startAt: { x: 0, y: currentHeight - menuBarHeight },
			duration: 0.5
		    });
		} else { // all
		    menuButtons.containerEl.style.top = top + "px";
		}
	    }
	}
	this.needLayout = false;
    },
    slideLeft: function(panel) {  this._slideInit(panel, true); },
    slideRight: function(panel) { this._slideInit(panel); },
    _slideStart: function(e) {
	var ex = e.extra;
	var s = e.el, po = ex.pOut, pi = ex.pIn, o = po.el, i = pi.el;
	var isLeft = (ex.direction == 'left');
	s.style.left = isLeft ? '0px' : '-' + currentWidth + 'px';
	o.style.left = isLeft ? '0px' : currentWidth + 'px';
	i.style.left = isLeft ? currentWidth + 'px' : '0px';
	i.show();
	panels.needLayout = true;
    },
    _slideFinish: function(e) {
	var ex = e.extra;
	var s = e.el, po = ex.pOut, pi = ex.pIn, o = po.el, i = pi.el;
	s.style.left = '0px';
	i.style.left = '0px';
	o.hide();
	panels.currentPanel = pi
	panels.showTitle();
	panels.isSliding = false;
	po.freeEl();
    },
    _slideInit: function(panel, isLeft) {
	var currentPanel = this.currentPanel;
	var backEl = this.backEl;

	if (currentPanel === panel) return;

	this.isSliding = true;
	window.scrollTo(0, 1);
	BrainEffect.Move(this.containerSliderEl, { x: (isLeft ? -(currentWidth) : 0), y: 0 }, {
	    startAt: { x: (isLeft ? 0 : - (currentWidth)), y: 0 },
	    duration: 0.5,
	    pOut: currentPanel,
	    pIn: panel,
	    direction: (isLeft ? 'left' : 'right'),
	    atStart: this._slideStart,
	    atFinish: this._slideFinish
	});

	this.buttonTransition(backEl, currentPanel.backPanel,
			      panel.backPanel ? panel.backPanel.title : null);
    }
};


function Panel(ref, title, forward) {
    this.ref = ref;
    //var id = name.split(/\W+/).collect(function(s) { return s.capitalize(); }).join('');
    this.id = 'p_' + ref;
    this.title = title || ref.capitalize();
    this.lastUpdate = 0;
    this.forwardAction = forward === undefined ? "login_account" : forward;
    this.contents = null;
}

Panel.prototype.setEl = function(el) {
    this.el = el;
    this._paint();
    if (this.onShow)
	this.onShow(this);
    else if (this.contents === null)
	controller.getContent(this.ref);
};

Panel.prototype.freeEl = function() {
    if (this.el) {
	if (this.onHide) this.onHide(this);
	this.el = null;
    }
};

Panel.prototype._paint = function() {
    var el = this.el;
    if (el) {
	var html = '';
	var possibleForm = false;

	if (this.contents === null) {
	    html = '<div class="contentLoading" />';
	} else if (typeof this.contents == 'string') {
	    if (this.contents == '') {
		html = '<div class="empty">empty document</div>';
	    } else {
		html = '<div class="contentPage">' + this.contents + '</div>';
		possibleForm = true;
	    }
	} else {
	    // assuming entries list
	    var entries = this.contents;
	    entryCount = entries.length;
	    if (entryCount > 0) {
		html = '';
		var hasIcons = false;
		for (var i = 0; i < entryCount; ++i) {
		    var entry = entries[i];
		    html += '<div class="h' + (entry.heading ? entry.heading : '0') + '"';
		    if (entry.ref) {
			html += ' onclick="panels.selectE(\'' + entry.ref + '\', \'' +
			    entry.title.replace(/\'/g, '\\\'') + '\')"' +
			    '><div class="hi">';
		    } else {
			html += '>';
		    }
		    if (entry.icon) {
			html += '<img src="' + imagePath + entry.icon + '.y.png" />';
			hasIcons = true;
		    } else {
			html += '<span class="if" />';
		    }
		    html += entry.title;
		    var subTitles = entry.subTitle;
		    if (subTitles) {
			var subTitlesLen = subTitles.length;
			for (var j = 0; j < subTitlesLen; ++j) {
			    html += '<span class="st' + j + '">' + subTitles[j] + '</span>';
			}
		    }
		    if (entry.ref) html += '</div>';
		    html += '</div>';
		}
		html = '<div class="contentDrillDown' + (hasIcons ? 'Icons' : '') + '">' + html + '</div>';

	    } else {
		html = '<div class="empty">empty list</div>';
	    }
	}
	el.innerHTML = html;

	$$('#' + el.id + ' script').each(function (el) {
		try {
		    eval(el.innerHTML);
		} catch (ex) {
		    console.log('eval of panel scripts: ' + ex.message);
		}
	    }, this);

	if (possibleForm) formManager.start(this, el);

	panels.needLayout = true;
    }
};

if (window.addProgress(5)) window.addProgress(5);

Panel.prototype.setContents = function(contents, lastUpdate) {
    if (this.lastUpdate == 0 || lastUpdate > this.lastUpdate) {
	this.contents = contents;
	if (lastUpdate > 0) this.lastUpdate = lastUpdate;
	this._paint();
    }
};


var formManager = {
    fields: null,
    actions: null,
    currentField: null,
    ajaxRequest: null,
    passwordRegExp: /password/i,

    statusUnknown: 0,
    statusRequired: 1,
    statusBad: 2,
    statusServerTest: 3,
    statusGood: 4,

    start: function(panel, el) {

	//console.log('formManager.start()');

	this.getAjaxObject(this.ajaxRequest);

	this.fields = {};
	this.actions = [];

	var fieldValues = panel.fieldValues || {};
	var hasFields = false;
	$$('#' + el.id + ' form').each(function (el) {
		el.observe('submit', this.userFormSubmit);
	    }, this);
	$$('#' + el.id + ' input').each(function (el) {
		var name = el.name;
		if (name) {
		    hasFields = true;
		    this.addField(el, name);
		    var value = fieldValues[name];
		    if (value) el.value = value;
		}
	    }, this);
	$$('#' + el.id + ' select').each(function (el) {
		var name = el.getAttribute('name');
		if (name) {
		    hasFields = true;
		    this.addField(el, name);
		    var value = fieldValues[name];
		    if (value !== undefined) el.value = value;
		}
	    }, this);
	$$('#' + el.id + ' .switch').each(function (el) {
		var name = el.getAttribute('name');
		if (name) {
		    hasFields = true;
		    this.addField(el, name);
		    var value = fieldValues[name];
		    if (value !== undefined) this.switchClick(el, value);
		}
	    }, this);
	$$('#' + el.id + ' .button').each(function (el) {
		var action = el.getAttribute('action');
		if (action) this.addAction(el, action);
	    }, this);

	if (hasFields || this.actions.len) {
	    this.panel = panel;
	    panel.fieldValues = fieldValues;

	    var fields = this.fields
	    for (var key in fields) {
		var f = fields[key];
		//this.fieldStatusChanged(f);
		this.validateField(f);
	    }
	} else {
	    this.panel = null;
	}
    },
    stop: function() {
	var fields = this.fields;
	if (fields) {
	    var fieldValues = this.panel ? this.panel.fieldValues : null;
	    for (var key in fields) {
		var f = fields[key];
		if (f.el && fieldValues) {
		    if (f.isSwitch) {
			fieldValues[key] = f.value;
		    } else if (f.isForget) {
			fieldValues[key] = '';
		    } else {
			fieldValues[key] = f.el.value;
		    }
		}
		this.removeField(f);
	    }
	    this.fields = null;
	}
	var actions = this.actions;
	if (actions) {
	    var actionsLen = actions.length;
	    for (var i = 0; i < actionsLen; ++i) {
		var a = actions[i];
		this.removeAction(a);
	    }
	    this.actions = null;
	}
    },
    getAjaxObject: function(ajax) {
	if ( ! ajax) {
	    ajax = Ajax.getTransport();
	    this.ajaxRequest = ajax;
	    ajax.fields = {};
	    ajax.currentField = null;
	    ajax.currentValue = null;
	} else if (ajax.readyState != 0 && ajax.readyState != 4) {
	    ajax.abort();
	}
    },
    _serverTest: function(f) {
	//console.log('_serverTest f.name="' + (f ? f.name : 'null') + '"');
	var ajax = this.ajaxRequest;

	if (f) {
	    var el = f.el;
	    if (el) {
		var value = el.value;
		if (ajax.currentField !== f || ajax.currentValue !== value) {
		    var readyState = ajax.readyState;
		    if (readyState != 0 && readyState != 4) ajax.abort();
		    
		    ajax.open('POST', serverAPI, true);
		    ajax.currentField = f;
		    ajax.currentValue = value;
		    ajax.onreadystatechange = this.serverTestResult.bind(this);
		    ajax.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
		    var request = 'wsmethod=' + encodeURIComponent(el.config.testServer) + '&' +
			encodeURIComponent(f.name) + '=' + encodeURIComponent(value);
		    ajax.send(request);
		}
	    }
	}
    },
    serverTest: function(f) {
	//console.log('serverTest f.name="' + (f ? f.name : 'null') + '"');
	f.serverWaitTimer = null;
	if (f.status != this.statusServerTest) return;
	var el = f.el;
	if ( ! el) return;

        var ajax = this.ajaxRequest;

	if (ajax.currentField === f || ! ajax.currentField) {
	    this._serverTest(f);
	} else {
	    ajax.fields[f.name] = f;
	}

	f.inServerTest = true;		    
    },
    serverTestNext: function() {
	//console.log('serverTestNext');
	var ajax = this.ajaxRequest;
	if (ajax) {
	    ajax.currentField = null;
	    ajax.currentValue = null;
	    for (var key in ajax.fields) {
		var f = ajax.fields[key];
		if (f.el) {
		    this._serverTest(f);
		    break;
		} else {
		    delete ajax.fields[key];
		}
	    }	    
	}	
    },
    serverTestCancel: function(f) {
	//console.log('serverTestCancel f.name="' + (f ? f.name : 'null') + '"');
	var ajax = this.ajaxRequest;
	if (ajax) {
	    if ( ! f) f = ajax.currentField;
	    if (f) {
		var isCurrent = false;
		if (f === ajax.currentField) {
		    isCurrent = true;
		    var readyState = ajax.readyState;
		    if (readyState != 0 && readyState != 4) ajax.abort();
		}
		delete ajax.fields[f.name];
		f.inServerTest = false;

		if (isCurrent) this.serverTestNext();
	    }
	}

	//panels.titleEl.innerHTML = '';
    },
    serverTestResult: function() {
	var ajax = this.ajaxRequest;
	//console.log('serverTestResult readyState=' + ajax.readyState);

	if (ajax.readyState == 4) {
	    var f = ajax.currentField;
	    if (f) {
		f.inServerTest = false;
		f.msg = '';

		if (f.status === this.statusServerTest) {
		    delete ajax.fields[f.name];
		
		    var el = f.el;
		    if (el) {
			if (ajax.currentValue == el.value) {
			    try {
				if (ajax.status == 200) {
				    //console.log('response = "' + ajax.responseText + '"');
				    //console.log('X-JSON = "' + ajax.getResponseHeader('X-JSON') + '"');
				    var result = { success: false };
				    try {
					result = eval('(' + ajax.getResponseHeader('X-JSON') + ')');
				    } catch (ex) { console.log(ex.message); }
				    //console.log('result: ' + result.success + ', ' + result.error);
				    f.status = result.success ? this.statusGood : this.statusBad;
				    if (f.status === this.statusBad) f.msg = result.error;
				    
				} else {
				    // this is actually a bad thing... but...
				    // we really have no choice but to act as if it is OK
				    f.status = this.statusGood;
				}
				this.fieldStatusChanged(f);
			    } catch (ex) {
				// something bad...  try again with a fresh ajax object
			        this.getAjaxObject(null); 
			    }
			} else {
			    // ook... value changed while testing... ignore
			}
		    } else {
			//console.log('el=' + el);
			// ook... looks like the form went away while being tested... ignore
		    }
		} else {
		    //console.log('f.status=' + f.status + ', X-JSON="' + ajax.getResponseHeader('X-JSON') + '"');
		    // result returned to late... ignore
		}
	    }

	    this.serverTestNext();
	}
    },
    addField: function(el, name) {
	var id = el.id;
	var f = {
	    el: el,
	    name: name,
	    value: null,
	    status: this.statusUnknown,
	    serverWaitTimer: null,
	    inServerTest: false,
	    isSwitch: el.className.indexOf('switch') < 0 ? false : true
	};

	var isType = f.isSwitch ? 'switch' : el.getAttribute('type');
	f.isType = isType ? isType.toLowerCase() : 'input';
	f.isForget = this.passwordRegExp.test(f.isType) || el.getAttribute('forget');

	if (el.getAttribute('noauto')) {
	    el.setAttribute('autocomplete', 'off');
	    el.setAttribute('autocapitalize', 'off');
	    el.setAttribute('autocorrect', 'off');
	}
	if (name) {
	    if (el.tagName == 'INPUT') {
	        el.observe('focus', this.focus);
	        el.observe('blur', this.blur);
	    } else if (el.tagName == 'SELECT') {
		el.observe('change', this.change);
	    } else if (f.isSwitch) {
		var imgID = id + '_iSwitch';
		el.innerHTML = '<div id="' + imgID + '"></div>';
		f.imgEl = $(imgID);
		el.value = true;
		el.observe('click', this.switchClick);
		f.status = this.statusGood;
	    }
	}
	f.glyphEl = $(id + '_glyph');
	f.msgEl = $(id + '_msg');
	el.me = f;
	this.fields[name] = f;
    },
    removeField: function(f) {
	var el = f.el;
	try {
	    el.me = null;
	    el.stopObserving('focus');
	    el.stopObserving('blur');
	    el.stopObserving('click');
	    el.stopObserving('change');
	} catch (ex) { };
	el.me = null;
	delete this.fields[el.name];
    },
    addAction: function(el, action) {
	var a = { el: el, action: action, ready: null, name: el.getAttribute('name') };
	var id = el.id;
	if (id) {
	    var msgEl = $(id + '_msg');
	    if (msgEl) {
		msgEl.hide();
		a.msgEl = msgEl;
	    }
	}
	var ready = true;
	var fields = [];
	var aFields = el.getAttribute('fields');
	if (aFields) {
	    var fieldNames = aFields.split(' ');
	    var fieldNamesLen = fieldNames.length;
	    for (var i = 0; i < fieldNamesLen; ++i) {
		var name = fieldNames[i];
		var f = this.fields[name];
		if (f) {
		    if (f.status != this.statusGood) ready = false;
		    fields.push(f);
		} else {
		    alert('action can NOT find field "' + name + '"');
		}
	    }
	}
	a.fields = fields;
	el.me = a;
	this.actions.push(a);
	this.setActionStatus(a, ready);
	el.observe('click', this.actionClick);
    },
    removeAction: function(a) {
	var el = a.el;
	try {
	    this.el.stopObserving('click');
	} catch (ex) { };
	el.me = null;
	//delete formManager.actions[a.action];
    },
    setActionStatus: function(a, ready) {
	if (a) {
	    var el = a.el;
	    if (el) {
		if (a.ready !== ready) {
		    a.ready = ready;
		    var names = el.className;
		    names = names.replace('disabled', '');
		    names = names.replace('green', '');
		    el.className = names + ' ' + (ready ? 'green' : 'disabled');
		}
	    }
	}
    },
    updateActions: function() {
	var good = this.statusGood;
	var actions = this.actions;
	var actionsLen = actions.length;
	for (var ai = 0; ai < actionsLen; ++ai) {
	    var a = actions[ai];
	    var ready = true;
	    var fields = a.fields;
	    var fieldsLen = fields.length;
	    for (var fi = 0; fi < fieldsLen; ++fi) {
		var f = fields[fi];
		if (f.status != good) {
		    ready = false;
		    break;
		}
	    }
	    if (a.ready != ready) {
		this.setActionStatus(a, ready);
		if (ready && a.msgEl) a.msgEl.hide();
	    }
	}
    },
    buildServerQuery: function(a) {
	var query = 'wsmethod=' + encodeURIComponent(a.action);
	var fields = a.fields;
	var fieldsLen = fields.length;
	for (var i = 0; i < fieldsLen; ++i) {
	    var f = fields[i];
	    query += '&' + encodeURIComponent(f.name) + '=' + encodeURIComponent(f.value);
	}
	//console.log('query: ' + query);
	return query;
    },
    fieldStatusChanged: function(f) {	
	var glyphEl = f.glyphEl;
	var msgEl = f.msgEl;
	var msg = '';
	var classNames = 'fieldStatusGlyph';
	switch (f.status) {
	case this.statusUnknown:
	    classNames += ' fieldStatusBad';
	    msg = '???';
	    break;
	case this.statusRequired:
	case this.statusBad:
	    classNames += ' fieldStatusBad';
	    msg = f.msg;
	    break;
	case this.statusServerTest:
	    classNames += ' fieldStatusTesting';
	    break;
	case this.statusGood:
	    classNames += ' fieldStatusGood';
	    break;
	}
	if (glyphEl) {
	    glyphEl.className = classNames;
	    //console.log(f.name + ': glyphEl className = "' + classNames + '"');
	} else {
	    //console.log(f.name + ': glyphEl is undefined');
	}
	if (msgEl) msgEl.innerHTML = msg;

	this.updateActions();
    },
    validateField: function(f, immediate) {
	var el = f.el;
	var config = el.config;
	var value = el.value;
	if (typeof value === 'string') value = value.replace(/^\s\s*/, '').replace(/\s\s*$/, '');

	if (f.value !== value) {
	    if (f.inServerTest) this.serverTestCancel(f);
	    if (f.serverWaitTimer !== null) {
		clearTimeout(f.serverWaitTimer);
		f.serverWaitTimer = null;
	    }
	    
	    f.value = value;
	    var status = this.statusGood;
	    var errMsg = f.msg;

	    if (config) {
		if (value == '') {
		    if (config.required) {
			status = this.statusRequired;
			errMsg = 'required';
		    }
		} else {
		    var t = config.testNow;
		    if (t) {
			try {
			    errMsg = t(value, f);
			    if (errMsg) status = this.statusBad;
			} catch (ex) {
			    alert('validate field: ' + ex.message);
			}
		    }
		    if (config.testServer && status == this.statusGood) {
			status = this.statusServerTest;
			if (immediate) {
			    this.serverTest(f);
			} else {
			    f.serverWaitTimer = setTimeout(function() { formManager.serverTest(f); }, 1000);
			}
		    }
		}
	    }
	    if (f.status != status || f.msg != errMsg) {
		f.status = status;
		f.msg = errMsg;
		this.fieldStatusChanged(f);
	    }
	} else if (immediate && f.status == this.statusServerTest && f.serverWaitTimer !== null) {
	    clearTimeout(f.serverWaitTimer);
	    f.serverWaitTimer = null;
	    this.serverTest(f);
	}
    },
    focus: function(e) {
	var fm = formManager;
	if (fm.currentField) fm.validateField(fm.currentField, true);
	fm.currentField = e.observee.me;
    },
    blur: function(e) {
	var fm = formManager;
	if (fm.currentField) fm.validateField(fm.currentField, true);
	fm.currentField = null;
    },
    monitor: function() {
	var f = this.currentField;
	if (f) this.validateField(f);
    },
    change: function(e) {	
	var el = e.observee;
	var f = el.me;
	formManager.validateField(f, true);
    },
    switchClick: function(e, value) {
	var el = e.observee || e;
	var f = el.me;
	if (value === undefined) value = ! f.value;
	if (f.value !== value) {
	    f.value = value;
	    BrainEffect.MarginLeft(f.imgEl, { duration: 0.25, finishAt: value ? 0 : -48 });
	}
    },
    attemptAction: function(a) {
	if (a.ready) {
	    try {
		var actionMsg = a.el.getAttribute('actionMsg') || 'working';
		messageBoxes.waiting(actionMsg);
		//setTimeout(function() { messageBoxes.doneWaiting(); }, 2000);

		var query = this.buildServerQuery(a);
		new Ajax.Request(serverAPI, {
		    parameters: query,
		    onSuccess: this.actionGot,
		    onFailure: this.actionFailed
	        });

	    } catch (ex) {
		console.log('attemptAction: ' + ex.message);
	    };
	    
	} else if (a.msgEl) {
	    a.msgEl.show();
	}
    },
    actionGot: function(response) {
	messageBoxes.doneWaiting();
	//console.log('got: ' + response.responseText);
	//X-JSON {"success":false,"error":"Could not send confirmation email!"}
	var json = null;
	try {
	    //console.log(response.getHeader('X-JSON'));
	    json = eval('(' + response.getHeader('X-JSON') + ')');
	} catch (ex) { console.log('actionGot() error: ' + ex.message); }

	if (json) {
	    if (json.success) {
		if (json.loggedIn) {
		    controller.login(json);
		} else if (json.loggedOut) {
		    controller.logout(json);
		} else {
		    messageBoxes.add(json.msg || '<h1>Success</h1>');
		    if (json.cookieValue) { ////  HACK LEON LEON LEON HACK
			var panel = panels.currentPanel; 
			panel.el.innerHTML = '';
			controller.sessionGot(response);
		    }
		}
		panels.select();
	    } else {
		messageBoxes.add(json.error || '<h1>Error Processing Request</h1>');
	    }
	} else {
	    messageBoxes.add('<h1>Internal Error</h1><div>Response from server was not understood.  Please try your request again later.</div>');
	}
    },
    actionFailed: function(xhr) {
	messageBoxes.doneWaiting();
	messageBoxes.add('<h1>Internal Error</h1><div>Internal error attempting to process your request.  Please try again later.</div>');
    },
    actionClick: function(e) {
	var el = e.observee;
	var a = el.me;
	if (a) formManager.attemptAction(a);
    },
    userFormSubmit: function(e) {
	try {
	    var el = e.observee;
	    var action = el.getAttribute('action');

	    var actions = formManager.actions;
	    if (actions) {
		var actionsLen = actions.length;
		for (var i = 0; i < actionsLen; ++i) {
		    var a = actions[i];
		    if (a.name == action) {
			formManager.attemptAction(a);
			return false;
		    }
		}
	    }
	    alert('userFormSubmit: can NOT find action "' + action + '"');

	} catch (ex) {
	    console.log('userFormSubmit: ' + ex.message);
	}
	return false;
    }
};

if (window.addProgress(5)) window.addProgress(5);
