var body;

var releases = new Array();

function czrcInit() {
	removeListener(window, "load", czrcInit);
	
	if (document.location.search != "?debug") {
		var dl = document.getElementById("debug_log");
		dl.parentNode.removeChild(dl);
	}
	
	debugLog("czrcInit()");
	
	body = document.getElementById("body");
	showMessageBox("Loading...");
	
	// Work around dodgy reload bug (it preserves the disabled of the term, but not the button!).
	document.getElementById("search_bugs_inc_closed").disabled = false;
	document.getElementById("search_bugs_term").value = "";
	document.getElementById("search_bugs_term").disabled = false;
	document.getElementById("search_bugs_button").disabled = false;
	
	toggleReleased();
	setInterval("updateReleaseList()", 60000);
	setInterval("updateBugSummaries()", 60000);
	setInterval("updateReleaseStatus()", 1000);
	
	updateReleaseList();
	closeMessageBox();
}

function updateReleaseList() {
	debugLog("updateReleaseList()");
	for (var i = 0; i < releases.length; i++) {
		releases[i].flaggedForDelete = true;
	}
	
	var releaseReq = new WebRequest("GET", "releases.txt", releasesLoadOnload, releasesLoadOnerror);
	releaseReq.priority = 20;
	releaseReq.load();
}

var currentBugStep = 0;
var currentBugIndex = 0;
function updateBugSummaries() {
	// Wait 1 hour between single bug updates.
	if (++currentBugStep < 60) {
		return;
	}
	currentBugStep = 0;
	
	var i = currentBugIndex;
	var c = 0;
	for (var id in bugs) {
		bugs[id].loadSummary();
		if (i-- == currentBugIndex) {
			bugs[id].loadDetails();
		}
		c++;
	}
	currentBugIndex++;
	if (currentBugIndex > c) {
		currentBugIndex = 0;
	}
}

function releasesLoadOnload(event, request, data) {
	try {
		var list = data.split(/[\r\n]+/);
		for (var i = 0; i < list.length; i++) {
			if (list[i]) {
				if (list[i].substr(0, 1) == "#") continue;
				addOrUpdateRelease(list[i]);
			}
		}
		for (var i = 0; i < releases.length; i++) {
			if (releases[i].flaggedForDelete) {
				debugLog("releasesLoadOnload() release " + releases[i].name + " removed");
				releases[i].container.parentNode.removeChild(releases[i].container);
				releases.splice(i, 1);
				i--;
			}
		}
		show("releases-controls");
	} catch (ex) {
		showMessageBox("Error parsing release list (" + (ex.message ? ex.message : ex) + ").");
	}
}

function releasesLoadOnerror(event, request, exception) {
	if (typeof exception != "undefined") {
		showMessageBox("Exception loading release list: " + exception);
	} else {
		showMessageBox("Error loading release list.");
	}
}

