
function ClonePage()
{
	this.initIdList(['build-resources', 'notes-container', 'chrm-search']);
}

ClonePage.prototype = new Page();

function initPage()
{
	if(!Array.prototype.indexOf)
		Array.prototype.indexOf = function(obj){
			var n = this.length;
			while(n-- > 0)
				if(this[n] == obj) break;
			return n;
		}
	
	// add RSSHandler's methods to ClonePage if they are not overridden
	appendMethods(ClonePage.prototype, RSSHandler.prototype);
	appendMethods(ClonePage.prototype, BuildListHandler.prototype);
	
	if(!window.controller){
		window.controller = new ClonePage();
		controller.preloadImages();
		controller.init();
	}
	if(window.console)
		window.console.log("--- Clone Finder: initializing ---");
}

Ext.onReady(initPage);
//window.onload = initPage;

ClonePage.prototype.newsRequest = {area:"mvsearch"};
ClonePage.prototype.rssRequest = {area:"mvsearch", expired:"yes"};
ClonePage.prototype.buildInfoRequest = {};
ClonePage.prototype.mapviewerRequest = {};

ClonePage.prototype.init = function()
{
	this.checkForOutage();
	this.form = document.forms["searchForm"];
	this.dataCache = $("data-cache");
	this.stateCache = this.form.state;
	
	try{
		this.libInfo = $("lib-info");
	}catch(e){
		logError(e);
	}
	
	if(this.dataCache && this.dataCache.value)
		this.dataIds = this.dataCache.value.split(','); // info to keep open
	
	this.taxid = this.form.taxid.value;
	this.build = this.form.build.value;
		
	this.rssContainer = $('notes-container');
	this.orgNotesAnchor = $('org-notes');

	var rt = 0; // region type
	var mode = 0; // object search mode
	var paramStr = window.location.search;
	this.params = paramStr? Utils._parseParams(paramStr.substr(1)) : null;
	if(this.params && this.params.rt)
		rt = parseInt(this.params.rt);
	if(this.params && this.params.m)
		mode = parseInt(this.params.m);
	
	if(window.RG){
		RG.initRG();
		var tabs = ["hpos", "hobj"];
		this.regionController = new RG.Region({
			header: false,
			renderTo:"rg-region",
			type:"panel",
			controlWidth: 130,
			inputWidth:166,
			panelWidth:640,
			tabs: tabs,
			activeTab: tabs[rt],
			tabIndex:200,
			buttonStyle: "margin-right: 138px",
			buildInfo:{taxid:this.taxid, build:this.build, load:false}
		});
		this.regionController.setRegionMatrix(new RegionMatrix()); // matrix is defined already
		this.regionController.show();
		this.regionController.on("submit", this.setRegion, this);
		if(document.getElementById("region-find")){
			var findButton1 = new Ext.Button({
					renderTo: "region-find",
					handler: this.findClones,
					scope: this,
					tabIndex: 300,
					text: "Find Clones"
				});
			var findButton2 = new Ext.Button({
					renderTo: "region-find2",
					handler: this.findClones,
					scope: this,
					tabIndex: 310,
					text: "Find Clones"
				});
			if(!window.supportsCloneFinder){
				findButton1.setDisabled(true);
				findButton2.setDisabled(true);
			}
		}
	}else{
		this.regionController = new RegionController(this.taxid, this.build, null, rt, mode);
		this.regionController.matrix = new RegionMatrix(); // matrix is set already
	}
	
	if(this.params){
		if(window.RG)
			this.regionController.on("render", this.updateRegionController, this);
		else
			this.regionController.update(this.params);
	}


	this.libContainer = $("lib-container");
	this.regionSetButton = $("region-set");
	this.regionTable = $("regions");
	this.setupLibraries();

	try{
		this.initDivContent($('info'), false, this.idList);
		this.initBuildList($('org-build-list'));
	}catch(e){
		logError(e);
	}

	this.rssRequest.taxid = this.taxid;
	this.newsRequest.taxid = this.taxid;
	this.rssUrl += "?" + Utils._encodeParams(this.rssRequest);
	this.rssOffset = [-40, -40];
	this.rssAlign = "tr-bl";
	
	this.getRSS();
	this.lineage = new Lineage($("lineage-container"));
	this.lineage.init(this.taxid);
	
	NotificationCenter.addObserver(this, "orgNotesDidLoad", InfoUtils.OrgNotesLoaded);
	NotificationCenter.addObserver(this, "orgNotesDidFail", InfoUtils.OrgNotesFailed);
	InfoUtils.getOrgNotes(this.taxid); // get organism notes

	NotificationCenter.addObserver(this, "containerDidCollapse", "ContainerDidCollapse");
	NotificationCenter.addObserver(this, "containerDidExpand", "ContainerDidExpand");

	NotificationCenter.addObserver(this, "populationDidEnable", "PopulationDidEnable");
	NotificationCenter.addObserver(this, "dnaSourceDidEnable", "DNASourceDidEnable");
	NotificationCenter.addObserver(this, "datasetDidEnable", "DatasetDidEnable");
	NotificationCenter.addObserver(this, "libraryDidEnable", "LibraryDidEnable");

	var panel = $("range-info");
	if(panel && window.DragController)
		DragController.add(panel);
	panel = $("info-panel");
	if(panel && window.DragController)
		DragController.add(panel);

	if(window.RG)
		RG.ContextHelp.setConfig({title:"Clone Finder Help", align:"c-c", offY:-40, offX: -120, width:560});

	var div = $("page-description");
	if(div){
		var helper;
		if(window.RG)
			helper = new RG.ContextHelp({
				container:div,
				width:"auto",
				bodyCls:null
			});
		else
			var helper = new ContextHelp(div);
		helper.getContextHelp("CloneFinderDescription");
	}
	
	if(this.restoreState)
		this.restoreState();
	this.idList["."] = true; // if all closed 
}

