// DataLounge.com Ajax Browsing
// (c) 2009 by Mediapolis, inc.
// All rights reserved
//

var threads 				= new posting(0,null);

var gCurrentThreadFilter 	= 'all';
var gCurrentThreadSortOrder = 'byLastPostDate';
var gCurrentThreadPage 		= 1;
var gCurrentThread 			= '';
var gCurrentThreadReplyPage = 1;
var gCurrentHighWaterMark 	= 0;
var gCurrentSearch 			= null;
var gCurrentSearchTerms		= '';
var gCurrentThreadSearchHits= '';
var gCurrentSearchThreadOnly= false;
var gTieBreaker				= 0;
var gUid					= getCookie('uid');
var gAuthName				= getCookie('authname');
var gSubscription			= getCookie('contributor');
var gPrimetime				= '';
var gPrimetimeDialog		= false;
var gPaneIsVisible			= new Array();
var gDebug					= false;
var gCunts 					= ['helen','joan','neely','joan-bette'];
var gCurrentCunt			= 'logo';


var gXmlFeed				= '/cgi-bin/iowa/threads-v1.3.xml';
var gXmlPost				= '/cgi-bin/iowa/ajax-post-v1.3.xml';

var staticSort				= null;
var itemsPerPage			= getCookie('settings_items_per_page') * 1;
if(!itemsPerPage) {
	itemsPerPage = 20;
}

var ignoredPosters			= new Array();

var gPollingFrequency		= 60000;
var gPollingForNewPosts		= null;
var gSleepTimer				= null;
var gSleeping				= false;

function debug(message) {
	if(gDebug) {
		var status_pane = document.getElementById('debug');
		if(status_pane) {
			status_pane.innerHTML += '<br>' + message;
		}
	}
}

function log(message) {
	var status_pane = document.getElementById('status');
	if(status_pane) {
		status_pane.innerHTML = message;
	}
}

function posting(row, xml) {
	this.record 		= row;	
	this.xml			= xml;
	this.loaded			= false;
	this.dirty			= false;
	this.viewed			= false;
	this.ignored		= false;
	this.ignoredByUser  = false;
	this.postings 		= new Array();
	this.reply			= 0;
	this.thread			= null;
	this.dirtyCount		= 0;
	this.poll_options 	= new Array();
	this.marked 		= false;
	if(xml) {
		this.create_sort			= xml.getElementsByTagName('create_timestamp').item(0).getAttribute('sort');
		this.create_timestamp 		= getXmlFirstChildData('create_timestamp', xml);
		this.last_post_sort			= xml.getElementsByTagName('last_posting_timestamp').item(0).getAttribute('sort');
		this.last_posting_timestamp	= getXmlFirstChildData('last_posting_timestamp', xml);
		this.posting_count	= getXmlFirstChildData('posting_count', xml);
		this.subject 		= getXmlFirstChildData('subject', xml);
		this.body			= getXmlFirstChildData('body', xml);
		this.url			= getXmlFirstChildData('url', xml);
		this.author			= getXmlFirstChildData('author', xml);
		this.cookie			= getXmlFirstChildData('cookie', xml);
		this.ww				= getXmlFirstChildData('ww', xml);
		this.ff				= getXmlFirstChildData('ff', xml);
		this.readonly		= getXmlFirstChildData('readonly', xml);
		this.keywords		= getXmlFirstChildData('keywords', xml);
		this.authenticated	= xml.getElementsByTagName('author').item(0).getAttribute('authenticated');
		this.poll_question  = getXmlFirstChildData('poll_question', xml);
		this.poll_options[0]= getXmlFirstChildData('poll_option0', xml);
		this.poll_options[1]= getXmlFirstChildData('poll_option1', xml);
		this.poll_options[2]= getXmlFirstChildData('poll_option2', xml);
		this.poll_options[3]= getXmlFirstChildData('poll_option3', xml);
		this.poll_options[4]= getXmlFirstChildData('poll_option4', xml);
		this.poll_options[5]= getXmlFirstChildData('poll_option5', xml);
		this.poll_options[6]= getXmlFirstChildData('poll_option6', xml);
		this.poll_options[7]= getXmlFirstChildData('poll_option7', xml);
		this.poll_options[8]= getXmlFirstChildData('poll_option8', xml);
		this.poll_options[9]= getXmlFirstChildData('poll_option9', xml);
		if(isIgnored(this.cookie) != -1) {
			this.ignoredByUser = true;
		}
		
		this.subject = this.subject.replace(/<br>/g,' ');
		this.subject = this.subject.replace(/<p>/g,'');
		this.subject = this.subject.replace(/<\/p>/g,'');
	}
		
	this.lastPage = function () {
		var pages = (this.posting_count / itemsPerPage);
		if(pages != Math.floor(pages)) { pages = Math.floor(pages) + 1; }
		return pages;
	}
		
	this.addPosting = function (p) {			
		// log('adding post ' + p.record + ' to thread ' + this.record);
		this.postings.push(p);
		this.last_post_sort 		= p.create_sort;
		this.last_posting_timestamp	= p.create_timestamp;
		this.posting_count = this.postings.length;
		
		p.reply = this.posting_count;
		p.thread = this;
	}
	
	this.findPosting = function (r) {
		var i;
	
		if(r == 0) { return threads; }

		for(var i = 0; i < this.postings.length; ++i) {
			if(this.postings[i].record == r) {
				return this.postings[i];
			}
		}
		
		return null;
	}
	
	this.markDirty = function () {
		if(this.thread) {
			this.dirty = true;
			this.thread.dirty = true;
			this.thread.dirtyCount++;
		}
	}
	
	this.markClean = function () {
		if(this.dirty && this.thread) {
			this.dirty = false;
			this.thread.dirtyCount--;
			if(this.thread.dirtyCount == 0) {
				this.thread.dirty = false;
			}
		}
	}

	this.processIgnored = function () {
		for(var i = 0; i < this.postings.length; ++i) {
			this.postings[i].ignoredByUser = false;
			if(isIgnored(this.postings[i].cookie) != -1) {
				this.postings[i].ignoredByUser = true;

				var div = document.getElementById(this.postings[i].record);
				if(div) {
					div.innerHTML = 'poster ignored [<a href="javascript:dontIgnorePoster(' + this.record + ',' + this.postings[i].record + ');">X</a>]';
				}
			}
			this.postings[i].processIgnored();
		}
	}
}

function unIgnore(cookie) {
	var i = isIgnored(cookie);
	if(i != -1) {
		ignoredPosters.splice(i,1);
	}
}

function isIgnored(cookie) {
	for(var i = 0; i < ignoredPosters.length; i++) {
		if(ignoredPosters[i] == cookie) {
			return i;
		}
	}
	
	return -1;
}

function setupAjax() {
	var http_request = null;
	
	if (window.XMLHttpRequest) { // Mozilla, Safari, ...
		http_request = new XMLHttpRequest();
	} else if (window.ActiveXObject) { // IE
		try {
			http_request = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				http_request = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e) {}
		}
	}

	if (!http_request) {
		alert('Browser unable to make AJAX request');
	}

	return http_request;
}

function getXmlFirstChildData(tag,xmldoc) {

	var node = xmldoc.getElementsByTagName(tag).item(0);
	
	if(node && node.firstChild) { 
		return unescape(node.firstChild.data);
	}
	else {
		return "";
	}
}

function getThreadList() {
	log('loading recently active threads...');
	var http_request = setupAjax();
	http_request.onreadystatechange = function() { getThreadListDone(http_request); };
	http_request.open('GET', gXmlFeed + '?active=1', true);
	http_request.send(null);
}

function getThreadListDone(http_request) {
	if (http_request.readyState == 4) {
		if (http_request.status == 200) {		
			var xmldoc = http_request.responseXML;

			if(getXmlFirstChildData('polling-frequency',xmldoc)) {
				gPollingFrequency = getXmlFirstChildData('polling-frequency',xmldoc);
				// alert('new polling frequency ' + gPollingFrequency);
			}

			gCurrentHighWaterMark 	= getXmlFirstChildData('highwater',xmldoc);
			gPrimetime 				= getXmlFirstChildData('primetime',xmldoc);
			
			var postings = xmldoc.getElementsByTagName('post');
			
			if(postings) {
				for(var i = postings.length - 1; i >= 0; --i) {
					var record = getXmlFirstChildData('record', postings[i]);
					var post = new posting(record,postings[i]);
					threads.addPosting(post);
				}
			}
			log('loaded. waiting for new posts.');
			
			refreshHashPage();
			
			getMarks();
			
			getWW();
			
			gPollingForNewPosts = window.setTimeout("getNewPosts()", 30000); // 30 seconds
		}
		else {
			alert("getThreadListDone status:" + http_request.status);
		}
	}
}

