window.authorsToBooks = new Object();
window.booksToAuthors = new Object();
window.seriesToBooks = new Object();
window.booksToSeries = new Object();


function sortableTable(id)
{
	this.id = id;
	this.table = get(id);
}

sortableTable.prototype.sort = function()
{
	// Selection sort seems appropriate...
	for (var i = 0; i < rows; i++) {
		var biggest = i;
		for (var j = i + 1; j < rows; j++) {
			if (nodes[j] > nodes[i])
				biggest = j;
		}

		if (biggest != i)
			swapNodes(i, biggest);
	}
}

sortableTable.prototype.swapRows = function(i, j)
{
	t_body = table.tBodies[0];
	var rows = getChildren(t_body, 'tr');

	if (i == j+1) {
		t_body.insertBefore(rows[i], rows[j]);
	}
	else if (j == i+1) {
		t_body.insertBefore(rows[j], rows[i]);
	}
	else {
		var tmp_node = t_body.replaceChild(rows[i], rows[j]);
		if (typeof(rows[i]) != 'undefined') {
			t_body.insertBefore(tmp_node, rows[i]);
		}
		else {
			this.table.appendChild(rows[i]);
		}
	}
}


/**
 * @param int id
 * @param string title
 * @param string language
 * @param bool read_original
 * @param string english_title null if the original title is English
 * @param array authors
 * @param array translations
 */
function Book(id, title, language, read_original, english_title, authors, translations)
{
	this.id = id;
	this.title = title;
	this.language = language;
	this.read_original = read_original;
	this.english_title = (english_title == null) ? title : english_title;
	this.authors = authors;
	this.translations = translations;
}


Book.allByTitle = function()
{
	var booklist = new Array();
	for (book_id in window.books)
	{
		var book = window.books[book_id];
		var authors = window.booksToAuthors[book_id];
		
		var title_search = book.english_title;
		var title_node = document.createTextNode(book.english_title);
		
		var author_desc = '';
		var author_search = '';
		for (var i = 0; i < authors.length; i++)
		{
			person = window.people[authors[i]];
			if (i > 0)
			{
				if (authors.length == 2)
					author_desc += ' and ';
				else if (i < authors.length-1)
					author_desc += ', ';
				else
					author_desc += ', and ';
			}
			author_desc += person.shortDesc();
			author_search += person.last_name + ' ' + person.first_name
			               + ' ' + person.middle_names + ';';
		}
		var author_node = document.createTextNode(author_desc);
		
		var info_search = '';
		var info_node = document.createElement('td');

		if (window.booksToSeries[book_id] == undefined)
		{
			info_node.appendChild(document.createTextNode(''));
		}
		else
		{
			var series = window.booksToSeries[book_id];
			var volume_no = series.getVolumeNoOf(book_id);
			
			info_search = 'Volume '+volume_no+' of ‘'+series.title+'’';
			
			var em = document.createElement('em');
			em.appendChild(document.createTextNode(series.title));
			info_node.appendChild(document.createTextNode('Volume '+volume_no+' of '));
			info_node.appendChild(em);
		}
		
		if (book.language != 'English')
		{
			var orig_title = document.createElement('em');
			orig_title.appendChild(document.createTextNode(book.title));
			if (book.read_original)
			{
				var t_note = 'I have read the original '+book.language+', ';
				info_node.appendChild(document.createTextNode(t_note));
				info_node.appendChild(orig_title);
				info_node.appendChild(document.createTextNode('.'));
			}
			else
			{
				var t_note = 'I have not read the original '+book.language+', ';
				info_node.appendChild(document.createTextNode(t_note));
				info_node.appendChild(orig_title);
				info_node.appendChild(document.createTextNode('.'));
			}
		}
		
		booklist.push([
			[title_search, title_node],
			[author_search, author_node],
			[info_search, info_node]
		]);
	}
	return booklist;
}


/**
 * @param int id
 * @param string first_name
 * @param string last_name
 * @param string middle_names
 * @param string nickname
 */
function Person(id, first_name, last_name, middle_names, nickname)
{
	this.id = id;
	this.first_name = first_name;
	this.last_name = last_name;
	this.middle_names = middle_names;
	this.nickname = nickname;
}

/**
 * @return string
 */
Person.prototype.shortDesc = function()
{
	if (this.nickname != '')
		return this.nickname + ' ' + this.last_name;
	else
		return this.first_name + ' ' + this.last_name;
};



function Translation(title, language, translators)
{
	this.title = title;
	this.language = language;
	this.translators = translators;
}


function Series(id, title)
{
	this.id = id;
	this.title = title;
	this.volumes = {};
}

Series.prototype.addVolume = function(book, volume)
{
	this.volumes[book] = volume;
	_registerVolume(book, this);
};

Series.prototype.getVolumeNoOf = function(book)
{
	return this.volumes[book];
};


/**
 * Register an association between a book and its series.
 *
 * @param int book
 * @param int series
 */