ClonePage.prototype.toString = function()
{
	return "ClonePage";
}

ClonePage.prototype.preloadImages = function()
{
	window.images = new Object();
	var def = [
		['arrowRight', this.commonImageDir + '/right-h.png', 'Click to expand'],
		['arrowDown', this.commonImageDir + '/down-h.png', 'Click to collapse']
	];
	for(var n=0;n<def.length;n++){
		images[def[n][0]] = $element('img');
		images[def[n][0]].src = def[n][1];
		images[def[n][0]].title = def[n][2];
	}
}

ClonePage.prototype.updateRegionController = function()
{
	if(this.params){
		this.params.tab = this.params.rt == 1? "hobj" : "hpos";
		this.regionController.update(this.params);
	}
}

ClonePage.prototype.initLibraries = function()
{
	try{
		this.dataSetContainer = new DatasetContainer();
		this.dataSetContainer.init($("dataset"), $("dataset-h"), "dataset");
		this.dnaSourceContainer = new DNASourceContainer();
		this.dnaSourceContainer.init($("dna-source"), $("dna-source-h"), "dnasource");
		this.populationContainer = new PopulationContainer();
		this.populationContainer.init($("population"), $("population-h"), "population");
		this.libraryContainer = new LibraryContainer();
		this.libraryContainer.init($("library"), $("library-h"), "librray");
		this.cloneTypeContainer = new CloneTypeContainer();
		this.cloneTypeContainer.init($("pl-char"), $("pl-char-h"), "placement");
	}catch(e){
		logError(e);
	}
}

ClonePage.prototype.setRegionLibraries = function()
{
	this.dataSetContainer.setRegion(this.region);
	this.dnaSourceContainer.setRegion(this.region);
	this.populationContainer.setRegion(this.region);
	this.libraryContainer.setRegion(this.region);
	this.cloneTypeContainer.setRegion(this.region);
}

ClonePage.prototype.resetLibraries = function()
{
	this.dataSetContainer = null;
	this.dnaSourceContainer = null;
	this.populationContainer = null;
	this.libraryContainer = null;
	this.cloneTypeContainer = null;
}

ClonePage.prototype.findClones = function()
{
	if(this.region.disabled){
		alert("Selected region has no placement ranges included.\nYou should include at least one plaecement range in the region.");
		return;
	}
	if(this.region.end - this.region.start > this.maxRegionLength){
		if(!confirm("The selected region length exceed the recommended maximum of " + ncbiformatter.formatNumber(this.maxRegionLength) + 
					" bp.\nThis may result in longer response time.\nClick OK to proceed or Cancel"))
			return;
	}
	var query = new Object();
	query.taxid = this.taxid;
	query.B = this.buildObject.build;
	query.V = this.buildObject.version;
	query.chr = this.region.chr;
	query.assembly = this.region.asmb;
	if(this.region.start)
		query.beg = this.region.start + 1;
	else
		query.beg = 1;
	if(this.region.end)
		query.end = this.region.end + 1;
	else{
		alert("Cannot get the length of chromosome '" + 
			this.region.chr + "' on assembly '" + this.region.asmb + "'.\nPlease specify the region using explicit 'To' position.");
		return;
	}
	var array = this.libraryContainer.selectedLibraries();
	query.libs = array.join(",");
	
//	var url = "../clonefinder/clonefinder.cgi?" + Utils._encodeParams(query);
	var url = this.actionURL + "?" + Utils._encodeParams(query);
	
	if(this.saveState)
		this.saveState();
	window.location = url;
}

ClonePage.prototype.setRegion = function()
{
	var query = this.regionController.regionQuery();
	if(query.error){
		if(query.message)
			alert(query.message)
		return;
	}
	delete query.options;
	var url = "mvclone.cgi?" + Utils._encodeParams(query);
	window.location.assign(url);
}