function getMarks() {
	var marks = getCookie('marks');
	if(marks) {
		marks = unescape(marks);
		var markList = marks.split(',');
		var need = new Array();
		for(var i = 0; i < markList.length; i++) {
			t = threads.findPosting(markList[i]);
			if(!t) {
				need.push(markList[i]);
			}
			else {
				mark(markList[i]);
			}
		}
		
		if(need.length) {
			var rows = need.join(',');
			log('loading old marked threads ' + rows);
			var http_request = setupAjax()
			http_request.onreadystatechange = function() { getMarksDone(http_request); };
			http_request.open('GET', gXmlFeed + "?rows=" + rows, true);
			http_request.send(null);
		}
	}
}

function getMarksDone(http_request) {
	if (http_request.readyState == 4) {
		if (http_request.status == 200) {		
			var xmldoc = http_request.responseXML;
			processNewPosts(xmldoc);			
			var postings = xmldoc.getElementsByTagName('post');
			for(var i = 0; i < postings.length; i++) {
				mark(getXmlFirstChildData('record', postings[i]));
			}
		}
		else {
			alert("getPostDone status:" + http_request.status);
		}
	}
}


function getPost(post) {
	log('loading post ' + post);

	var http_request = setupAjax()
	http_request.onreadystatechange = function() { getPostDone(http_request); };
	http_request.open('GET',gXmlFeed + "?rows=" + post, true);
	http_request.send(null);
}

function getPostDone(http_request) {
	if (http_request.readyState == 4) {
		if (http_request.status == 200) {		
			var xmldoc = http_request.responseXML;
			processNewPosts(xmldoc);			
		}
		else {
			alert("getPostDone status:" + http_request.status);
		}
	}
}


function getThread(thread, page, searching) {
	gCurrentThread			= thread;
	gCurrentThreadReplyPage = page;
	gSearchingThread		= searching;

	log('loading thread ' + thread);

	var http_request = setupAjax()
	http_request.onreadystatechange = function() { getThreadDone(http_request); };
	http_request.open('GET', gXmlFeed + "?thread=" + thread + '&sync=' + gCurrentHighWaterMark, true);
	http_request.send(null);
}

function getThreadDone(http_request) {
	if (http_request.readyState == 4) {
		if (http_request.status == 200) {
			var xmldoc = http_request.responseXML;
			if(getXmlFirstChildData('polling-frequency',xmldoc)) {
				gPollingFrequency = getXmlFirstChildData('polling-frequency',xmldoc);
			}
			gPrimetime = getXmlFirstChildData('primetime',xmldoc);
			var postings = xmldoc.getElementsByTagName('post');
			var thread = getXmlFirstChildData('thread', xmldoc);
			if(postings && postings.length) {
				var t = threads.findPosting(thread);
				if(!t) {
					var record = getXmlFirstChildData('record', postings[0]);
					t = new posting(record, postings[0]);
					threads.addPosting(t);				
				}
				t.loaded = true;
				t.dirty  = false;
				for(var i = 1; i < postings.length; ++i) {
					var record = getXmlFirstChildData('record', postings[i]);
					var parent = getXmlFirstChildData('parent', postings[i]);
					var post = new posting(record, postings[i]);
					t.addPosting(post);
				}
				if(gSearchingThread) {
					searchResultsThread(thread, 1);
				}
				else {
					displayThread(thread,gCurrentThreadReplyPage);
				}
				log('thread loaded. waiting for new posts.');
			}
			else {
				alert('thread does not exist.');
				listThreads(gCurrentThreadFilter, gCurrentThreadSortOrder, gCurrentThreadPage)
			}
		}
		else {
			alert("getThread status: " + http_request.status);
		}
	}
}

function processNewPosts(xmldoc) {
	var postings = xmldoc.getElementsByTagName('post');
	var newCount  = 0;
	
	if(getXmlFirstChildData('primetime',xmldoc)) {
		gPrimetime = getXmlFirstChildData('primetime',xmldoc);
	}
	
	if(getXmlFirstChildData('highwater',xmldoc)) {
		gCurrentHighWaterMark = getXmlFirstChildData('highwater',xmldoc);
	}
	if(postings) {
		for(var i = 0; i < postings.length; ++i) {
			var record = getXmlFirstChildData('record', postings[i]);
			var parent = getXmlFirstChildData('parent', postings[i]);
			
			if(!parent) {
				t = threads.findPosting(record);
				if(!t) {
					var post = new posting(record,postings[i]);
					threads.addPosting(post);
					post.dirty = true;
					++newCount;
				}
			}
			else {
				t = threads.findPosting(parent);
				if(t) {
					if(t.loaded) {
						if(!t.findPosting(record)) {
							var post = new posting(record, postings[i]);
							t.addPosting(post);
							post.markDirty();
							++newCount;
						}
						else {
							// log("post " + record + " ignored already on thread " + parent);
						}
					}
					else {
						t.last_post_sort = postings[i].getElementsByTagName('create_timestamp').item(0).getAttribute('sort');
						t.last_posting_timestamp = getXmlFirstChildData('last_posting_timestamp', postings[i]);

						++t.posting_count;
						t.dirty = true;
						++newCount;
					}
				}
				else {
					getPost(parent);
				}
			}
		}
		
		if(newCount) {
			log('Found new posts');
			refreshNew();
		}
		else {
			log('Waiting for new posts');
		}
	}
}

function getNewPosts() {

	gPollingForNewPosts = null;

	if(gCurrentHighWaterMark && !gSleeping && gPollingFrequency > 0) {
		log('checking for new posts');
		var http_request = setupAjax()
		http_request.onreadystatechange = function() { getNewPostsDone(http_request); };
		http_request.open('GET', gXmlFeed + "?highwater=" + gCurrentHighWaterMark, true);
		http_request.send(null);
	}
	else {
		if(gPollingFrequency > 0) {
			log('Sleeping. <a href="javascript:resetSleepTimer()">Click here</a> to wake up.');
		}
		else {
			log('Stopped. Connection closed');
		}
	}
}

function getNewPostsDone(http_request) {
	if (http_request.readyState == 4) {
		if (http_request.status == 200) {		
			var xmldoc = http_request.responseXML;
			processNewPosts(xmldoc);

			if(getXmlFirstChildData('polling-frequency',xmldoc)) {
				gPollingFrequency = getXmlFirstChildData('polling-frequency',xmldoc);
				// alert('new polling frequency ' + gPollingFrequency);
			}
			
			if(gPollingFrequency > 0) {
				gPollingForNewPosts = window.setTimeout("getNewPosts()", gPollingFrequency);
			}
		}
		else {
			alert("getNewPostsDone status:" + http_request.status);
		}
	}
}

function byReplyCount(a,b) {
	return b.posting_count - a.posting_count;
}

function byCreateDate(a,b) {
	return b.create_sort - a.create_sort;
}

function byLastPostDate(a,b) {
	return b.last_post_sort - a.last_post_sort;
}

function hideAll() {
	debug('hideAll');
	hidePane('thread');
	hidePane('searchform');
	hidePane('searchthreadform');
	hidePane('search');
	hidePane('searchthread');
	hidePane('postingForm');
	hidePane('list');
	showPane('busy');
	scroll(0,0);
}

function showListPane() {
	hidePane('busy');
	showPane('list');
}

function showThreadPane() {
	hidePane('busy');
	showPane('thread');
}

function showSearchPane() {
	hidePane('busy');
	showPane('searchform');
	showPane('search');
}

function listStatic() {
	listThreads(gCurrentThreadFilter, gCurrentThreadSortOrder, gCurrentThreadPage)
	if(gCurrentThread) {			
		div = document.getElementById(gCurrentThread);
		if(div) {
			var pos = findPos(div);
			window.scroll(0,pos[1] - 70);
		}
	}
}