function addOrUpdateRelease(data) {
	var releasesBox = document.getElementById("releases");
	
	var ary = data.match(/^(\S+)\s*(.*?)$/);
	if (!ary) {
		throw "Invalid release data: '" + data + "'";
	}
	
	var release, newRelease;
	for (var i = 0; i < releases.length; i++) {
		if (releases[i].name == ary[1]) {
			release = releases[i];
			newRelease = false;
			break;
		}
	}
	if (release) {
		delete release.flaggedForDelete;
		debugLog("addOrUpdateRelease() release " + release.name + " - updated");
	} else {
		newRelease = true;
		release = new Object();
		release.name = ary[1];
		release.date = "";
		release.closed = false;
		release.bugs = new Array();
		releases.push(release);
		debugLog("addOrUpdateRelease() release " + release.name + " - added");
	}
	
	var flags = ary[2].split(/\s+/);
	
	for (var i = 0; i < flags.length; i++) {
		if (flags[i].substr(0, 5) == "date=") {
			release.date = flags[i].substr(5);
		} else if (flags[i].substr(0, 9) == "released=") {
			release.released = (flags[i].substr(9) == "yes");
		} else if (flags[i].substr(0, 5) == "bugs=") {
			var bugList = flags[i].substr(5);
		}
	}
	
	if (newRelease) {
		var insertBefore;
		for (var i = 0; i < releases.length; i++) {
			if (releases[i].name > release.name) {
				insertBefore = releases[i].container;
				break;
			}
		}
		
		release.container = document.createElement("div");
		
		var relTitle = document.createElement("h4");
		relTitle.className = "release-title";
		relTitle.onclick = function(e) {
				var cn = " release-closed";
				if (this.parentNode.className.indexOf(cn) == -1) {
					this.parentNode.className += cn;
				} else {
					this.parentNode.className = this.parentNode.className.replace(cn, "");
				}
			};
		relTitle.appendChild(document.createTextNode(release.name));
		release.container.appendChild(relTitle);
		
		var relCountdown = document.createElement("h5");
		relCountdown.className = "release-countdown";
		relCountdown.appendChild(document.createTextNode(""));
		release.container.appendChild(relCountdown);
		release.countdownBox = relCountdown;
		
		var relDate = document.createElement("h5");
		relDate.className = "release-date";
		var relDateLabel = document.createElement("span");
		relDateLabel.appendChild(document.createTextNode("?"));
		var relEdit = document.createElement("spam");
		relEdit.className = "release-edit";
		var relDateEdit = document.createElement("a");
		relDateEdit.href = "#";
		relDateEdit.onclick = "?";
		relDateEdit.appendChild(document.createTextNode("edit"));
		relEdit.appendChild(document.createTextNode(" ("));
		relEdit.appendChild(relDateEdit);
		relEdit.appendChild(document.createTextNode(")"));
		relDate.appendChild(relDateLabel);
		relDate.appendChild(relEdit);
		release.container.appendChild(relDate);
		release.dateLabelBox = relDateLabel;
		
		var relStatus = document.createElement("h5");
		relStatus.className = "release-status";
		relStatus.appendChild(document.createTextNode("..."));
		release.container.appendChild(relStatus);
		release.statusBox = relStatus;
		
		// Add Bug action
		var relAddBug = document.createElement("a");
		relAddBug.href = "javascript:showAddBug('" + release.name + "')";
		relAddBug.className = "release-add-bug";
		relAddBug.appendChild(document.createTextNode("Add Bug"));
		
		release.container.appendChild(relAddBug);
		
		releasesBox.insertBefore(release.container, insertBefore || null);
	}
	
	var isReleaseClosed = release.released;
	if (release.container.className) {
		isReleaseClosed = /(^| )release-closed( |$)/.test(release.container.className);
	}
	
	release.container.className = "release-box";
	if (release.released) {
		release.container.className += " release-box-released";
	}
	if (isReleaseClosed) {
		release.container.className += " release-closed";
	}
	
	// Show countdown time until release.
	var now = Number(new Date());
	var ary = release.date.match(/^(\d\d\d\d)-(\d\d)-(\d\d)$/);
	var date = 0;
	if (ary) {
		date = new Date(ary[1], ary[2] - 1, ary[3], 23, 59, 59);
	}
	if (date && (date > now)) {
		var days = Math.floor((date - now) / 86400000);
		var weeks = Math.floor(days / 7);
		days -= 7 * weeks;
		if ((weeks == 0) && (days == 0)) {
			var hours = Math.floor((date - now) / 3600000);
			var minutes = Math.floor((date - now) / 60000) - 60 * hours;
			showTextIn(release.countdownBox, (hours > 0 ? hours + "h" : "") + minutes + "m");
		} else {
			showTextIn(release.countdownBox, (weeks > 0 ? weeks + "w" : "") + days + "d");
		}
	} else {
		showTextIn(release.countdownBox, "");
	}
	showTextIn(release.dateLabelBox, release.date);
	
	if (release.bugList != bugList) {
		// Remove all bugs.
		debugLog("addOrUpdateRelease() release " + release.name + " - removed all (" + release.bugs.length + ") bugs");
		for (var i = 0; i < release.bugs.length; i++) {
			release.bugs[i].bugBox.parentNode.removeChild(release.bugs[i].bugBox);
		}
		release.bugs = new Array();
	}
	release.bugList = bugList;
	
	if (bugList) {
		bugList = bugList.split(/,/);
	} else {
		bugList = new Array();
	}
	
	for (var i = 0; i < release.bugs.length; i++) {
		release.bugs[i].flaggedForDelete = true;
	}
	
	for (var i = 0; i < bugList.length; i++) {
		var found = false;
		for (var j = 0; j < release.bugs.length; j++) {
			if (release.bugs[j].key == bugList[i]) {
				release.bugs[j].flaggedForDelete = false;
				found = true;
				break;
			}
		}
		if (!found) {
			addBugToRelease(release.name, bugList[i], !release.released);
		}
	}
	
	for (var i = 0; i < release.bugs.length; i++) {
		if (release.bugs[i].flaggedForDelete) {
			debugLog("addOrUpdateRelease() release " + release.name + " - removed bug " + release.bugs[j].bug.number);
			release.bugs[i].bugBox.parentNode.removeChild(release.bugs[i].bugBox);
			release.bugs.splice(i, 1);
			i--;
		} else {
			delete release.bugs[i].flaggedForDelete;
		}
	}
}