ClonePage.prototype.loadRegions = function()
{
	var array = new Array();
	var regionIds = Container.prototype.reference.regions;
	for(var k=0;k<regionIds.length;k++){
		var region = Container.prototype.reference[regionIds[k]];
		region.order = this.chrOrder[region.chr];
		if(!region.end)
			region.end = this.regionController.chromosomeLength(region) - 1;
		if(region.end < 0)
			delete region.end;
		array.push(region);
	}
	if(array.length > 0){
		var cmp = function(r1,r2){
			return r1.order < r2.order? -1 : (r1.order > r2.order? 1 : 0);
		}
		array.sort(cmp);
	}
	this.regionRows = [];
	for(var n=0;n<array.length;n++)
		this.addRegionRow(array[n], n);
}

ClonePage.prototype.addRegionRow = function(region, regionIndex)
{
	var index = this.regionTable.rows.length;
	var row = this.regionTable.insertRow(index);
	row.region = region;
	if(regionIndex % 2 == 0)
		row.className = "odd";
	var td = $element("td");
	td.className = "region-mark";
	row.appendChild(td);
	
	td = $element("td");
	row.chbx = $element("input");
	row.chbx.type = "radio";
	row.chbx.row = row;
	if(row.chbx.addEventListener)
		row.chbx.addEventListener("click", function(eventObj){
		var target = eventObj.target;
		controller.selectRegion(target)
		}, false);
	else if(row.chbx.attachEvent)
		row.chbx.attachEvent("onclick", function(){
			var target = event.srcElement;
			controller.selectRegion(target);
		});
	td.appendChild(row.chbx);
	row.appendChild(td);
	td.className = "radio";
	
	row.appendChild(td = $element("td"));
	td.appendChild($text(region.asmb));
	td.className = "asmb";
	row.appendChild(td = $element("td"));
	td.appendChild($text(region.chr));
	td.className = "chr";

	row.appendChild(td = $element("td"));
	td.className = "region-info";
	td.appendChild(row.info = $element("img"));
	row.info.src = this.commonImageDir + "/info.png";
	row.info.region = region;
	row.info.style.display = "none";
	row.info.title = "Click for info on the region";
	
	row.appendChild(td = $element("td"));
	td.className = "number";
	if(region.start != null)
		td.appendChild($text(ncbiformatter.formatNumber(region.start + 1)));
	row.appendChild(td = $element("td"));
	td.className = "number";
	if(region.end != null)
		td.appendChild($text(ncbiformatter.formatNumber(region.end + 1)));
	row.appendChild(td = $element("td"));
	td.className = "number";
	if(region.end != null && region.start != null)
		td.appendChild($text(ncbiformatter.formatNumber(region.end - region.start + 1)));
	if(region.ranges && region.ranges.length > 1)
		this.addRangeRows(this.regionTable, row);
	if(region.end - region.start > this.maxRegionLength)
			this.markRegionRow(row, true);

	if(row.info && row.info.addEventListener){
		row.info.addEventListener("click", function(eventObj){
								  var target = eventObj.target;
								  controller.showRegionInfo(target);
								  }, false);
	}else if(row.info && row.info.attachEvent){
		row.info.attachEvent("onclick", function(){
							 var target = event.srcElement;
							 controller.showRegionInfo(target);
							 });
	}
	this.regionRows.push(row);
}

ClonePage.prototype.addRangeRows = function(table, regionRow)
{
	regionRow.rangeRows = new Array();
	var region = regionRow.region;
	var index = table.rows.length;
	var row = table.insertRow(index++);
	row.className = "range-header";
	var td = $element("td");
	td.colSpan = 6;
	td.style.textAlign = "center";
	td.appendChild($text("Select placement ranges to include"));
	row.appendChild(td);

	row.appendChild(td = $element("td"));
	td.colSpan = 3;
	td.style.textAlign = "right";
	td.innerHTML = "<span class='rlink'>" +
		"<a onclick='enableAllRanges(this,true)' href='javascript:void(0)'><img src='" + this.commonImageDir + "/check-all1.png'/>Check all</a>" +
		"<a onclick='enableAllRanges(this,false)' href='javascript:void(0)'><img src='" + this.commonImageDir + "/clear1.png'/>Clear all</a>" +
		"</span>";
	regionRow.rangeRows.push(row);
	row.style.borderBottom = "solid 1px rgb(192,198,203)";
	row.style.display = "none";
	for(var n=0;n<region.ranges.length;n++){
		var range = region.ranges[n];
		row = table.insertRow(index++);
		row.style.display = "none";
		row.className = regionRow.className;
		row.appendChild(td = $element("td"));
		td.colSpan = 3;
		
		row.appendChild(td = $element("td"));
		td.className = "range";
		row.chbx = $element("input");
		row.chbx.type = "checkbox";
		td.appendChild(row.chbx);
		row.chbx.checked = true;
		row.chbx.range = range;
		row.chbx.region = region;
		row.chbx.regionRow = regionRow;

		row.appendChild(td = $element("td"));
		td.className = "region-info";
		td.appendChild(row.info = $element("img"));
		row.info.src = this.commonImageDir + "/info.png";
		row.info.range = range;
		row.info.title = "Click for info on the range";
		
		row.appendChild(td = $element("td"));
		td.className = "number";
		if(range.start != null)
			td.appendChild($text(ncbiformatter.formatNumber(range.start + 1)));
		row.appendChild(td = $element("td"));
		td.className = "number";
		if(range.end != null)
			td.appendChild($text(ncbiformatter.formatNumber(range.end + 1)));
		row.appendChild(td = $element("td"));
		td.className = "number";
		if(range.end != null && range.start != null)
			td.appendChild($text(ncbiformatter.formatNumber(range.end - range.start + 1)));
		
		regionRow.rangeRows.push(row);

		if(row.chbx.addEventListener){
			row.chbx.addEventListener("click", function(eventObj){
			var target = eventObj.target;
			controller.updateRegion(target);
			}, false);
		}else{
			row.chbx.attachEvent("onclick", function(){
				var target = event.srcElement;
				controller.updateRegion(target);
			});
		}

		if(row.info.addEventListener){
			row.info.addEventListener("click", function(eventObj){
				var target = eventObj.target;
				controller.showRangeInfo(target);
			}, false);
		}else if(row.info.attachEvent){
			row.info.attachEvent("onclick", function(){
				var target = event.srcElement;
				controller.showRangeInfo(target);
			});
		}
	}
	row.style.borderBottom = "solid 1px rgb(192,198,203)";

}