function formatPost(post,threadlist,showsubject,brief,op,markClean,searching) {
	var buffer = '';
	
	if(post.dirty) {
		buffer += '<div id="' + post.record + '" class="dirty_border">';
		if(markClean) {
			post.markClean();
		}
	}
	else if(post.viewed) {
		buffer += '<div id="' + post.record + '" class="viewed_border">';
	}
	else {
		buffer += '<div id="' + post.record + '" class="unread_border">';
	}
	
	if(post.ignoredByUser) {
		buffer += 'poster ignored [<a href="javascript:dontIgnorePoster(' + post.thread.record + ',' + post.record + ');">X</a>]';
	}
	else if(post.ignored) {
		buffer += 'thread ignored';
	}
	else {
		if(showsubject) {
			var tools = '';
			if(threadlist) {
				if(searching) {
					tools += '[<a href="javascript:searchThread(' + post.record + ')">search thread</a>]<br>';
				}
				if(post.loaded && post.dirty) {
					tools += '[<a href="javascript:setLocationHash(\'showDirty,' + post.record + '\')">show unread</a>]<br>';
				}
				if(post.posting_count > itemsPerPage) { 
					tools += '[<a href="javascript:setLocationHash(\'showThread,' + post.record + ',' + post.lastPage() + '\')">last page</a>]<br>';
				}
			}
			else {
				tools += 'flag: [<a href="javascript:flagWW(' + post.thread.record + ',' + post.record + ');">ww</a>] ';
				tools += '[<a href="javascript:flagFF(' + post.thread.record + ',' + post.record + ');">ff</a>]';
			}
			if(tools) {
				buffer += '<div class="tools">';
				buffer += tools;
				buffer += '</div>';
			}
			if(op) {
				if(post.marked) {
					buffer += '<img src="/mark-on.gif" width=13 height=13 onClick="mark(' + post.record + ',this);" style="vertical-align:middle;"> ';
				}
				else {
					buffer += '<img src="/mark-off.gif" width=13 height=13 onClick="mark(' + post.record + ',this);" style="vertical-align:middle;"> ';
				}
			}
			if(threadlist) {
				buffer += '<a href="javascript:setLocationHash(\'showThread,' + post.record + ',1\')" class="subject">';
			}
			buffer += '<span class="subject">' + post.subject + '</span>';
			if(threadlist) {
				buffer += '<\/a>';
			}
		}
		else {
			buffer += '<div  class="tools">';
			buffer += 'flag: [<a href="javascript:flagWW(' + post.thread.record + ',' + post.record + ');">ww</a>] ';
			buffer += '[<a href="javascript:flagFF(' + post.thread.record + ',' + post.record + ');">ff</a>]';
			buffer += '</div>';
		}
		
		var formatted = markup(post,brief); 

		buffer += formatted;
		
		if(post.url) {
			buffer += '<p>' + markupUrl(post.url,threadlist) + '</p>';
		}
		
		if(post.poll_question) {
			if(!threadlist) {
				buffer += '<div class="poll" id="poll_' + post.record + '">';
				buffer += 'Take Poll: <i>' + post.poll_question + '</i><ul>';
				for(var o = 0; o < 10; o++) {
					if(post.poll_options[o]) {
						buffer += '<input type=radio name=poll value="' + o + '" onClick="submitPoll(' + post.record + ',\'' + o +'\');"> ' + post.poll_options[o] + '<br>';
					}
				}
				buffer += '</ul>Select option to vote or [<a href="javascript:showPollResults(' + post.record + ');">show results</a>]';
				buffer += '</div>';
			}
			else {
				buffer += '<p>[<span class="link">see poll inside</span>]</p>';
			}
		}
		
		buffer += '<table width="476" cellpadding=0 cellspacing=0><tr><td width=245 valign=top class="author"><span class="by">by:</span> ' + post.author;
		if(post.authenticated) {
			buffer += ' <span class=authenticated>(authenticated)</span>';
		}
		buffer += '</td><td align=center valign=top>';
		if(op) {
			buffer += '<span class="replies">replies</span> ' + post.posting_count;
		}
		else {
			buffer += '<span class="replies">reply</span> ' + post.reply;
		}
		buffer += '</td><td align=right valign=top class="date">';
		if(threadlist) {
			buffer += post.last_posting_timestamp;
		}
		else {
			buffer += post.create_timestamp;
		}
		buffer += '</td></tr></table>';
		
		// if(op) {
		// 	buffer += '<p>[<a href="javascript:ignoreThread(' + post.record + ');">ignore thread</a>] ';
		// }
		// buffer += '[<a href="javascript:ignorePoster(' + post.thread.record + ',' + post.record + ');">ignore poster</a>] ';
		
	}
	
	buffer += '</div>';
	return buffer;
}

function listThreadsPage(page) {
	scroll(0,0);
	listThreads(gCurrentThreadFilter,gCurrentThreadSortOrder,page);
}

function refreshNew() {
	var buffer = '';
	var marked_buffer = '';
	var div = document.getElementById('new');
	if(div) {
		var sorted;
		var filtered = new Array();
		
		sorted = threads.postings.sort(byLastPostDate);
		if(sorted.length) {
			for(var i = 0; i < sorted.length; i++) {
				if(sorted[i].marked) {
					if(sorted[i].loaded) {
						++gTieBreaker;
						marked_buffer += '<tr><td valign=top><img src="/mark-on.gif" width=13 height=13 onClick="mark(' + sorted[i].record + ',this);" style="vertical-align:middle;"> <a href="javascript:setLocationHash(\'showDirty,' + sorted[i].record + ',' + gTieBreaker + '\')">' + sorted[i].subject + '</a></td><td valign=top align=right>' + sorted[i].dirtyCount + '</td></tr>';
					}
					else {
						marked_buffer += '<tr><td valign=top><img src="/mark-on.gif" width=13 height=13 onClick="mark(' + sorted[i].record + ',this);" style="vertical-align:middle;"> <a href="javascript:setLocationHash(\'showThread,' + sorted[i].record + '\')">' + sorted[i].subject + '</a></td><td valign=top align=right>' + sorted[i].posting_count + '</td></tr>';
					}
				}
			}
			for(var i = 0; i < sorted.length && i < 25; i++) {
				if(!sorted[i].marked && sorted[i].dirty) {
					if(sorted[i].loaded) {
						++gTieBreaker;
						buffer += '<tr><td valign=top><img src="/mark-off.gif" width=13 height=13 onClick="mark(' + sorted[i].record + ',this);" style="vertical-align:middle;"> <a href="javascript:setLocationHash(\'showDirty,' + sorted[i].record + ',' + gTieBreaker + '\')">' + sorted[i].subject + '</a></td><td valign=top align=right>' + sorted[i].dirtyCount + '</td></tr>';
					}
					else {
						buffer += '<tr><td valign=top><img src="/mark-off.gif" width=13 height=13 onClick="mark(' + sorted[i].record + ',this);" style="vertical-align:middle;"> <a href="javascript:setLocationHash(\'showThread,' + sorted[i].record + ',1\')">' + sorted[i].subject + '</a></td><td valign=top align=right>' + sorted[i].posting_count + '</td></tr>';
					}
				}
			}
		}
		div.innerHTML = '<table>' + marked_buffer + buffer + '</table>';
	}
}


function listThreads(filter,sortOrder,page) {

	if(sortOrder == 'static' && !staticSort) {
		sortOrder = 'byLastPostDate';
	}
	if(!page) { page = 1; }

	gCurrentThreadFilter 	= filter;
	gCurrentThreadSortOrder = sortOrder;
	gCurrentThreadPage      = page;
	
	var page_options = '';
	var buffer = '';
	var div = document.getElementById('threadlist');
	if(div) {
		var sorted;
		var filtered = new Array();

		if(filter == 'read') {
			page_options = 'Read Threads';
		}
		else if(filter == 'unread') {
			page_options = 'Un-Read Threads';
		}
		else if(filter == 'dirty') {
			page_options = 'New Threads';
		}
		else if(filter == 'all') {
			page_options = 'All Threads';
		}
		
		if(sortOrder == 'byLastPostDate') {
			sorted = threads.postings.sort(byLastPostDate);
			page_options += ' By Last Post Date';
		}
		else if (sortOrder == 'byCreateDate') {
			sorted = threads.postings.sort(byCreateDate);
			page_options += ' By Thread Create Date';
		}
		else if (sortOrder == 'byReplyCount') {
			sorted = threads.postings.sort(byReplyCount);
			page_options += ' By Reply Count';
		}
		else {
			sorted = staticSort;
		}

		document.title = 'List ' + page_options + ' (page ' + page + ')';
		
		staticSort = sorted;
		
		if(sorted.length) {
		
			if(filter == 'all') {
				filtered = sorted;
			}
			else {
				for(var i = 0; i < sorted.length; i++) {
					if(filter == 'read') {
						if(sorted[i].viewed) {
							filtered.push(sorted[i]);
						}
					}
					else if(filter == 'unread') {
						if(!sorted[i].viewed) {
							filtered.push(sorted[i]);
						}
					}
					else if(filter == 'dirty') {
						if(sorted[i].dirty) {
							filtered.push(sorted[i]);
						}
					}
					else if(filter == 'all') {
						filtered.push(sorted[i]);
					}
				}
			}

			var pagination;
			
			if(filtered.length > itemsPerPage) {
				pagination = paginate(page, itemsPerPage, filtered, 'listThreads,' + filter + ',' + sortOrder);
				buffer += '<table cellpadding=10 cellspacing=0 width="100%" class=pagination><tr><td class="pagination_description">thread ' + pagination.page_buffer + ' threads</td><td align=right>' + pagination.pagination_buffer + '</td></tr></table>';
				filtered = pagination.items;
			}
			
			for(var i = 0; i < filtered.length; i++) {
				buffer += formatPost(filtered[i],true,true,true,true,false);
			}

			if(pagination) {
				buffer += '<table cellpadding=10 cellspacing=0 width="100%" class=pagination><tr><td class="pagination_description">thread ' + pagination.page_buffer + ' threads</td><td align=right>' + pagination.pagination_buffer + '</td></tr></table>';
			}

		}
		else {
			buffer = 'nothing found';
		}
		div.innerHTML = buffer;
	}
	showListPane();
}

function listRepliesPage(page) {
	displayThread(gCurrentThread, page);
}