function updateReleaseStatus() {
	for (var i = 0; i < releases.length; i++) {
		var release = releases[i];
		
		var loading = false;
		var bugCount = 0;
		var bugOpen = 0;
		var patchesRQ = 0;
		var patchesRP = 0;
		var patchesRM = 0;
		
		for (var j = 0; j < release.bugs.length; j++) {
			var bug = release.bugs[j].bug;
			if (bug.status) {
				bugCount++;
				if (!bug.resolution) {
					bugOpen++;
				}
			}
			if (bug.patchStatus) {
				if (!bug.resolution) {
					patchesRQ += bug.patchStatus.reviewQ;
					patchesRP += bug.patchStatus.reviewP;
					patchesRM += bug.patchStatus.reviewM;
				}
			} else {
				loading = true;
			}
		}
		
		var status = new Array();
		if (release.released) {
			status.push("released");
		}
		if (bugCount > 0) {
			if (bugOpen > 0) {
				status.push("bugs: " + bugCount + " (" + bugOpen + " open)");
				
				var patchStatus = new Array();
				if (patchesRQ > 0) {
					patchStatus.push(patchesRQ + "?");
				}
				if (patchesRP > 0) {
					patchStatus.push(patchesRP + "+");
				}
				if (patchesRM > 0) {
					patchStatus.push(patchesRM + "-");
				}
				status.push("patches: " + (patchesRQ + patchesRP + patchesRM) + (patchStatus.length > 0 ? " (" + patchStatus.join(", ") + ")" : ""));
			} else {
				status.push("bugs: " + bugCount + " (all closed)");
			}
		}
		if (loading) {
			status.push("still loading...");
		}
		showTextIn(release.statusBox, status.join(", "));
	}
}

function addBugToRelease(releaseName, bugNumber, highPriority) {
	debugLog("addBugToRelease() release " + releaseName + " - added bug " + bugNumber + (highPriority ? " HIGH PRIORITY":""));
	var release;
	for (var i = 0; i < releases.length; i++) {
		if (releases[i].name == releaseName) {
			release = releases[i];
			break;
		}
	}
	if (!release) {
		throw "Error: release '" + releaseName + "' not found.";
	}
	
	var key = bugNumber;
	var maybe = false;
	var ifPoss = false;
	var definately = false;
	if (/[?\.!]$/.test(bugNumber)) {
		if (bugNumber.substr(bugNumber.length - 1) == "?")
			maybe = true;
		if (bugNumber.substr(bugNumber.length - 1) == ".")
			ifPoss = true;
		if (bugNumber.substr(bugNumber.length - 1) == "!")
			definately = true;
		bugNumber = bugNumber.substr(0, bugNumber.length - 1);
	}
	
	bugNumber = bugNumber.replace(/[^0-9]/g, "");
	
	if (highPriority) {
		var bug = getBug(bugNumber);
		bug.loadSummary(true);
		bug.loadDetails(true);
	}
	
	var inst = insertBugSummaryLine(release.container, "release", bugNumber);
	inst.key = key;
	release.bugs.push(inst);
	
	if (maybe || ifPoss || definately) {
		// Extra status info.
		var bugExtra = document.createElement("span");
		bugExtra.className = "bug-extra";
		if (maybe)
			bugExtra.appendChild(document.createTextNode("(maybe)"));
		if (ifPoss)
			bugExtra.appendChild(document.createTextNode("(if poss.)"));
		if (definately)
			bugExtra.appendChild(document.createTextNode("(required)"));
		inst.bugBox.insertBefore(bugExtra, inst.bugBox.firstChild);
	}
	
	// Remove action
	var bugRemoveBtn = document.createElement("a");
	bugRemoveBtn.href = "javascript:alert('No!')";
	bugRemoveBtn.className = "bug-remove";
	bugRemoveBtn.appendChild(document.createTextNode("Remove"));
	inst.bugBox.appendChild(bugRemoveBtn);
}

function showAddBug(releaseName) {
	showTextIn("search_bugs_title", "Add bug to " + releaseName);
	showDialog("search");
	focus("search_bugs_term");
}

function bugSearchKeypress(event) {
	if (event.keyCode == 13) {
		searchForBugs();
		if (event.stopPropagation) {
			event.stopPropagation();
		}
	}
}