ClonePage.showAlert = function(mark, eventObj)
{
	if(mark.alert && mark.alertBox){
		var rect = Rect.elementRect(mark);
		mark.alertBox.style.top = (rect.y + rect.height + 10) + "px";
		mark.alertBox.style.left = (rect.x + 10) + "px";
		mark.alertBox.innerHTML = mark.alert;
		mark.alertBox.style.visibility = "visible";
	}
}
ClonePage.hideAlert = function(mark, eventObj)
{
	if(mark.alertBox)
		mark.alertBox.style.visibility = "hidden";
}

ClonePage.prototype.markRegionRow = function(row, show)
{
	if(show){
		if(!this.alertBox){
			this.alertBox = $element("div");
			this.alertBox.className = "alert";
			this.alertBox.style.position = "absolute";
			this.alertBox.style.visibility = "hidden";
			document.body.appendChild(this.alertBox);
		}
		if(!row.mark){
			row.mark = $element("img");
			row.mark.src = this.commonImageDir + "/region-mark.png";
			row.mark.alertBox = this.alertBox;
			if(row.mark.addEventListener){
				row.mark.addEventListener("mouseover", function(eventObj){
					var target = eventObj.target;
					ClonePage.showAlert(target, eventObj);
				}, false);
				row.mark.addEventListener("mouseout", function(eventObj){
					var target = eventObj.target;
					ClonePage.hideAlert(target, eventObj);
				}, false);
			}else if(row.mark.attachEvent){
				row.mark.attachEvent("onmouseover", function(){
					var target = event.target? event.target : event.srcElement;
					ClonePage.showAlert(target, eventObj);
				});
				row.mark.attachEvent("onmouseout", function(){
					var target = event.target? event.target : event.srcElement;
					ClonePage.hideAlert(target, eventObj);
				});
			}
			row.cells[0].appendChild(row.mark);
			if(row.region && row.region.ranges && row.region.ranges.length > 1)
				row.mark.alert = "Region length is too long.</br>The recommended region length is " + ncbiformatter.formatNumber(this.maxRegionLength) +
					" or less.<br>The longer region length may result in longer response time or even a timeout with error code 500.<br>" +
					"Please select ranges.";
			else
				row.mark.alert = "Region length is too long.</br>The recommended region length is " + ncbiformatter.formatNumber(this.maxRegionLength) +
					" or less.<br>The longer region length may result in longer response time or even a timeout with error code 500.<br>" +
					"Please reset the region.";
		}else
			row.mark.style.display = "";
	}else if(row.mark)
		row.mark.style.display = "none";
}

ClonePage.prototype.setupLibraries = function(regionId)
{
	var ok = false;
	var error;
	if(this.regionTable){
		this.loadRegions();
		this.initLibraries();
	//	this.regionSetButton.disabled = false;
		var row0 = null;
		for(var n=1; n<this.regionTable.rows.length;n++){
			var row = this.regionTable.rows[n];
			if(row && row.region && row.region.id == regionId){
				row0 = row; break;
			}
		}
		if(!row0)
			row0 = this.regionTable.rows[1];
		if(row0)
			this.selectRegion(row0);
	}
}

ClonePage.prototype.populationDidEnable = function(note)
{
	if(this.libraryContainer)
		this.libraryContainer.updateCells(note);
}

ClonePage.prototype.dnaSourceDidEnable = function(note)
{
	if(this.libraryContainer)
		this.libraryContainer.updateCells(note);
}
ClonePage.prototype.datasetDidEnable = function(note)
{
	if(this.libraryContainer)
		this.libraryContainer.updateCells(note);
}
ClonePage.prototype.libraryDidEnable = function(note)
{
	if(this.cloneTypeContainer)
		this.cloneTypeContainer.libraryDidEnable(note);
}