function showDirty(thread) {
	gCurrentThread = thread;
	scroll(0,0);
	var div = document.getElementById('postlist');
	if(div) {
		var buffer = '';
		var filtered = new Array();
		var t = threads.findPosting(thread);
		if(t) {

			gCurrentThreadReplyPage = t.lastPage();

			document.title = 'Thread Unread Posts: ' + t.subject;

			buffer += '<div class="viewed_border">';
			if(t.marked) {
				buffer += '<img src="/mark-on.gif" width=13 height=13 onClick="mark(' + t.record + ',this);" style="vertical-align:middle;"> ';
			}
			else {
				buffer += '<img src="/mark-off.gif" width=13 height=13 onClick="mark(' + t.record + ',this);" style="vertical-align:middle;"> ';
			}
			buffer += 'Unread Posts Re: <span class="subject">' + t.subject + '</span>';
			buffer += '</div>';
			
			buffer += '<div class=controls style="border-top:0;">[<a href="javascript:setLocationHash(\'showThread,' + t.record + ',1\')">show all posts in thread</a>]';

			if(t.posting_count > itemsPerPage) { 
				buffer += ' [<a href="javascript:setLocationHash(\'showThread,' + t.record + ',' + t.lastPage() + '\')">last page</a>]';
			}
			
			buffer += '</div>';

			var sorted = t.postings.sort(byCreateDate);
			
			for(var i = 0; i < sorted.length; i++) {
				if(sorted[i].dirty) {
					filtered.push(sorted[i]);
				}
			}
			
			if(filtered.length) {
				filtered.reverse();
						
				for(var i = 0; i < filtered.length; i++) {
					buffer += formatPost(filtered[i],false,false,false,false,true);
				}
			}
			else {
				buffer += '<div class="unread_border">No unread posts.</div>';
			}
			
		}
		else {
			alert('thread ' + thread + ' not found');
		}
		
		div.innerHTML = buffer;
	}

}

function displayThread(thread, page) {
	gCurrentThread 			= thread;
	gCurrentThreadReplyPage = page;
	
	if(!page) { page = 1; }
		
	var div = document.getElementById('postlist');
	if(div) {
		var buffer = '';
		var filtered = new Array();
		var t = threads.findPosting(thread);
		if(t) {
		
			document.title = 'Thread: ' + t.subject + ' (page ' + page + ')';
		
			if(page < 2) {
				buffer = formatPost(t,false,true,false,true,true);
			}
			else {
				buffer += '<div class="viewed_border">';
				if(t.marked) {
					buffer += '<img src="/mark-on.gif" width=13 height=13 onClick="mark(' + t.record + ',this);" style="vertical-align:middle;"> ';
				}
				else {
					buffer += '<img src="/mark-off.gif" width=13 height=13 onClick="mark(' + t.record + ',this);" style="vertical-align:middle;"> ';
				}
				buffer += '<span class="subject">Re: ' + t.subject + '</span>';
				buffer += '</div>';
			}
			var sorted = t.postings.sort(byCreateDate);
			
			filtered = sorted;
			
			filtered.reverse();
			
			var pagination;
			
			if(filtered.length > itemsPerPage) {
				pagination = paginate(page, itemsPerPage, filtered, 'showThread,'+ thread);
				buffer += '<table cellpadding=10 cellspacing=0 width="100%" class=pagination><tr><td class="pagination_description">Reply ' + pagination.page_buffer + '</td><td align=right>' + pagination.pagination_buffer + '</td></tr></table>';
				filtered = pagination.items;
			}
			
			for(var i = 0; i < filtered.length; i++) {
				buffer += formatPost(filtered[i],false,false,false,false,true);
			}

			if(pagination) {
				buffer += '<table cellpadding=10 cellspacing=0 width="100%" class=pagination><tr><td class="pagination_description">Reply ' + pagination.page_buffer + '</td><td align=right>' + pagination.pagination_buffer + '</td></tr></table>';
			}
			
			t.viewed = true;
		}
		else {
			alert('thread ' + thread + ' not found');
		}
		
		div.innerHTML = buffer;
	}

	showThreadPane();

	refreshNew();
}

function showThread(thread, page) {	
	var t = threads.findPosting(thread);
	if(t) {
		if(t.loaded) {
			displayThread(thread, page);
		}
		else {
			getThread(thread, page);
		}
	}
	else {
		getThread(thread, page);
	}
}

function hidePane(id) {
	if(gPaneIsVisible[id] != 'hidden') {
		debug('hidePane: ' + id);
		if(0 && gPaneIsVisible[id] == 'shown') {
			Effect.Fade(id, { duration: .3 });		
		}
		else {
			div = document.getElementById(id);
			if(div) {
				div.style.display = 'none';
			}
		}
		gPaneIsVisible[id] = 'hidden';
	}
}

function showPane(id) {
	if(gPaneIsVisible[id] != 'shown') {
		debug('showPane: ' + id);
		if(0 && gPaneIsVisible[id] == 'hidden' && id != 'busy') {
			Effect.Appear(id, { duration: .3 });		
		}
		else {
			div = document.getElementById(id);
			if(div) {
				div.style.display = '';
			}
		}
		gPaneIsVisible[id] = 'shown';
	}
}

function paginate(page, items_per_page, items, callback) {
	
	if(!page) { page = 1; }
	else { page = page * 1 } // it might be a string
	
	var item_count = items.length;

	var first_item = (page * items_per_page) - (items_per_page - 1);

	var last_item  = first_item + items_per_page - 1;
	if(last_item > item_count) { last_item = item_count; }

	var items_on_page = new Array();	
	for(var i = first_item; i <= last_item; ++i) {
		items_on_page.push(items[i - 1]);
	}

	var page_buffer = first_item + ' - ' + last_item + ' of ' + item_count;
	var pagination_buffer = '';
	
	if(item_count > items_per_page) {

		var pages = (item_count / items_per_page);
		
		if(pages != Math.floor(pages)) { pages = Math.floor(pages) + 1; }

		var next_page = page + 1;
		if(next_page > pages) { next_page = pages; }	

		prev_page = page - 1;
		if(prev_page < 1)	{ prev_page = 1; }	


		if(page != prev_page) {
			pagination_buffer += '<a href="javascript:setLocationHash(\'' + callback + ',1\');">first</a> | ';
			pagination_buffer += '<a href="javascript:setLocationHash(\'' + callback + ',' + prev_page + '\');">prev</a> | ';
		}
		else {
			pagination_buffer += 'first | ';
			pagination_buffer += 'prev | ';
		}
		
		pagination_buffer += '<select onChange="setLocationHash(\'' + callback + ',\'\+this.options[this.selectedIndex].value)">';
		for(var i = 1; i <= pages; i++) {
			pagination_buffer += '<option value="' + i + '"';
			if(page == i) {		
				pagination_buffer += ' selected';
			}
			
			pagination_buffer += '>';
			pagination_buffer += i;
			pagination_buffer += '</option>';
		}
		pagination_buffer += '</select>\n';
		
		if(page != next_page) {
			pagination_buffer += ' | <a href="javascript:setLocationHash(\'' + callback + ',' + next_page + '\');">next</a>';
			pagination_buffer += ' | <a href="javascript:setLocationHash(\'' + callback + ',' + pages + '\');">last</a>';
		}
		else {
			pagination_buffer += ' | next';
			pagination_buffer += ' | last';
		}


	}
	
	return { page_buffer: page_buffer, pagination_buffer: pagination_buffer, items: items_on_page };
}

function setFilter(filter) {
	setLocationHash('listThreads,' + filter + ',' + gCurrentThreadSortOrder);
}

function setSort(sortOrder) {
	setLocationHash('listThreads,' + gCurrentThreadFilter + ',' + sortOrder);
}

function showReply(r,x,y) {

	var div = dialogBoxShowWindow('reply',y - 50,x -50,500,'','','',false);
	
	var buffer = '<div class="popin_reply">';
	
	buffer += '<div class=popin_reply_heading>Reply ' + r + ': [<a href="javascript:dialogBoxCloseWindow(\'reply\');">close</a>]</div>';
	
	var t = threads.findPosting(gCurrentThread);
	if(t) {
		var sorted = t.postings.sort(byCreateDate);
		var reversed = sorted.reverse();
		var p = reversed[r - 1];
		if(p) {
			buffer += formatPost(p,false,false,false,false,false);
		}
		else {
			buffer += 'reply not found in thread';
		}
	}
	else {
		buffer += 'could not find current thread ' + gCurrentThread;
	}
	
	buffer += '</div>';
	
	div.innerHTML = buffer;
}

// marks, flags & ignore 