function searchForBugs() {
	// http://bugzilla.mozilla.org/buglist.cgi
	// ?component=ChatZilla
	// &bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED
	// &short_desc_type=allwordssubstr&short_desc=foobar
	
	showTextIn("search_bugs_footer", "Searching...");
	document.getElementById("search_bugs_inc_closed").disabled = true;
	document.getElementById("search_bugs_term").disabled = true;
	document.getElementById("search_bugs_button").disabled = true;
	
	var term = document.getElementById("search_bugs_term").value;
	var incClosed = document.getElementById("search_bugs_inc_closed").checked;
	
	var url = "https://bugzilla.mozilla.org/buglist.cgi" +
			"?format=rdf&columnlist=all&component=ChatZilla" +
			(incClosed ? "" : "&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED") +
			"&short_desc_type=allwordssubstr&short_desc=" + escape(term) +
			"&order=Last+Changed";
	
	var searchReq = new WebRequest("GET", url, bugSearchOnload, bugSearchOnerror);
	searchReq.priority = 100;
	searchReq.load();
}

function bugSearchOnload(event, request, data) {
	var results = document.getElementById("search_bugs_results");
	while (results.lastChild) {
		results.removeChild(results.lastChild);
	}
	
	data = data.replace(/[\r\n\s]+/g, " ");
	
	var bugMatch, id, count = 0;
	var list = new Array();
	while ((bugMatch = data.match(/^(.*?)<\/bz:bug>/))) {
		var bugItem = bugMatch[1];
		data = data.substr(bugMatch[0].length);
		
		var ary = bugItem.match(/<bz:id[^>]*>(.*?)<\/bz:id>/);
		id = 1 * ary[1];
		
		count++;
		list.unshift(id);
	}
	
	// Make list of all release-used bug IDs.
	var i, j;
	var bugIDs = new Object();
	for (i = 0; i < releases.length; i++) {
		for (j = 0; j < releases[i].bugs.length; j++) {
			bugIDs[releases[i].bugs[j].bug.number] = true;
		}
	}
	
	for (i = 0; i < list.length; i++) {
		insertBugSummaryLine(results, (list[i] in bugIDs ? "search-used" : "search"), list[i]);
	}
	
	showTextIn("search_bugs_footer", (count == 1 ? "1 bug" : count + " bugs"));
	document.getElementById("search_bugs_inc_closed").disabled = false;
	document.getElementById("search_bugs_term").disabled = false;
	document.getElementById("search_bugs_button").disabled = false;
	focus("search_bugs_term");
}

function bugSearchOnerror(event, request, exception) {
	showTextIn("search_bugs_footer", "");
	document.getElementById("search_bugs_inc_closed").disabled = false;
	document.getElementById("search_bugs_term").disabled = false;
	document.getElementById("search_bugs_button").disabled = false;
	if (typeof exception != "undefined") {
		showTextIn("search_bugs_results", "Exception loading bug list: " + exception);
	} else {
		showTextIn("search_bugs_results", "Error loading bug list: " + request.req.status + " (" + request.req.statusText + ")");
	}
	focus("search_bugs_term");
}

var currentBugView;
function showBugInfo(id) {
	var bug = bugs[id];
	
	if (currentBugView) {
		currentBugView.remove();
	}
	currentBugView = new BugInst(bug.number);
	
	function set(name, id) {
		var elt = document.getElementById(id);
		currentBugView[name] = elt;
		
		while (elt.lastChild) {
			elt.removeChild(elt.lastChild);
		}
	};
	
	set("summaryBox",    "bug_view_summary");
	set("whiteboardBox", "bug_view_whiteboard");
	set("productBox",    "bug_view_product");
	set("componentBox",  "bug_view_component");
	set("severityBox",   "bug_view_severity");
	set("priorityBox",   "bug_view_priority");
	set("opsysBox",      "bug_view_opsys");
	set("platformBox",   "bug_view_platform");
	set("versionBox",    "bug_view_version");
	set("reporterBox",   "bug_view_reporter");
	set("assigneeBox",   "bug_view_assignee");
	set("qaBox",         "bug_view_qa");
	
	set("commentsContainer", "bug_view_comments");
	
	showTextInWithHint("bug_view_title", "Bug " + bug.number + " details");
	showBugSummary(currentBugView);
	
	showTextIn("bug_view_status", bug.status + (bug.resolution ? " / " + bug.resolution : ""));
	
	document.getElementById("bug_view_link").href = "https://bugzilla.mozilla.org/show_bug.cgi?id=" + bug.number;
	
	showDialog("bug_view");
	focus("bug_view_close");
}

function reloadBugView() {
	if (currentBugView) {
		currentBugView.bug.loadSummary();
		currentBugView.bug.loadDetails();
	}
}

var releasedHidden = false;
function toggleReleased() {
	releasedHidden = !releasedHidden;
	if (releasedHidden) {
		document.body.className += " hide-released";
		showTextIn("toggle-released", "Show released versions");
	} else {
		document.body.className = document.body.className.replace(/(^| )hide-released/g, "");
		showTextIn("toggle-released", "Hide released versions");
	}
}

addListener(window, "load", czrcInit);