// sender may be a row or an input in the row
ClonePage.prototype.selectRegion = function(sender)
{
	if(this.region){
		this.regionRow.style.backgroundColor = "";
		this.regionRow.chbx.checked = false;
		if(this.regionRow.rangeRows){
			for(var n=0;n<this.regionRow.rangeRows.length;n++)
				this.regionRow.rangeRows[n].style.display = "none";
		}
		if(this.regionRow.info)
			this.regionRow.info.style.display = "none";
	}
	var row = sender;
	while(row.nodeName.toLowerCase() != "tr")
		row = row.parentNode;
	this.regionRow = row;
	this.regionRow.style.backgroundColor = /*"rgb(155,195,230)";*/ "rgb(182,206,229)";
	this.region = row.region;
	row.chbx.checked = true;
	if(this.regionRow.rangeRows){
		for(var n=0;n<this.regionRow.rangeRows.length;n++)
			this.regionRow.rangeRows[n].style.display = "";
	}
	if(this.regionRow.info && this.region.ranges && this.region.ranges.length > 0)
		this.regionRow.info.style.display = "";
	
	this.setRegionLibraries();
	this.hideRangeInfo();
}

ClonePage.prototype.enableAllRanges = function(sender, flag)
{
	if(this.regionRow && this.regionRow.rangeRows){
		for(var n=1;n<this.regionRow.rangeRows.length;n++){
			this.regionRow.rangeRows[n].chbx.checked = flag;
			this.regionRow.rangeRows[n].chbx.range.enabled = flag;
		}
		this.updateRegion({region:this.regionRow.region, regionRow:this.regionRow});
	}
}

ClonePage.prototype.regionRangeCellIndex = 5;
ClonePage.prototype.updateRegion = function(sender)
{
	if(sender.range)
		sender.range.enabled = sender.checked;
	if(sender.region && sender.region.ranges){
		var region = sender.region;
		var start = null;
		var end = null;
		for(var n=0;n<region.ranges.length;n++){
			var range = region.ranges[n];
			if(range.enabled){
				if(start == null){
					start = range.start;
					end = range.end;
				}else{
					if(range.start < start)
						start = range.start;
					if(range.end > end)
						end = range.end;
				}
			}
		}
		region.start = start;
		region.end = end;
		if(region.start != null){
			sender.regionRow.cells[this.regionRangeCellIndex].innerHTML = ncbiformatter.formatNumber(this.region.start + 1);
			sender.regionRow.cells[this.regionRangeCellIndex + 1].innerHTML = ncbiformatter.formatNumber(this.region.end + 1);
			sender.regionRow.cells[this.regionRangeCellIndex + 2].innerHTML = ncbiformatter.formatNumber(this.region.end - this.region.start + 1);
			region.disabled = false;
			if(end - start > this.maxRegionLength)
				this.markRegionRow(sender.regionRow, true);
			else
				this.markRegionRow(sender.regionRow, false);
		}else{
			sender.regionRow.cells[this.regionRangeCellIndex].innerHTML = "";
			sender.regionRow.cells[this.regionRangeCellIndex + 1].innerHTML = "";
			sender.regionRow.cells[this.regionRangeCellIndex + 2].innerHTML = "";
			region.disabled = true;
			this.markRegionRow(sender.regionRow, false);
		}
	}
	this.hideRangeInfo();
}

function NotifyingContainer() {}
NotifyingContainer.prototype = new Container();
NotifyingContainer.prototype.notifyAll = function()
{
	if(this.notificationName){
		var count = 0;
		var info = new Object();
		for(var n=0;n<this.cells.length;n++){
			var cell = this.cells[n];
			if(!cell.chbx.disabled){
				var uid = cell.getAttribute("uid");
				var ref = this.reference[this.region.id][this.refTag];
				if(!ref)
					ref = this.reference[this.refTag];
				if(ref){
					if(!ref[uid] || !ref[uid].enabled) // chbx should be disabled in this case
						continue;
					if((cell.chbx.checked && !ref[uid].state) || (!cell.chbx.checked && ref[uid].state)){
						ref[uid].state = cell.chbx.checked? 1 : 0;
						info[uid] = true;
						count += 1;
					}
				}
			}
		}
		if(count > 0)
			Notification.postNotification(this.notificationName, this, info);		
	}
}
NotifyingContainer.prototype.notifyCell = function(cell)
{
	if(this.notificationName && cell){
		var uid = cell.getAttribute("uid");
		var ref = this.reference[this.region.id][this.refTag];
		if(!ref)
			ref = this.reference[this.refTag];
		if(ref && ref[uid] && ref[uid].enabled){
			ref[uid].state = cell.chbx.checked? 1 : 0;
			var info = new Object();
			info[uid] = true;
			Notification.postNotification(this.notificationName, this, info);
		}
	}
}

NotifyingContainer.prototype.setRegion = function(region)
{
	this.region = region;
	for(n=0;n<this.cells.length;n++){
		var cell = this.cells[n];
		var uid = cell.getAttribute("uid");
		var ref = this.reference[this.region.id][this.refTag];
		if(ref[uid] && ref[uid].enabled){
			cell.className = "";
			cell.chbx.disabled = false;
			cell.chbx.checked = ref[uid].state != 0;
			this.updateCellStatus(cell, ref[uid].state);
		}else{
			cell.chbx.disabled = true;
			cell.chbx.checked = false;
			cell.className = "off";
		}
	}
}