function mark(thread,img) {
	var t = threads.findPosting(thread);
	if(t) {
		if(!t.marked) {
			t.marked = true;
			
			if(img) {
				img.src = '/mark-on.gif';
			}
			
			var marks = getCookie('marks');
			if(marks) {
				marks = unescape(marks);
				var found = false;
				var markList = marks.split(',');
				for(var i = 0; i < markList.length; i++) {
					if(markList[i] == thread) {
						found = true;
					}
				}
				if(!found) {
					markList.push(thread);
				}
				marks = markList.join(',');
			}
			else {
				marks = thread;
			}
			
			setCookie('marks',marks,365);
		}
		else {
			t.marked = false;
			
			if(img) {
				img.src = '/mark-off.gif';
			}

			var marks = getCookie('marks');
			if(marks) {
				marks = unescape(marks);
				var markList = marks.split(',');
				var newList = new Array();
				for(var i = 0; i < markList.length; i++) {
					if(markList[i] != thread) {
						newList.push(markList[i]);
					}
				}
				marks = newList.join(',');
				setCookie('marks',marks,365);
			}
		}
	}
	
	refreshNew();
}
	

function flagWW(thread,post) {
	var t = threads.findPosting(thread);
	if(t) {
		var p = t.findPosting(post);
		if(p) {
			log('saving flag.');
			var request_body = 'type=ww&post=' + post;
			var http_request = setupAjax();
			http_request.onreadystatechange = function() { flagDone(http_request); };
			http_request.open('POST', "/cgi-bin/iowa/ajax-flag.xml", true);
			http_request.send(request_body);
		}
	}
}

function flagFF(thread,post) {
	var t = threads.findPosting(thread);
	if(t) {
		var p = t.findPosting(post);
		if(p) {
			log('saving flag.');
			var request_body = 'type=ff&post=' + post;
			var http_request = setupAjax();
			http_request.onreadystatechange = function() { flagDone(http_request); };
			http_request.open('POST', "/cgi-bin/iowa/ajax-flag.xml", true);
			http_request.send(request_body);
		}
	}
}

function flagDone(http_request) {
	if (http_request.readyState == 4) {
		if (http_request.status == 200) {		
			var xmldoc = http_request.responseXML;
			var status = getXmlFirstChildData('status',xmldoc);
			if(status == 'ok') {
				log('flag saved.');
				alert('flag saved');
			}
			else {
				alert('flag failed ' + status);
			}
		}
		else {
			alert('flag failed ' + http_request.status);
		}
	}
}

function ignoreThread(thread) {
	var t = threads.findPosting(thread);
	if(t) {
		t.ignored = true;
		
		var div = document.getElementById(thread);
		if(div) {
			div.innerHTML = 'thread ignored';
		}
	}
}

function dontIgnorePoster(thread, post) {
	var t = threads.findPosting(thread);
	if(t) {
		var p = t.findPosting(post);
		if(p) {
			unIgnore(p.cookie);
			threads.processIgnored();
			refreshHashPage();
		}
	}
}


function ignorePoster(thread, post) {
	var t = threads.findPosting(thread);
	if(t) {
		var p = t.findPosting(post);
		if(p) {
			ignoredPosters.push(p.cookie);
			threads.processIgnored();
		}
	}
}

// posting form utilities

function postingForm(thread) {
	postingFormSetupAuthor();
	
	var allowed = false;
	
	hidePane('postingFormSubjectPane');
	hidePane('postingFormNoSubjectPane');
	hidePane('postingFormPollPane');
	if(thread) {
		var t = threads.findPosting(gCurrentThread);
		
		if(t.readonly == 'yes') {
			alert('Thread closed');
		}
		else if(t.posting_count >= 600) {
			alert('Thread full. No more replies.');
		}
		else {
			div = document.getElementById('postingFormNoSubjectPane');
			div.innerHTML = "<p><strong>Post a reply</strong></p><p>Re: " + t.subject + '</p>';
			var field = document.getElementById('postingForm_parent');
			field.value = thread;
			showPane('postingFormNoSubjectPane');
			allowed = true;
		}
	}
	else {
		if(0 && !gSubscription) {
			alert('Threads can only be started by paid members.');
		}
		else {
			hideAll();
			var field   = document.getElementById('postingForm_parent');
			field.value = '';
			showPane('postingFormSubjectPane');
			showPane('postingFormPollPane');
			allowed = true;
		}
	}
	
	if(allowed) {
		hidePane('busy');
		showPane('postingForm');
		
		div = document.getElementById('postingForm');
		if(div) {
			var pos = findPos(div);
			window.scroll(0,pos[1]);
		}
	}
	else {
		hidePane('busy');
	}
}

function maxLenth(field,max) {
	if(field.value.length > max) {
		field.value = field.value.substring(0, max);
	}
}	

function postingFormSetupAuthor() {
	if(gUid && gAuthName) {
		hidePane('post_postingForm_anonymous');		
		div = document.getElementById('post_postingForm_authenticated');
		if(div) {
			div.innerHTML = 'Author: ' + gAuthName + ' [<a href="javascript:postingFormAnonymously();">post this anonymously</a>]';
		}
		showPane('post_postingForm_authenticated');
	}
	else {
		postingFormAnonymously()
	}
	var field = document.getElementById('postingForm_anonymous');
	field.value = '';
}

function postingFormAnonymously() {
	hidePane('post_postingForm_authenticated');
	showPane('post_postingForm_anonymous');
	var field = document.getElementById('postingForm_anonymous');
	field.value = 1;
}

function postingFormPoll() {
	hidePane('post_postingForm_poll_button');
	showPane('post_postingForm_poll');
}

// ww

function getWW() {
	log('loading ww');
	var http_request = setupAjax();
	http_request.onreadystatechange = function() { getWWDone(http_request); };
	http_request.open('GET', gXmlFeed + "?ww=1", true);
	http_request.send(null);
}

function getWWDone(http_request) {
	if (http_request.readyState == 4) {
		if (http_request.status == 200) {		
			var xmldoc = http_request.responseXML;
			processWW(xmldoc);			
			log('loading ww done');
		}
		else {
			alert("getWWDone status:" + http_request.status);
		}
	}
}

function processWW(xmldoc) {
	var buffer = '<strong>wit & wisdom</strong>';
	var postings = xmldoc.getElementsByTagName('post');
	if(postings) {
		for(var i = 0; i < postings.length; ++i) {
			var record 	= getXmlFirstChildData('record', postings[i]);
			var parent 	= getXmlFirstChildData('parent', postings[i]);
			var subject = getXmlFirstChildData('subject', postings[i]);
			var body	= getXmlFirstChildData('body', postings[i]);
			var author	= getXmlFirstChildData('author', postings[i]);
			var ww	= getXmlFirstChildData('ww', postings[i]);
			
			body = body.replace(/\[bold\]/g,'<b>');
			body = body.replace(/\[\/bold\]/g,'</b>');
			body = body.replace(/\[italic\]/g,'<i>');
			body = body.replace(/\[\/italic\]/g,'</i>');
			body = body.replace(/\[quote\]/ig,'<p style="padding-left:14px;">');
			
			var thread;
			var page;
			if(parent) {
				thread = parent;
				page = 1;
			}
			else {
				thread = record;
				page = 1;
			}

			var brief = body.substr(0,512);
			
			brief = brief.replace(/<p>/g,'</p><p>');
			subject = subject.replace(/<p>/g,'');
			subject = subject.replace(/<\/p>/g,'');

			buffer += '<p><a href="javascript:setLocationHash(\'showThread,' + thread + ',' + page + '\')">' + subject + '</a>';
			buffer += '<p>' + brief;
			buffer += '<br><i>--' + author + '</i>';
			buffer += "</p>\n";
		}
	}
	var div = document.getElementById('ww');
	if(div) {
		div.innerHTML = buffer;
	}
}


// kludge browser back & forward buttons

var currentHistory = location.hash;

function setLocationHash(params) {
	location.hash = 'page:' + params;	
	resetSleepTimer();
	newAdvert();
}

function watchLocationHash() {
	if(location.hash != currentHistory) {
		refreshHashPage();
	}
	window.setTimeout('watchLocationHash()',100);
}

function refreshHashPage() {
	currentHistory = location.hash;                            //  123456
	if(currentHistory.length > 6 && currentHistory.substr(0,6) == '#page:') {
		doHashPage(currentHistory.substr(6));
	}
	else {
		listThreads(gCurrentThreadFilter,gCurrentThreadSortOrder,gCurrentThreadPage);
	}
}

function doHashPage(currentHistory) {
	var params = currentHistory.split(',');
	
	hideAll();
	
	if(params[0] == 'listStatic') {
		listStatic();
		showListPane();
	}
	else if(params[0] == 'showThread') {
		showThread(params[1],params[2]);
	}
	else if(params[0] == 'listThreads') {
		listThreads(params[1],params[2],params[3]);
		showListPane();
		if(gCurrentThread) {			
			var div = document.getElementById(gCurrentThread);
			if(div) {
				var pos = findPos(div);
				window.scroll(0,pos[1] - 70);
			}
			gCurrentThread = '';
		}
	}
	else if(params[0] == 'listThreadsPage') {
		listThreadsPage(params[1]);
		showListPane();
	}
	else if(params[0] == 'listRepliesPage') {
		listRepliesPage(params[1]);
		showThreadPane();
	}
	else if(params[0] == 'showDirty') {
		showDirty(params[1]);
		showThreadPane();
	}
	else if(params[0] == 'postThread') {
		if(gSubscription) {
			postingForm();
		}
		else {
			alert('Only subscribers can start threads');
			showListPane();
		}
	}
	else if(params[0] == 'postReply') {
		showThread(params[1],params[2]);
		showThreadPane();
		postingForm(params[1]);
	}
	else {
		listThreads(gCurrentThreadFilter,gCurrentThreadSortOrder,gCurrentThreadPage);
	}
	
	refreshNew();

	googleClickTrack(currentHistory);
	
	if(gPrimetime && !gSubscription && !gPrimetimeDialog) {
		googleClickTrack('primetime');
		primetime();
	}
}