function _registerVolume(book, series)
{
	window.booksToSeries[book] = series;

	if (window.seriesToBooks[series] == undefined)
		window.seriesToBooks[series] = [book];
	else
		window.seriesToBooks[series].push(book);
}


/**
 * Register an association between a book and its author.
 *
 * @param int book Book id
 * @param int person Person id
 */
function _registerAuthorship(book, person)
{
	if (window.booksToAuthors[book] == undefined)
		window.booksToAuthors[book] = [person];
	else
		window.booksToAuthors[book].push(person);

	if (window.authorsToBooks[person] == undefined)
		window.authorsToBooks[person] = [book];
	else
		window.authorsToBooks[person].push(book);
}


/**
 * @param array data_rows
 */
function makeTableBody(data_rows)
{
	// Let's not use jQuery here; it's a lot slower.
	var tbody = document.createElement("tbody");
	
	// creating all cells
	for(var i = 0; i < data_rows.length; i++)
	{
		var row = document.createElement('tr');

		for(var j = 0; j < data_rows[i].length; j++)
		{
			var cell = document.createElement('td');
			var content = data_rows[i][j][1];
			if (j!=2)
			{
				cell.appendChild(content);
				row.appendChild(cell);
			}
			else
			{
				row.appendChild(content);
			}
		}
		tbody.appendChild(row);
	}
	return tbody;
}


/**
 * @param array data_rows
 */
function updateTable(data_rows)
{
	$('#book_table > tbody').replaceWith(makeTableBody(data_rows));
}


/**
 * Remove leading 'The ' from a title, if it is present.
 *
 * Useful for sorting, as catalogues ignore the word 'the'.
 *
 * @param string title
 * @return string Title without (optional) leading 'The '.
 */
function unTheify(title)
{
	if (title.length > 4 && title.substring(0, 4) == 'The ')
		return title.substring(4);
	else
		return title;
}


/**
 * Lexicographic title sort; ignores a leading "The".
 *
 * @param string t1
 * @param string t2
 * @return int -1 if t1<t2, 0 if t1=t2, +1 if t1>t2
 */
function titleCmp(t1, t2)
{
	t1 = unTheify(t1).toUpperCase();
	t2 = unTheify(t2).toUpperCase();
	
	if (t1 < t2)
		return -1;
	else if (t2 < t1)
		return 1;
	else
		return 0;
}


var author_forwards = true;
var title_forwards = true;


function sortByTitle()
{
	var booklist = Book.allByTitle();
	if (title_forwards == null || title_forwards)
	{
		booklist.sort(function(a, b) { return titleCmp(a[0][0], b[0][0]); });
		title_forwards = false;
		author_forwards = null;
		$('.sort_arrow').hide();
		$('.title_sort_up').show();
	}
	else
	{
		booklist.sort(function(b, a) { return titleCmp(a[0][0], b[0][0]); });
		title_forwards = true;
		author_forwards = null;
		$('.sort_arrow').hide();
		$('.title_sort_down').show();
	}
	updateTable(booklist);
}


function sortByAuthor()
{
	var booklist = Book.allByTitle();
	if (author_forwards == null || author_forwards)
	{
		booklist.sort(function(a, b) {
			return titleCmp(a[1][0], b[1][0]);
		});
		author_forwards = false;
		title_forwards = null;
		$('.sort_arrow').hide();
		$('.author_sort_up').show();
	}
	else
	{
		booklist.sort(function(b, a) {
			return titleCmp(a[1][0], b[1][0]);
		});
		author_forwards = true;
		title_forwards = null;
		$('.sort_arrow').hide();
		$('.author_sort_down').show();
	}
	updateTable(booklist);
}


function init()
{
	window.people = new Object;
	for (pdi in people_data)
	{
		var pd = people_data[pdi];
		window.people[pd[0]] = new Person(pd[0], pd[1], pd[2],
		                                  pd[3], pd[4]);
	}
	delete people_data;
	people_data = null;

	window.books = new Object;
	for (bdi in book_data)
	{
		var bd = book_data[bdi];
		window.books[bd[0]] = new Book(bd[0], bd[1], bd[2],
		                               bd[3], bd[4]);
	}
	delete book_data;
	book_data = null;

	window.series = new Object();
	for (sti in series_title_data)
	{
		var st = series_title_data[sti];
		window.series[st[0]] = new Series(st[0],
		                                  st[1]);
	}
	delete series_title_data;
	series_title_data = null;

	for (sdi in series_data)
	{
		var sd = series_data[sdi];
		var series_id = sd[0];
		var series_ob = window.series[series_id];
		series_ob.addVolume(sd[1], sd[2]);
	}
	delete series_data;
	series_data = null;

	for (pair_i in author_data)
	{
		var pair = author_data[pair_i];
		_registerAuthorship(pair[0],
		                    pair[1]);
	}
	delete author_data;
	author_data = null;
}