NotifyingContainer.prototype.setCellEnabled = function(cell, enabled)
{
	var uid = cell.getAttribute("uid");
	var ref = this.reference[this.region.id][this.refTag];
	if(ref && ref[uid]){
		ref[uid].state = enabled? 1 : 0;
		cell.chbx.checked = ref[uid].state != 0;
		this.updateCellStatus(cell, ref[uid].state);
	}
}

function PopulationContainer(){ }
PopulationContainer.prototype = new NotifyingContainer();
PopulationContainer.prototype.notificationName = "PopulationDidEnable";
PopulationContainer.prototype.refTag = "population";


function DNASourceContainer() {}
DNASourceContainer.prototype = new NotifyingContainer();
DNASourceContainer.prototype.notificationName = "DNASourceDidEnable";
DNASourceContainer.prototype.refTag = "dnaSource";

DNASourceContainer.prototype.setRegion = function(region)
{
	this.region = region;
	for(n=0;n<this.cells.length;n++){
		var cell = this.cells[n];
		var uid = cell.getAttribute("uid");
		this.reference.dnaSource[uid].state = 1;
		cell.chbx.checked = true;
		this.updateCellStatus(cell, 1);
	}
}

function DatasetContainer(){ }
DatasetContainer.prototype = new NotifyingContainer();
DatasetContainer.prototype.notificationName = "DatasetDidEnable";
DatasetContainer.prototype.refTag = "ds";


function LibraryContainer() {}
LibraryContainer.prototype = new NotifyingContainer();
LibraryContainer.prototype.notificationName = "LibraryDidEnable";
LibraryContainer.prototype.refTag = "lib";

LibraryContainer.prototype.updateCells = function(note)
{
	var info = new Array();
	for(var n=0;n<this.cells.length;n++){
		var cell = this.cells[n];
		var uid = cell.getAttribute("uid");
		var ref = this.reference[this.region.id].lib[uid];
		if(ref){
			var newState = 0;
			for(var k=0;k<ref.ds.length;k++){ // calculate new state
				var dsUid = ref.ds[k];
				if(this.reference[this.region.id].ds[dsUid] && this.reference[this.region.id].ds[dsUid].state){
					newState = 1;
					break;
				}
			}
			// intersect with dna source
			if(newState){
				var phenotype = cell.getAttribute("phenotype");
				var source = phenotype? phenotype.toLowerCase() : "normal"; 
				var dnaRef = this.reference.dnaSource[source];
				newState = newState && dnaRef.state;
			}
			// intersect with population
			if(newState){
				var popRef = this.reference[this.region.id].population[ref.pid];
				newState = newState && (popRef? popRef.state : 0); // popRef must be set
			}
			if(newState != ref.state){
				info.push(uid);
				ref.state = newState;
				cell.chbx.checked = newState != 0;
				this.updateCellStatus(cell, newState);
			}
		}
	}
	if(info.length > 0)
		Notification.postNotification(this.notificationName, this, info);
}

LibraryContainer.prototype.selectedLibraries = function()
{
	var array = new Array();
	for(var n=0; n<this.cells.length;n++){
		if(this.cells[n].chbx.checked)
			array.push(this.cells[n].chbx.value);
	}
	return array;
}

function CloneTypeContainer(){ }
CloneTypeContainer.prototype = new Container();
CloneTypeContainer.prototype.refTag = "cloneType";

CloneTypeContainer.prototype.setRegion = function(region)
{
	this.region = region;
	for(var n=0;n<this.cells.length;n++){
		var cell = this.cells[n];
		var uid = cell.getAttribute("uid");
		var ref = this.reference[this.region.id].cloneType[uid];
		if(ref && ref.libs && ref.libs.length > 0){
			ref.enabled = true;
			ref.state = 1;
			cell.chbx.checked = true;
			cell.chbx.disabled = false;
			cell.className = "";
			this.updateCellStatus(cell, ref.state);
		}else{
			cell.chbx.checked = false;
			cell.chbx.disabled = true;
			cell.className = "off";
			if(ref){
				ref.enabled = false;
				ref.state = 0;
			}
		}
	}
}

CloneTypeContainer.prototype.libraryDidEnable = function(note)
{
	for(var n=0;n<this.cells.length;n++){
		var cell = this.cells[n];
		var uid = cell.getAttribute("uid");
		var ref = this.reference[this.region.id].cloneType[uid];
		if(ref){
			var newState = 0;
			for(var k=0;k<ref.libs.length;k++){
				var libRef = this.reference[this.region.id].lib[ref.libs[k]];
				if(libRef && libRef.state){
					newState = 1;
					break;
				}
			}
			if(newState != ref.state){ // our population did change
				ref.state = newState;
				cell.chbx.checked = newState != 0;
				cell.chbx.disabled = newState == 0;
				this.updateCellStatus(cell, newState);
			}
		}
	}
}
CloneTypeContainer.prototype.toggleCellStatus = function(sender)
{
	var cell = null;
	if(sender.nodeName.toLowerCase() == 'input' && sender.type == 'checkbox'){
		cell = sender.parentNode;
		this.updateCellStatus(cell, sender.checked? 1 : 0);
		var uid = cell.getAttribute("uid");
		var ref = this.reference[this.region.id].cloneType[uid];
		if(ref)
			ref.state = cell.chbx.checked? 1 : 0;
	}
}