watchLocationHash(); // start watching for location.hash events

// authentication

function authStatus() {
	var div = document.getElementById('authstatus');
	if(div) {
		if(gUid && gAuthName) {
			div.innerHTML = "Authenticated as " + gAuthName + ' [<a href="javascript:authLogout();">logout</a>]';
		}
		else {
			div.innerHTML = "<a href=\"javascript:showPane('authlogin');\">Authenticated Login</a>";
		}
	}

	div = document.getElementById('subscribestatus');
	if(div) {
		if(gSubscription) {
			div.innerHTML = "Subscription Registered";
		}
		else {
			div.innerHTML = "<a href=\"javascript:showPane('subscribelogin');\">Subscription Registration</a>";
		}
	}
	
	postingFormSetupAuthor();
}

function authLogout() {
	gUid 		= '';
	gAuthName 	= '';
	deleteCookie('uid');
	deleteCookie('authname');
	deleteCookie('authenticate');
	authStatus();
}

function submitAuthentication() {
	var login = document.getElementById('authname').value;
	var password = document.getElementById('authpasword').value;

	hidePane('authlogin');
	log('submitting login...');

	var http_request = setupAjax();
	http_request.onreadystatechange = function() { authLoginDone(http_request); };
	http_request.open('POST', "/cgi-bin/iowa/ajax-auth-login.xml", true);
	http_request.send('login=' + login + '&password=' + password);
}

function authLoginDone(http_request) {
	if (http_request.readyState == 4) {
		if (http_request.status == 200) {
			var xmldoc = http_request.responseXML;
			var status = getXmlFirstChildData('status',xmldoc);
			if(status == 'ok') {
				gUid 		= getXmlFirstChildData('uid',xmldoc);
				gAuthName   = getXmlFirstChildData('authname',xmldoc);
				authStatus();
			}
			else {
				alert('login failed ' + status);
			}
		}
		else {
			alert("authLoginDone status:" + http_request.status);
		}
	}
}

function submitSubscription(id) {
	hidePane('subscribelogin');
	log('submitting subscription...');

	var http_request = setupAjax();
	http_request.onreadystatechange = function() { submitSubscriptionDone(http_request); };
	http_request.open('POST', "/cgi-bin/iowa/ajax-subscribe-login.xml", true);
	http_request.send('id=' + id);
}

function submitSubscriptionDone(http_request) {
	if (http_request.readyState == 4) {
		if (http_request.status == 200) {
			var xmldoc = http_request.responseXML;
			var status = getXmlFirstChildData('status',xmldoc);
			if(status == 'ok') {
				gSubscription = true;
				authStatus();
				newAdvert();
				gPollingFrequency = 60000;
				getNewPosts();
				if(gPrimetimeDialog) {
					dialogBoxCloseWindow('primetime');
					gPrimetimeDialog = false;
				}
				
			}
			else {
				alert('Subscription registration failed: ' + status);
			}
		}
		else {
			alert("authLoginDone status:" + http_request.status);
		}
	}
}

// submit 

function getFieldValue(id,prompt) {
	var field = document.getElementById(id);
	if(field) {
		var value = unescape(unescape(field.value));
		if(value.indexOf('<') != -1) {
			alert(id + ' contains markup');
		}
		else {
			return value;
		}
	}
	else {
		alert('count not find ' + id);
	}
}

function clearPostingForm () {
	var form = document.getElementById('thepostingformform');
	if(form && form.elements) {
		for(var i = 0; i < form.elements.length; i++) {
			form.elements[i].value = '';
		}
	}
	else {
		alert('could not find form ' + form);
	}
}