ClonePage.prototype.libInfoTimeout = 30000; // ms
ClonePage.prototype.fadeOutLibInfo = false;

ClonePage.prototype.showLibInfo = function(eventObj, span, flag)
{
	var cell = span.parentNode;
	if(flag){
		$("lib-info-name").innerHTML = cell.getAttribute("name");
		$("lib-info-libid").innerHTML = this.libInfo.libId = cell.getAttribute("uid");
		var population = cell.getAttribute("population");
		var kind = cell.getAttribute("kind");
		$("lib-info-pop").innerHTML = population? population : "Unspecified";
		$("lib-info-kind").innerHTML = (kind? kind : "Strain") + ":";
		$("lib-info-type").innerHTML = cell.getAttribute("type") || "unspecified";
		$("lib-info-dnasrc").innerHTML = cell.getAttribute("phenotype") || "unspecified";
		var rect = Rect.elementRect(cell);
		this.libInfo.style.top = (rect.y + rect.height + 10) + "px";
		this.libInfo.style.left = (rect.x + 10) + "px";
		this.libInfo.style.visibility = "visible";
		if(this.fadeOutLibInfo)
			this.libInfo.timeoutId = window.setTimeout("controller.closeLibInfo(" + this.libInfo.libId + ")", this.libInfoTimeout);
	}else
		this.libInfo.style.visibility = "";
}

ClonePage.prototype.closeLibInfo = function(libId)
{
	if(this.libInfo.libId == libId)
		this.libInfo.style.visibility = "";
}

ClonePage.prototype.showRangeInfo = function(infoEl)
{
	var div = $("range-info");
	var range = infoEl.range;
	if(div && range && range.objects){
		var table = $("range-info-table");
		var n = table.rows.length;
		while(n-- > 1)
			table.deleteRow(n);
		if(this.showObjectId)
			this.fillFullRangeInfo(range, table);
		else
			this.fillRangeInfo(range, table);

		var rect = Rect.elementRect(infoEl);
		div.style.top = (rect.y + 20) + "px";
		div.style.left = (rect.x + 20) + "px";
		div.style.visibility = "visible";
	}
}
ClonePage.prototype.fillFullRangeInfo = function(range, table)
{
	var index = 1;
	for(n=0;n<range.objects.length;n++){
		var row = table.insertRow(index++);
		var cell;
		row.appendChild(cell = $element("td"));
		cell.appendChild($text(range.objects[n].id));
		row.appendChild(cell = $element("td"));
		cell.appendChild($text(range.objects[n].name));
		row.appendChild(cell = $element("td"));
		cell.appendChild($text(range.objects[n].type));
	}
}
ClonePage.prototype.fillRangeInfo = function(range, table)
{
	var index = 1;
	var hitMap = new Object();
	for(n=0;n<range.objects.length;n++){
		var key = range.objects[n].name + "-" + range.objects[n].type;
		if(hitMap[key])
			hitMap[key].count += 1;
		else
			hitMap[key] = {name: range.objects[n].name, type: range.objects[n].type, count:1};
	}
	for(var key in hitMap){
		var row = table.insertRow(index++);
		var cell;
		row.appendChild(cell = $element("td"));
		cell.appendChild($text(hitMap[key].name));
		row.appendChild(cell = $element("td"));
		cell.appendChild($text(hitMap[key].type));
		row.appendChild(cell = $element("td"));
		if(hitMap[key].count > 0)
			cell.appendChild($text("(" + hitMap[key].count + ")"));
	}
}


ClonePage.prototype.showRegionInfo = function(infoEl)
{
	var div = $("range-info");
	var region = infoEl.region;
	if(div && region && region.ranges){
		var table = $("range-info-table");
		var n = table.rows.length;
		while(n-- > 1)
			table.deleteRow(n);
		if(this.showObjectId)
			this.fillFullRegionInfo(region, table);
		else
			this.fillRegionInfo(region, table);
		
		var rect = Rect.elementRect(infoEl);
		div.style.top = (rect.y + 20) + "px";
		div.style.left = (rect.x + 20) + "px";
		div.style.visibility = "visible";
	}
}

ClonePage.prototype.fillFullRegionInfo = function(region, table)
{
	var index = 1;
	var hitMap = new Object();
	for(n=0;n<region.ranges.length;n++){
		if(region.ranges[n].enabled && region.ranges[n].objects)
			for(var k=0;k<region.ranges[n].objects.length;k++)
				hitMap[region.ranges[n].objects[k].id] = region.ranges[n].objects[k];
	}
	for(var key in hitMap){
		var row = table.insertRow(index++);
		var cell;
		row.appendChild(cell = $element("td"));
		cell.appendChild($text(hitMap[key].id));
		row.appendChild(cell = $element("td"));
		cell.appendChild($text(hitMap[key].name));
		row.appendChild(cell = $element("td"));
		cell.appendChild($text(hitMap[key].type));
	}
}
ClonePage.prototype.fillRegionInfo = function(region, table)
{
	var index = 1;
	var hitMap = new Object();
	var hitArray = new Array();
	for(n=0;n<region.ranges.length;n++){
		if(region.ranges[n].enabled && region.ranges[n].objects)
			for(var k=0;k<region.ranges[n].objects.length;k++){
				var key = region.ranges[n].objects[k].name + "-" + region.ranges[n].objects[k].type;
				if(hitMap[key])
					hitMap[key].count += 1;
				else{
					hitMap[key] = {name:region.ranges[n].objects[k].name, type:region.ranges[n].objects[k].type, count:1};
					hitArray.push(hitMap[key]);
				}
			}
	}
	var cmp = function(obj1, obj2){
		return obj1.name < obj2.name? -1 : (obj1.name > obj2.name ? 1 : 0);
	}
	hitArray.sort(cmp);
	for(var n = 0; n < hitArray.length;n++){
		var obj = hitArray[n];
		var row = table.insertRow(index++);
		var cell;
		row.appendChild(cell = $element("td"));
		cell.appendChild($text(obj.name));
		row.appendChild(cell = $element("td"));
		cell.appendChild($text(obj.type));
		row.appendChild(cell = $element("td"));
		cell.appendChild($text("(" + obj.count + ")"));
	}
}

ClonePage.prototype.hideRangeInfo = function()
{
	var div = document.getElementById("range-info");
	if(div)
		div.style.visibility = "hidden";
}

ClonePage.prototype.saveState = function()
{
	if(this.region && this.stateCache){
	var state = {
			asmb:this.region.asmb, 
			chr:this.region.chr, 
			start:this.region.start, 
			end:this.region.end,
			ds:[], 
			lib:[], 
			population:[]
		};
		for(n in this.region.ds){
			if(this.region.ds[n].state)
				state.ds.push(n);
		}
		for(n in this.region.population){
			if(this.region.population[n].state)
				state.population.push(n);
		}
		for(n in this.region.lib){
			if(this.region.lib[n].state)
				state.lib.push(n);
		}
		this.stateCache.value = Ext.util.JSON.encode(state);
	}
}

ClonePage.prototype.restoreState = function()
{
	if(this.stateCache && this.stateCache.value){
		var state = Ext.util.JSON.decode(this.stateCache.value);
		// get region
		var region;
		for(var n=0;n<this.regionRows.length;n++){
			region = this.regionRows[n].region;
			if(state.asmb == region.asmb && state.chr == region.chr && state.start >= region.start && state.end <= region.end)
				break;
		}
		if(n < this.regionRows.length){
			var regionRow = this.regionRows[n];
			this.selectRegion(regionRow);
			// select ranges
			if(region.ranges && region.ranges.length > 1){
				for(var k=1;k<regionRow.rangeRows.length;k++){
					var rangeRow = regionRow.rangeRows[k];
					var range = rangeRow.info.range;
					if(range.start != null && range.start < state.start || range.end != null && range.end > state.end){
						rangeRow.chbx.checked = false;
						range.enabled = false;
					}
				}
				this.updateRegion({regionRow:regionRow, region:region});
			}
			// select datasets
			var set = {};
			for(var k=0;k<state.ds.length;k++)
				set[state.ds[k]] = true;
			var cells = this.dataSetContainer.cells;
			for(var k=0;k<cells.length;k++){
				var cell = cells[k];
				var uid = cell.getAttribute("uid");
				this.dataSetContainer.setCellEnabled(cell, set[uid]);
			}
			
			// select DNA sources
			if(state.dnasrc){
			
			}
			
			// select population
			set = {};
			for(var k=0;k<state.population.length;k++)
				set[state.population[k]] = true;
			var cells = this.populationContainer.cells;
			for(var k=0;k<cells.length;k++){
				var cell = cells[k];
				var uid = cell.getAttribute("uid");
				this.populationContainer.setCellEnabled(cell, set[uid]);
			}
			
			//select libraries
			set = {};
			for(var k=0;k<state.lib.length;k++)
				set[state.lib[k]] = true;
			var cells = this.libraryContainer.cells;
			for(var k=0;k<cells.length;k++){
				var cell = cells[k];
				var uid = cell.getAttribute("uid");
				this.libraryContainer.setCellEnabled(cell, set[uid]);
			}
			
			
		}
	}
}

function showLibInfo(eventObj, cell, flag)
{
	window.controller.showLibInfo(eventObj, cell, flag);
}

function enableAllRanges(sender, flag)
{
	window.controller.enableAllRanges(sender, flag);
}