function submitPost() {

	var errors = 0;

	var parent 		= getFieldValue('postingForm_parent');
	var subject 	= getFieldValue('postingForm_subject','Subject');
	var body 		= getFieldValue('postingForm_body','Message Body');
	var author 		= getFieldValue('postingForm_author','Author');
	var anonymous 	= getFieldValue('postingForm_anonymous');
	var url 		= getFieldValue('postingForm_url','Web Site Link');
	var keywords 	= getFieldValue('postingForm_keywords','Keywords');
	var poll_question = getFieldValue('postingForm_poll_question','Poll Question');
	var poll_option0 = getFieldValue('postingForm_poll_option0','Poll option 1');
	var poll_option1 = getFieldValue('postingForm_poll_option1','Poll option 2');
	var poll_option2 = getFieldValue('postingForm_poll_option2','Poll option 3');
	var poll_option3 = getFieldValue('postingForm_poll_option3','Poll option 4');
	var poll_option4 = getFieldValue('postingForm_poll_option4','Poll option 5');
	var poll_option5 = getFieldValue('postingForm_poll_option5','Poll option 6');
	var poll_option6 = getFieldValue('postingForm_poll_option6','Poll option 7');
	var poll_option7 = getFieldValue('postingForm_poll_option7','Poll option 8');
	var poll_option8 = getFieldValue('postingForm_poll_option8','Poll option 9');
	var poll_option9 = getFieldValue('postingForm_poll_option9','Poll option 10');

	if(!subject && !parent) {
		alert('subject is mandatory');
		++errors;
	}
	
	if(!body) {
		alert('message body is mandatory');
		++errors;
	}
	
	if(url.length && !url.match(/^(http|https)\:\/\//)) {
		alert('url you entered is not valid');
		++errors;
	}

	if(!errors) {
		log('submitting post');

		clearPostingForm();
		hideAll();

		var requestBody = 'post=1';
		requestBody += '&parent=' + escape(parent);
		requestBody += '&subject=' + encodeURIComponent(subject);
		requestBody += '&body=' + encodeURIComponent(body);
		requestBody += '&url=' + escape(url);
		requestBody += '&anonymous=' + escape(anonymous);
		requestBody += '&author=' + escape(author);
		requestBody += '&keywords=' + escape(keywords);
		requestBody += '&poll_question=' + escape(poll_question);
		requestBody += '&poll_option0=' + escape(poll_option0);
		requestBody += '&poll_option1=' + escape(poll_option1);
		requestBody += '&poll_option2=' + escape(poll_option2);
		requestBody += '&poll_option3=' + escape(poll_option3);
		requestBody += '&poll_option4=' + escape(poll_option4);
		requestBody += '&poll_option5=' + escape(poll_option5);
		requestBody += '&poll_option6=' + escape(poll_option6);
		requestBody += '&poll_option7=' + escape(poll_option7);
		requestBody += '&poll_option8=' + escape(poll_option8);
		requestBody += '&poll_option9=' + escape(poll_option9);

		var http_request = setupAjax();
		http_request.onreadystatechange = function() { submitPostDone(http_request); };
		http_request.open('POST', gXmlPost, true);
		http_request.send(requestBody);
	}
}

function submitPostDone(http_request) {
	if (http_request.readyState == 4) {
		if (http_request.status == 200) {
			var xmldoc = http_request.responseXML;
			var status = getXmlFirstChildData('status',xmldoc);
			if(status == 'ok') {
				processNewPosts(xmldoc);
				var post = getXmlFirstChildData('new-post',xmldoc);
				var parent = getXmlFirstChildData('parent',xmldoc);
				if(parent) {
					var t = threads.findPosting(parent);
					if(t) {
						if(!t.marked) {
							mark(parent);
						}
						alert('Post saved. It may take a few moments for your post to appear.');
						setLocationHash('showThread,' + parent + ',' + t.lastPage());
					}
					else {
						alert('error could not find thread ' + parent + ' for new post ' + post);
					}
				}
				else {
					var t = threads.findPosting(post);
					if(post) {
						mark(post);
						setLocationHash('showThread,' + post + ',1');
					}
					else {
						alert('error could not find new thread ' + post);
					}
				}
			}
			else {
				alert('could not save post ' + status);
			}
		}
	}
}

// submit poll

function submitPoll(post,option) {
	log('saving poll vote.');
	var request_body = 'post=' + post + '&option=' + option + '&vote=1';
	var http_request = setupAjax();
	http_request.onreadystatechange = function() { pollDone(http_request); };
	http_request.open('POST', "/cgi-bin/iowa/ajax-poll.xml", true);
	http_request.send(request_body);
}

function showPollResults(post) {
	log('retrieving poll results.');
	var request_body = 'post=' + post + '&results=1';
	var http_request = setupAjax();
	http_request.onreadystatechange = function() { pollDone(http_request); };
	http_request.open('POST', "/cgi-bin/iowa/ajax-poll.xml", true);
	http_request.send(request_body);
}

function pollDone(http_request) {
	if (http_request.readyState == 4) {
		if (http_request.status == 200) {		
			var xmldoc = http_request.responseXML;
			var status = getXmlFirstChildData('status',xmldoc);
			if(status == 'ok') {
				log('poll done.');
				var status = getXmlFirstChildData('row',xmldoc);
				var row = getXmlFirstChildData('row',xmldoc);
				var p = threads.findPosting(row);
				if(p) {
					var buffer = 'Poll results: ' + p.poll_question + '<ul>';
					var total = getXmlFirstChildData('total',xmldoc);
					if(total) {
						for(var i = 0; i < 10; i++) {
							if(p.poll_options[i]) {
								var value = getXmlFirstChildData('poll_answer' + i,xmldoc);
								buffer += '<li> ' + p.poll_options[i] + ' -- ' + value / total * 100 + '%';
							}
						}
						
						buffer += '<p>total votes: ' + total;
					}
					else {
						buffer += 'no vote yet';
					}
					buffer += '</ul>';
					
					var div = document.getElementById('poll_' + row);
					if(div) {
						div.innerHTML = buffer;
					}
					else {
						alert('could not find poll_' + row);
					}
				}
				else {
					alert('could not find post ' + row);
				}
			}
			else {
				alert('poll failed ' + status);
			}
		}
		else {
			alert('poll failed ' + http_request.status);
		}
	}
}

// general utilities

function findPos(obj) {
  var curleft = curtop = 0;
  if (obj.offsetParent) {
	 curleft = obj.offsetLeft
	 curtop = obj.offsetTop
	 while (obj = obj.offsetParent) {
		curleft += obj.offsetLeft
		curtop += obj.offsetTop
	 }
  }
  return [curleft,curtop];
}

function getCookie(name) {

	var value = '';

	if(document.cookie.length > 0) {
	
		var pairs = document.cookie.split(';');
		
		for(var i = 0; i < pairs.length; i++) {
			var kv = pairs[i].split('=');
			
			var n = kv[0].replace(/^\s+|\s+$/g, '');
			
			if(n == name) {
				if(kv.length > 1) {
					value =  unescape(kv[1].replace(/^\s+|\s+$/g, ''));
					
					return value;
				}
				else {
					return '';
				}
			}
		}
	}
	
	return '';
}

function setCookie(name,value,expiredays) {
	var exdate=new Date();
	exdate.setDate(exdate.getDate() + expiredays);
	document.cookie = name + "=" + escape(value) + ((expiredays==null) ? "" : ";expires=" + exdate.toGMTString()) + ';path=/';
}

function deleteCookie(name) {
	setCookie(name, "", "");
}

function markup(post,brief) {

	var buffer = post.body;

	var paragraphs = null;
	
	if(buffer) {
		paragraphs = buffer.split('<p>');
		
		if(brief && (buffer.length > 1024 || paragraphs.length > 20)) {
			
			if(buffer.length > 1024) {
				buffer = buffer.substr(0,1024);
			}
			
			paragraphs = buffer.split('<p>');
			if(paragraphs.length > 20) {
				paragraphs.splice(20);
				buffer = paragraphs.join('<p>');
			}
			
			buffer += '</b></i>... [<a href="javascript:setLocationHash(\'showThread,' + post.record + '\')">more</a>]';
		}
	
		buffer = buffer.replace(/<br>\s*<br>/g,'<p>');
		buffer = buffer.replace(/<br>/g,' ');
	
		buffer = buffer.replace(/\[bold\]/g,'<b>');
		buffer = buffer.replace(/\[\/bold\]/g,'</b>');
		buffer = buffer.replace(/\[italic\]/g,'<i>');
		buffer = buffer.replace(/\[\/italic\]/g,'</i>');
	
		paragraphs = buffer.split('<p>');
		for(var i = 0; i < paragraphs.length; i++) {
			paragraphs[i].replace(/<\/p>/i,'');
			if(paragraphs[i].indexOf('[quote]') > -1) {
				paragraphs[i] = paragraphs[i].replace(/\[quote\]/,'<div class="quote">');
				paragraphs[i] += '</div>';
			}
			else {
				paragraphs[i] = '<p>' + paragraphs[i];
			}
			paragraphs[i] += '</p>';
		}
	
		buffer = paragraphs.join("\n");
			
		var matches = buffer.match(/\bR(\d+)\b/ig);
		
		if(matches) {
			for(var i = 0; i < matches.length; i++) {
				var r = matches[i];
				var replyNumber = r.substr(1);
				
				buffer = buffer.replace(r,'[<a href="" onmouseover="showReply(' + replyNumber + ',cursorX,cursorY);">R' + replyNumber + '</a>]');
				
				// log('found reply ' + replyNumber + ' in buffer');
			}	
		}
	}
	
	return buffer;
}

// http://www.youtube.com/watch?v=GEMuAnFH_lM

function markupUrl(url,threadlist) {
	var buffer = '';
	
	var matches = url.match(/^(http|https):\/\/([^\/]+)/i);
	var domain = '';
	if(matches) {
		domain = matches[2];
	}
	
	if(url.match(/http:\/\/(www\.)*youtube\.com\/watch\?v\=/i)) {
		matches = url.match(/v=([^&]+)/);
		var vid = matches[0].substr(2);
		
		if(threadlist) {
			buffer = '[<span class="link">see YouTube video inside</span>]';
		}
		else {
			if(getCookie('settings_youtube_inline') == 'true') {
				buffer = "<object width='425' height='344'>";
				buffer += "<param name=\"wmode\" value=\"transparent\"></param>";
				buffer += "<param name='movie' value='http://www.youtube.com/v/" + vid + "'></param>";
				buffer += "<param name='allowFullScreen' value='true'></param>";
				buffer += "<param name='allowscriptaccess' value='always'></param>";
				buffer += "<embed src='http://www.youtube.com/v/" + vid + "' type='application/x-shockwave-flash' wmode=\"transparent\" allowscriptaccess='always' allowfullscreen='true' width='425' height='344'></embed>";
				buffer += "</object>";
			}
			else {
				buffer = '[<a href="' + url + '" target="offsite" class="link">see YouTube video</a>]';
			}
		}
	}
	else if(url.match(/\.jpg$/i)) {
		if(threadlist) {
			buffer = '[<span class="link">see offsite photo inside</span>]';
		}
		else {
			if(getCookie('settings_images_inline') == 'true') {
				buffer = 'offsite image: click image to view actual size<br><a href="' + url + '" target="offsite"><img src="' + url + '" width=300></a><br>Note: some servers disallow embedding. <a href="' + url + '" target="offsite">click here</a> if image does not display above. (' + domain + ')';
			}
			else {
				buffer = '[<a href="' + url + '" target="offsite" class="link">see offsite photo on ' + domain + '</a>]';
			}
		}
	}
	else {
		buffer = '[<a href="' + url + '" target="offsite" class="link">see offsite link on ' + domain + '</a>]';
	}
	
	return buffer;
}

// status pane scrolling

var oldScrollOffset = 0;

function startWatchForScroll(){
	window.setTimeout("watchForScroll()", 100);
}

function getScrollXY() {
    var x = 0, y = 0;
    if( typeof( window.pageYOffset ) == 'number' ) {
        // Netscape
        x = window.pageXOffset;
        y = window.pageYOffset;
    } else if( document.body && ( document.body.scrollLeft || document.body.scrollTop ) ) {
        // DOM
        x = document.body.scrollLeft;
        y = document.body.scrollTop;
    } else if( document.documentElement && ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) {
        // IE6 standards compliant mode
        x = document.documentElement.scrollLeft;
        y = document.documentElement.scrollTop;
    }
    return [x, y];
}

function watchForScroll() {
	var position = 0;
	
	var pos = getScrollXY();
	
	position = pos[1];

	if(position != oldScrollOffset) {
		oldScrollOffset = position;
		
		if(getCookie('settings_scroll_new') == 'true') {
			var statusdiv = document.getElementById('floatingstatus');
			position += 8;
			new Effect.Move(statusdiv, {x:745,y:position,mode:'absolute',duration:.5})
		}
	}
	
	window.setTimeout("watchForScroll()", 1000);
}

startWatchForScroll();

// track mouse position

var cursorX = 0;
var cursorY = 0;

if (document.addEventListener){
  document.addEventListener('mousemove', getMousePosition, true); 
} else if (document.attachEvent){
  document.attachEvent('onmousemove', getMousePosition);
}

function getMousePosition(e) {
	var posx = 0;
	var posy = 0;
	if (!e) var e = window.event;
	if (e.pageX || e.pageY) {
		posx = e.pageX;
		posy = e.pageY;
	}
	else if (e.clientX || e.clientY) 	{
		posx = e.clientX + document.body.scrollLeft
			+ document.documentElement.scrollLeft;
		posy = e.clientY + document.body.scrollTop
			+ document.documentElement.scrollTop;
	}

    cursorX = posx;
    cursorY = posy;
}

// advert

var gAdvertCounter = 0;

function newAdvert() {
	var advertDiv = document.getElementById('advert');
	if(gSubscription || gPrimetime) {
		advertDiv.style.display = 'none';
	}
	else {
		advertDiv.style.display = '';
		++gAdvertCounter;
		advertDiv.innerHTML = '<iframe id=advertIframe frameborder=0 width="100%" height=300 src="/ajax-advert.html?' + gAdvertCounter + '"></iframe>';
	}
}

// watch for inactivity

resetSleepTimer();

function resetSleepTimer() {
	if(gSleeping) {
		gSleeping = false;
		if(!gPollingForNewPosts) {
			getNewPosts();
		}
	}
	if(gSleepTimer) {
		window.clearTimeout(gSleepTimer);
	}
	gSleepTimer = window.setTimeout("stopPolling()",600000); // 10 min
}

function stopPolling() {
	gSleeping = true;
}

function setItemsPerPage(i) {
	itemsPerPage = i * 1;
	setCookie('settings_items_per_page',i,365);
}

// customize css

function undoColors() {
	deleteCookie('page-bg');
	deleteCookie('page-text');
	deleteCookie('page-link');
	deleteCookie('viewed-bg');
	deleteCookie('viewed-text');
	deleteCookie('unread-bg');
	deleteCookie('unread-text');
	deleteCookie('dirty-bg');
	deleteCookie('dirty-text');
	deleteCookie('threadwatcher-bg');
	deleteCookie('threadwatcher-text');
	deleteCookie('tools-bg');
	deleteCookie('tools-text');
	deleteCookie('subject-text');
	var l = document.createElement("link");
	l.href = '/ajax.css?' + (++gTieBreaker);
	l.rel  = "stylesheet";
	l.type = "text/css";
	document.body.appendChild(l);
}

function applyColors() {	
	var l = document.createElement("link");
	l.href = '/cgi-bin/iowa/ajax-customize.css?' + (++gTieBreaker);
	l.rel  = "stylesheet";
	l.type = "text/css";
	document.body.appendChild(l);
}

function randomCunt() {
	var lastCunt = gCurrentCunt;
	Effect.Fade(gCurrentCunt,{ duration: 3.0});
	while(lastCunt == gCurrentCunt) {
		gCurrentCunt = gCunts[Math.floor(Math.random() * gCunts.length)];
	}
	Effect.Appear(gCurrentCunt,{ duration: 3.0});
	window.setTimeout('randomCunt();',30000);
}

function initialize() {
	//newAdvert();
	applyColors();
	authStatus();
	getThreadList();
	// window.setTimeout('randomCunt();',30000);
}

function googleClickTrack(id) {
	if(pageTracker) {
		pageTracker._trackPageview(escape(id));
	}
}

function primetime() {
	var div = dialogBoxShowWindow('primetime','','',500,'','','',true);
	var buffer = '<div class="popin_primetime" style="background-color:white;">';
	buffer += '<strong>Primetime</strong>';
	buffer += '<p>Due to extremely high traffic, the DataLounge forum is limited during peak hours to paying DataLounge users only. This paying-users-only limit kicks in automatically when the server load is very high. During these periods we give priority access to DataLounge subscribers. Anyone can access the site outside of peak traffic periods.';
	buffer += '<p><b>Subscribers can access the site in primetime for one year for $18.</b> If you would like to subscribe to the site now, please <a href="https://www.datalounge.com/cgi-bin/dl/index.html">click here</a>.';
	buffer += '<p>If you are already a subscriber, you can access the site by entering your payment code code: <input type=text id=subscription_popin> [<a href="javascript:submitSubscription(document.getElementById(\'subscription_popin\').value);">Save</a>]';
	buffer += '<p>If not, please check back with the site in a few hours when traffic is lighter.';
	buffer += '</div>';
	div.innerHTML = buffer;
	gPrimetimeDialog = 1;
}

function settings() {
	var div = dialogBoxShowWindow('settings','','',500,800,'','/cgi-bin/iowa/ajax-settings.html',true);
}

// searching (server side)

function searchForm() {
	gCurrentSearchThreadOnly = false;
	hideAll();
	hidePane('busy');
	showPane('searchform');
}

function submitSearch(terms) {	
	if(terms) {
		hideAll();
		gCurrentSearchTerms = terms;
		var http_request = setupAjax();
		http_request.onreadystatechange = function() { submitSearchDone(http_request); };
		http_request.open('GET', "/cgi-bin/iowa/ajax-search.xml?terms=" + escape(terms), true);
		http_request.send(null);
	}
	else {
		alert('enter words to find');
	}
}

function submitSearchDone(http_request) {
	if (http_request.readyState == 4) {
		if (http_request.status == 200) {
			var xmldoc = http_request.responseXML;
			var status = getXmlFirstChildData('status',xmldoc);
			if(status == 'ok') {
				processNewPosts(xmldoc);
				gCurrentSearch = new Array();
				var postings = xmldoc.getElementsByTagName('post');
				for(var i = 0; i < postings.length; i++) {
					gCurrentSearch.push(threads.findPosting(getXmlFirstChildData('record', postings[i])));
				}

				if(gCurrentSearch.length) {
					showSearchPane();
					++gTieBreaker;
					searchResults(1);
				}
				else {
					alert('No threads found');
					hidePane('busy');
					showPane('searchform');
				}
			}
			else {
				alert('search failed ' + status);
			}
		}
		else {
			alert("search failed status:" + http_request.status);
		}
	}
}

function searchThreadForm() {
	gCurrentSearchThreadOnly = true;
	showPane('searchthreadform');
}

function submitThreadSearch(thread,terms) {	
	if(terms) {
		hideAll();
		gCurrentSearchTerms = terms;
		searchThread(thread);
	}
	else {
		alert('enter words to find');
	}
}

function searchThread(thread) {
	hideAll();
	var http_request = setupAjax();
	http_request.onreadystatechange = function() { searchThreadDone(http_request); };
	http_request.open('GET', "/cgi-bin/iowa/ajax-search.xml?terms=" + escape(gCurrentSearchTerms) + '&thread=' + thread, true);
	http_request.send(null);
}

function searchThreadDone(http_request) {
	if (http_request.readyState == 4) {
		if (http_request.status == 200) {
			var xmldoc = http_request.responseXML;
			var status = getXmlFirstChildData('status',xmldoc);
			if(status == 'ok') {
				var thread = getXmlFirstChildData('thread',xmldoc);
				var hits   = getXmlFirstChildData('hits',xmldoc);
				if(!hits) {
					alert('no replies found');
					showThreadPane();
				}
				else {
					gCurrentThreadSearchHits = hits;
					var t = threads.findPosting(thread);
					if(t) {
						if(t.loaded) {
							searchResultsThread(thread, 1);
						}
						else {
							getThread(thread, 1, true);
						}
					}
					else {
						alert('could not find thread ' + thread);
					}
				}
			}
			else {
				alert('search failed ' + status);
			}
		}
		else {
			alert("search failed status:" + http_request.status);
		}
	}
}

function searchResults(page) {
	hideAll();
	var div = document.getElementById('searchlist');
	if(div) {
		var pagination;
		var buffer = '';
		
		for(var i = 0; i < gCurrentSearch.length; i++) {
			buffer += formatPost(gCurrentSearch[i],true,true,true,true,false,true);
		}

		div.innerHTML = buffer;
	}
	hidePane('busy');
	showPane('searchform');
	showPane('search');
}

function searchResultsThread(thread,page) {
	hideAll();
	var div = document.getElementById('searchthreadlist');
	if(div) {
		var t = threads.findPosting(thread);
		if(t) {
			currentThreadSearch = new Array();

			var h = gCurrentThreadSearchHits.split(/,/);
			h = h.sort();
			for(var i = 0; i < h.length; i++) {
				var p = t.findPosting(h[i]);
				if(p) {
					currentThreadSearch.push(p);
				}
			}

			var buffer = '';
			
			buffer = formatPost(t,false,true,false,true,true);

			++gTieBreaker;

			buffer += '<div class=controls style="border-top:0;">';
			buffer += 'Matching replies in thread: ';
			buffer += '[<a href="javascript:setLocationHash(\'showThread,' + t.record + ',1,' + gTieBreaker + '\')">show all posts in thread</a>]';
			buffer += '</div>';
	
			for(var i = 0; i < currentThreadSearch.length; i++) {
				buffer += formatPost(currentThreadSearch[i],false,false,false,false,false,false);
			}
		
			div.innerHTML = buffer;
		}
		else {
			alert('could not find thread ' + thread);
		}
	}
	
	document.getElementById('search_thread_terms').value = gCurrentSearchTerms;
	
	hidePane('busy');
	showPane('searchthreadform');
	showPane('searchthread');
	
	var backbutton = document.getElementById('searchbackbutton');
	if(gCurrentSearchThreadOnly) {
		backbutton.style.display = 'none';
	}
	else {
		backbutton.style.display = '';
	}
}
