//
// DEPENDENCY CHECKING:
//
if(typeof GLADIATOR_REQUEST_INCLUDED == 'undefined') alert('NOTE BENE: "gladiatorAssist.js" REQUIRES "gladiatorRequest.js"!');
if(typeof GLADIATOR_WINDOWS_INCLUDED == 'undefined') alert('NOTE BENE: "gladiatorAssist.js" REQUIRES "gladiatorWindows.js"!');
if(typeof GLADIATOR_TABLE_EDITOR_INCLUDED == 'undefined') alert('NOTE BENE: "gladiatorAssist.js" REQUIRES "gladiatorTableEditor.js"!');

var GLADIATOR_PEDIGREE_INCLUDED=true;


//
// gPedigreeToolBar
//
// id: gPedigreeToolBar container id
// parentNode: parent of the gAssist container
//
function gPedigreeToolBar(id,left,top,width,height){
	
	//
	// Private variables:
	//
	var _id;
	if(id) _id = id; 
	else _id = "myToolBar";
	
	var _left;
	if(left) _left = left;
	else _left = 15;
	
	var _top;
	if(top) _top = top;
	else _top = 125;
	
	var _width;
	if(width) _width = width;
	else _width = 160;
	
	var _height;
	if(height) _height = height;
	else _height = 220;
	
	var _self=this;
	
	// User Toolbar Menu:
	var _dataSubMenu = new gMenu("Data Formats","datasubmenu",300,50,150,false,true);
	_dataSubMenu.addItem("Tab Delimited","tab",null,false,false,false);
	_dataSubMenu.addItem("Madeline Flat","madeline",null,false,false,false);
	_dataSubMenu.addItem("Madeline XML","madelinexml",null,false,false,false);
	
	var _toolbar = new gMenu("Toolbar","tbmenu",_left,_top,_width,true,false);
	_toolbar.addItem("Add Spouse","spouse",null,false,false,false);
	_toolbar.addItem("Add Siblings","sibling",null,false,true,false);
	_toolbar.addItem("Add Children","children",null,false,true,false);
	_toolbar.addItem("Add Founding Group","founders",null,false,false,false);
	_toolbar.addItem("Delete","delete",null,false,false,false);
	_toolbar.addItem("Save online","save",null,false,true,false);
	_toolbar.addItem("Save data as","savedata",_dataSubMenu,true,true,false);
	_toolbar.addItem("Save SVG as","savesvg",null,false,true,false);
	_toolbar.addItem("Print SVG","printsvg",null,false,true,false);
	
	// User Input Section:
	var _userInputSection = document.createElementNS(NS.xhtml,"div");
	_userInputSection.id = "uis";
	
	var _childrenLabel = new gDivider("Number of Children","label1",_userInputSection);
	var _siblingLabel = new gDivider("Number of Siblings","label2",_userInputSection);
	_siblingLabel.hide();
	_childrenLabel.hide();
	
	var _males = new gSpin("# of Males","males",0,1,-1,0,16,20,_userInputSection);
	var _females = new gSpin("# of Females","females",0,1,-1,0,16,20,_userInputSection);
	var _unknown = new gSpin("# Unknown","unknown",0,1,-1,0,16,20,_userInputSection);
	var _nochildren = new gCheckBox("No Children","nochildren",_userInputSection);
	var _draw = new gFormButton("Draw","draw",_userInputSection);
	var _uisWin = new gWindow("Input","uisw",_left,_top+260,285,275,_userInputSection,false);
	_uisWin.allowMinMax(false);
	_uisWin.allowIconify(false);
	_uisWin.allowResize(false);
	
	///////////////////////////////////////////////
	//
	// Public Functions:
	//
	///////////////////////////////////////////////
	
	this.showUserInputSection = function(siblingFlag,spouseFlag){
		_uisWin.show(true);
		_uisWin.bringToTop("uisw");
		if(siblingFlag){
			_siblingLabel.show();
			_childrenLabel.hide();
			_nochildren.hide();
		}else{
			_childrenLabel.show();
			_siblingLabel.hide();
			_nochildren.hide();
			if(spouseFlag){
				_nochildren.show();
				_nochildren.reset();
			}
		}
	}
	
	this.hideUserInputSection = function(){
		
		_uisWin.show(false);
		
	}
	
	this.hide = function(){
		_toolbar.hide();
	}
	
	this.show = function(){
		_toolbar.show();
	}
	
	
	this.setMenuItemAction = function(id,action){
		
		_toolbar.addItemAction(id,action);
		
	}
	
	this.setDataSubMenuItemAction = function(id,action){
		
		_dataSubMenu.addItemAction(id,action);
		
	}
	
	this.setDrawHandler = function(eventName,functionHandler){
		_draw.addEventListener(eventName,functionHandler);
	}
	
	
	this.resetSpinValues = function(){
		
		_males.resetValue();
		_females.resetValue();
		_unknown.resetValue();
		
	}
	
	this.updateDisplay = function(currentMatingFlag,currentIndividualFlag,isOrdinaryFounder,isOriginalFounder,genderUnknown){
		
		if(currentMatingFlag){
			_toolbar.disableItem("spouse");
			_toolbar.disableItem("sibling");
			_toolbar.disableItem("founders");
			_toolbar.enableItem("children");
			_toolbar.enableItem("delete");
			
		}else if(currentIndividualFlag){
			
			if(!isOrdinaryFounder && !isOriginalFounder && !genderUnknown){
				_toolbar.enableItem("spouse");
				_toolbar.enableItem("sibling");
			}else{
				_toolbar.disableItem("spouse");
				_toolbar.disableItem("sibling");
				if(isOriginalFounder) _toolbar.enableItem("spouse");
			}
			_toolbar.disableItem("founders");
			_toolbar.disableItem("children");
			_toolbar.enableItem("delete");
			
		}else{
			_toolbar.disableItem("spouse");
			_toolbar.disableItem("sibling");
			_toolbar.disableItem("children");
			_toolbar.enableItem("founders");
			_toolbar.disableItem("delete");
		}
	}
	
	this.enableSave = function(){
		_toolbar.enableItem("save");
	
	}
	
	this.disableSave = function(){
		_toolbar.disableItem("save");
	}
	
	this.enableDownload = function(){
		_toolbar.enableItem("savedata");
		_toolbar.enableItem("savesvg");
		_toolbar.enableItem("printsvg");
	}
	
	this.disableDownload = function(){
		_toolbar.disableItem("savedata");
		_toolbar.disableItem("savesvg");
		_toolbar.disableItem("printsvg");
	}
	
}

//
// gRegisterSection:
//
function gRegisterSection(id){
	
	// User Input Section:
	var _registerSection = document.createElementNS(NS.xhtml,"div");
	_registerSection.id = id;
	var _self = this;
	var _emailInput = new gText("Email","email",_registerSection);
	var _passwordInput = new gPassword("Password","password",_registerSection);
	var _givenNameInput = new gText("Given Name","given_name",_registerSection);
	var _familyNameInput = new gText("Family Name","family_name",_registerSection);
	var _onMailingList = new gCheckBox("On Mailing List","on_mailing_list",_registerSection);
	var _departmentInput = new gText("Department","department",_registerSection);
	var _instituteInput    = new gText("Institute","institute",_registerSection);
	var _register = new gFormButton("Register","register",_registerSection);
	var _regWin = new gWindow("User Registration","regw",0,100,300,425,_registerSection,true);
	_regWin.allowMinMax(false);
	_regWin.allowIconify(false);
	
	this.hide = function(){
		_regWin.show(false);
	}
	
	this.show = function(){
		_regWin.show(true);
	}
	
	this.setRegisterHandler = function(eventName,functionHandler){
		_register.addEventListener(eventName,functionHandler);
	}
	
	this.getQueryStringParameters = function(){
		
		if(!_self.validateUserName()) return "";
		if(!_self.validatePassword()) return "";
		var queryString = 'r=' + _emailInput.getValue()+","+_passwordInput.getValue()+","+_onMailingList.isChecked()+","+_givenNameInput.getValue()+","+_familyNameInput.getValue()+","+_departmentInput.getValue()+","+_instituteInput.getValue();
		return queryString;
		
	}
	
	this.validateUserName = function(){
		
		if(_emailInput.getValue() == ""){
			alert("Enter a valid email address");
			return false;
		}
		if (/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(_emailInput.getValue())){
			return true;
		}else alert("Invalid email address");
		return true;
	}
	
	this.validatePassword = function(){
		
		if(_passwordInput.getValue() == "" || _passwordInput.getValue().length < 4){
			alert("Password should be atleast 4 characters long");
			return false;
		}
		return true;
	}
	
	_emailInput.addEventListener("change",_self.validateUserName);
	_passwordInput.addEventListener("change",_self.validatePassword);
}

//
// gIndividual:
//
function gIndividual(){
	
	this.node=false;
	this.isAffected=false;
	
}

//
// vIndividualParents:
//
function vIndividualParents(fatherId,motherId){
	
	this.fatherId = fatherId;
	this.motherId = motherId;
	
}



//
// gPedigreeManager:
//
function gPedigreeManager(svgContainer,scrollableTable,gte,URL,svgNodeId,gridFieldsOrder,hasDemo){
	
	
	// Explicitly  initialize the window dimesions for browsers like Opera:
	DIMENSIONS.init();
	
	// Ids of selected individuals
	var _currentIndividual="";
	var _currentFather="";
	var _currentMother="";
	
	// Parameters retrieved from the database
	var _unsampledCount=100;
	var _sampledPrefix='';
	var _unsampledPrefix='';
	var _familyPrefix='';
	var _familyId;
	
	// Drawing flags
	var _addChildrenFlag=false;
	var _addSpouseFlag=false;
	var _addSiblingFlag=false;
	var _addFounderFlag=false;
	
	
	// Pedigree Toolbar:
	var _toolBarLeft  = 20;
	var _toolBarTop   = 152;
	var _toolBarWidth = 202;

	var _myToolBar = new gPedigreeToolBar("tb1",_toolBarLeft,_toolBarTop,_toolBarWidth);
	_myToolBar.hideUserInputSection();
	
	var _registerSection = new gRegisterSection("regs");
	_registerSection.hide();
	
	// Selected individual objects
	var _selectedIndividual = new gIndividual();
	var _selectedMother  = new gIndividual();
	var _selectedFather  = new gIndividual();
	
	// Core column indices are required for adding/updating rows
	// set based on gridFieldsOrder
	var _familyIndex;
	var _individualIndex;
	var _genderIndex;
	var _fatherIndex;
	var _motherIndex;
	
	// loggedIn boolean:
	_loggedIn = false;
	
	// gRequest object:
	var _grequest;
	
	var _grid = scrollableTable.getNode(); // table node
	var _rowTemplateNode; // table row template node 
	
	var _self = this;
	
	var _svgDrawingNode; // holds the current svg node
	var _minimumRows = 1; // one header row
	
	var _parentsOfVirtualChild = new Object(); // array of parent pair objects (vIndividualParents) who have no children
	var _showToolBar; // flag to show the toolbar when the page is reloaded
	
	// Save indicator
	var _hasBeenTouched = false; 
	
	// New pedigree loaded indicator
	var _newPedigree=false;
	var _trackDeleted=false; // track individuals who have been deleted from saved pedigrees
	var _deletedIndividuals="";
	
	// OriginalFounders:
	var _originalFounders = new Array();
	
	//
	// User Interface Sections:
	//
	
	// Sample Pedigrees section:
	var _peds;
	var _isExample = false;
	
	// Edit Pedigrees section:
	var _loginStatus;
	var _familyInput;
	var _unsampledPrefixInput;
	var _retrieve;
	// Viewing saved pedigrees section:
	var _viewSaved;
	var _viewContainer = document.createElementNS(NS.xhtml,"div");
	_viewContainer.id="viewContent";
	// Window for viewing saved pedigree ids:
	var _viewWin = new gWindow("Saved Pedigrees","viewWin",20,12,288,300,_viewContainer);
	_viewWin.allowResize(false);
	_viewWin.allowMinMax(false);
	_viewWin.show(false);
	
	// Login/Logout section:
	var _loginWidget;
	var _loginButton;
	
	//
	// Calculate available width and height for svg and grid windows:
	// 
	var winLeft  = _toolBarWidth + _toolBarLeft;
	var winTop   = 12;
	var winWidth = DIMENSIONS.width - _toolBarWidth - _toolBarLeft -2 ;
	var winHeight= 0.5*(DIMENSIONS.height - winTop - 2 );
	var winTop2  = winTop+winHeight;
	
	
	// Window for svg drawing:
	var _svgWin = new gWindow("Pedigree Drawing","svgWin",winLeft,winTop,winWidth,winHeight,svgContainer);
	_svgWin.allowClose(false);
	_svgWin.show(false);
	
	// Window for grid:
	var _tableWin = new gWindow("Pedigree Data Table","gridWin",winLeft,winTop2,winWidth,winHeight,scrollableTable.getBaseNode());
	
	_tableWin.allowClose(false);
	_tableWin.show(false);
	
	//
	// Wait indicator to use with AJAX requests:
	//
	var _waitIndicator = new gWaitIndicator();
	_waitIndicator.setPosition(250,50);
	//_waitIndicator.setPosition(POSITION.center,POSITION.center);
	
	// Browser window manager:
	var _browserWindowManager = new browserWindowManager();
	
	// Main Window:
	var _mainWin;
	var _mtc; // main tab container
	_createMainWindow();
	
	///////////////////////////////////////////////
	//
	// Private Functions:
	//
	///////////////////////////////////////////////
	
	//
	// Interface Functions:
	//
	
	//
	// _createMainWindow:
	//
	function _createMainWindow(){
		
		_mtc = new gTabContainer("mtc",220,20,"top",null);
		if(hasDemo) _mtc.addTab("Sample Pedigrees",false);
		_mtc.addTab("Create & Edit Pedigrees",false);
		_mtc.addTab("Login & Logout",false);
		var selectTab=1;
		_mtc.finish(selectTab); 
		//
		// Window: mainWindow 
		//
		_mainWin = new gWindow("Madeline 2.0 PDE","mainWin",225,205,845,400,_mtc.getNode());
		_mainWin.allowClose(false);
		//
		// Get the tab canvas nodes:
		//
		var samplesNode = _mtc.getTabNode(1);
		var editorNode  = _mtc.getTabNode(2);
		var loginNode   = _mtc.getTabNode(3);
		//
		// Add the content to the tab nodes:
		//
		if(hasDemo) _createSamplePedigreesSection(samplesNode);
		_createEditPedigreesSection(editorNode);
		_createLoginSection(loginNode);
		
	}
	
	//
	// _createSamplePedigreesSection:
	//
	function _createSamplePedigreesSection(insertionNode){
		
		var sec01 = new gDivider("Pedigree Examples","pe",insertionNode);
		_peds = new gDropDown("Select Pedigree","peds",insertionNode);
		_peds.addSelection(".",".");
		_peds.addSelection("si_001","Simple 001");
		_peds.addSelection("si_004","Simple 004");
		_peds.addSelection("tw_002","Twin 002");
		_peds.addSelection("cs_002","Consanguinity 002");
		_peds.addSelection("cs_010","Consanguinity 010");
		_peds.addSelection("ms_001","Multiple Spouse 001");
		_peds.addSelection("dt_002","Descent Tree 002");
		_peds.addSelection("ic_002","Icon Shading 002");
		_peds.addSelection("cs_ms_003","CS + MS 003");
		_peds.addSelection("cx_001","Complex 001");
		_peds.addSelection("cx_002","Complex 002");
		
		
	}
	
	//
	// _createEditPedigreesSection:
	//
	function _createEditPedigreesSection(insertionNode){
		
		// node to display login status:
		_loginStatus=document.createElementNS(NS.xhtml,"p");
		_loginStatus.setAttributeNS(null,"class","loggedIn");
		insertionNode.appendChild(_loginStatus);
		var sec01 = new gDivider("Retrieve Saved Pedigrees","rsp",insertionNode);
		var viewSavedMethod = false;
		_viewSaved            = new gSVGFormButton("View Saved Pedigrees","view",viewSavedMethod,insertionNode);
		_viewSaved.disable();
		
		var sec02 = new gDivider("Create & Edit Pedigrees","ce",insertionNode);
		_familyInput          = new gText("FamilyId"       ,"family_id"       ,insertionNode);
		_unsampledPrefixInput = new gText("UnsampledPrefix","unsampled_prefix",insertionNode);
		var retrieveMethod = false;
		_retrieve             = new gSVGFormButton("Go","retrieve",retrieveMethod,insertionNode);
		
		var sec03 = new gDivider("Upload a Madeline2 supported file format (tab-delimited,xml,xhtml,ods) ","ged",insertionNode);
		var sec03a = new gDivider("The uploaded filename prefix before '.' will be assumed to be the FamilyId (Read FAQ)","geda",insertionNode);
		var _fileUpload = new gFileUpload("gedfile","","post",insertionNode);
	
	}
	
	
	//
	// _createLoginSection:
	//
	function _createLoginSection(insertionNode){
		
		var sec01 = new gDivider("Login & Logout","lg",insertionNode);
		var loginMethod = false;
		//_loginButton = new gSVGFormButton("Login","loginButton",loginMethod,insertionNode);
		_loginButton = new gFormButton("Login","loginButton",insertionNode);
		
	}
	
	//
	// _createLoginWidget:
	//
	function _createLoginWidget(){
		
		var URL = "login.php";
		_loginWidget = new gSVGLoginComponent(URL,_self.setLoggedIn,false,_self.registerHandler);
		_loginWidget.setPosition(POSITION.center,POSITION.top);
		_loginWidget.show(false);
		
	}
	
	//
	// Pedigree Drawing Functions:
	//
	
	//
	// _createRowTemplateNode:
	//
	function _createRowTemplateNode(){
		
		if(!gridFieldsOrder){
			alert("Please specify the order of the columns in the grid.");
			return false;
		}
		
		var coreColumnCount = 5; // Family, Individual,Gender,Father and Mother
		if(gridFieldsOrder.length < 5){
			alert("The core grid columns are missing. Please specify the order of the columns in the grid.");
			return false;
		}
		_rowTemplateNode = document.createElementNS(NS.xhtml,"tr");
		for(var i=0;i<gridFieldsOrder.length;i++){
			var td = document.createElementNS(NS.xhtml,"td");
			td.appendChild(document.createTextNode("."));
			_rowTemplateNode.appendChild(td);
			
		}
		// Convert all the grid fields to upper case:
		var tempArray = new Array();
		for(var i=0;i<gridFieldsOrder.length;i++)
			tempArray[i] = gridFieldsOrder[i].toUpperCase();
		
		// Assign the indices of core columns and set classes on tds for updating the pedigree drawing:
		// NOTE: class 'redraw' sends the grid data back to the server to redraw the pedigree with updated information 
		// class 'bubble' causes all the rows of the grid to be updated with the new value and the pedigree is redrawn:  
		var index=-1;
		index = tempArray.indexOf('FAMILYID');
		if(index != -1) _familyIndex = index;
		else{
			alert("Core column Family Id not found in the grid");
			return false;
		}
		var tdElements = _rowTemplateNode.getElementsByTagName("td");
		index = tempArray.indexOf('INDIVIDUALID');
		if(index != -1) _individualIndex = index;
		else{
			alert("Core column Individual Id not found in the grid");
			return false;
		}
		tdElements[index].setAttributeNS(null,"class","bubble");
		index = tempArray.indexOf('GENDER');
		if(index != -1) _genderIndex = index;
		else{ 
			alert("Core column Gender not found in the grid");
			return false;
		}
		tdElements[index].setAttributeNS(null,"class","redraw");
		index = tempArray.indexOf('FATHER');
		if(index != -1) _fatherIndex = index;
		else{
			alert("Core column Father not found in the grid");
			return false;
		}
		tdElements[index].setAttributeNS(null,"class","bubble");
		index = tempArray.indexOf('MOTHER');
		if(index != -1) _motherIndex = index;
		else{
			alert("Core column Mother not found in the grid");
			return false;
		}
		tdElements[index].setAttributeNS(null,"class","bubble");
		index = tempArray.indexOf('DECEASED');
		if(index != -1) tdElements[index].setAttributeNS(null,"class","redraw");
		index = tempArray.indexOf('PROBAND');
		if(index != -1) tdElements[index].setAttributeNS(null,"class","redraw");
		index = tempArray.indexOf('MZTWIN');
		if(index != -1) tdElements[index].setAttributeNS(null,"class","redraw");
		index = tempArray.indexOf('DZTWIN');
		if(index != -1) tdElements[index].setAttributeNS(null,"class","redraw");
		index = tempArray.indexOf('AFFECTED');
		if(index != -1) tdElements[index].setAttributeNS(null,"class","redraw");
		index = tempArray.indexOf('SAMPLED');
		if(index != -1) tdElements[index].setAttributeNS(null,"class","redraw");
		
		return true;
		
	}
	
	//
	// _getNextId: formats the next unsampled id
	//
	function _getNextId(){
		
		var strTemplate="00000";
		var formatId;
		var unsampledString = _unsampledCount+"";
		formatId = strTemplate.substring(0,strTemplate.length-unsampledString.length)+_unsampledCount;
		_unsampledCount++;
		return _unsampledPrefix+formatId;
		
	}
	
	//
	// _resetFlags:
	//
	function _resetFlags(){
		_addChildrenFlag = _addSpouseFlag = _addSiblingFlag = _addFounderFlag = false;
	}
	
	//
	// _setPreviousState: this function is requried since Ajax is used to upload the entire pedigree
	// into the svg container. If the user had previously selected 
	//
	function _setPreviousState(){
		if(_currentIndividual){
			_selectIndividual(_selectedIndividual,document.getElementById(_currentIndividual));
		}
	}
	
	//
	// _resetDrawingParameters: reset on every new family request
	//
	function _resetDrawingParameters(){
		
		_familyId="";
		_currentIndividual = _currentMother = _currentFather = "";
		_deletedIndividuals="";
	}
	
	//
	// _showPedigreeWindows(){
	//
	function _showPedigreeWindows(){
		_svgWin.show(true);
		_tableWin.show(true);
	}
	
	//
	// _hidePedigreeWindows:
	//
	function _hidePedigreeWindows(){
		_svgWin.show(false);
		_tableWin.show(false);
	}
	
	//
	// _logout:
	//
	function _logout(){
		
		//console.log("_logout called");
		
		_loggedIn = false;
		_loginButton.changeLabel("Login");
		_loginWidget.reset();
		_loginWidget.show(false);
		_myToolBar.disableSave();
		
		//
		// remove logged in status
		//_loginStatus.removeChild(_loginStatus.firstChild);
		// reset the window canvas class
		//_mainWin.getCanvas().setAttribute("class","windowCanvas");
		_mainWin.setTitleNodeIconTrayClass("","iconTray");
		_mainWin.setTitle("Madeline 2.0 PDE ");
		_viewSaved.disable();
		_viewWin.show(false);
		
		//
		// abort the ongoing request
		//
		//_grequest.abort();
		//_grequest.setQueryTermsString('li='+1);
		//_grequest.load();
		
		////////////////////////////////////////////////////////////
		//
		// Load the "logged out page":
		//
		// This is the quickest and cheapest way to remove
		// all the visible application data from the screen ...
		//
		////////////////////////////////////////////////////////////
		window.location="loggedout.php"
		
	}
	
	//
	// _addRow: add a single row to the grid
	//
	function _addRow(gender,father,mother,whichId,virtualFlag){
		
		var cloneRow = _rowTemplateNode.cloneNode(true);
		var tdNodes = cloneRow.getElementsByTagName("td");
		tdNodes[_familyIndex].firstChild.nodeValue = _familyId;
		var nextId = _getNextId();
		cloneRow.id="r"+nextId;
		tdNodes[_individualIndex].firstChild.nodeValue = nextId;
		tdNodes[_genderIndex].firstChild.nodeValue = gender;
		tdNodes[_fatherIndex].firstChild.nodeValue = father;
		tdNodes[_motherIndex].firstChild.nodeValue = mother;
		if(virtualFlag){
			
			// Virtual individual added
			cloneRow.setAttributeNS(null,"class","hiddenRow");
			//cloneRow.style.display="none";
			tdNodes[_individualIndex].firstChild.nodeValue = "^"+nextId;
		}
		scrollableTable.addRow(cloneRow);
		if(whichId) return nextId;
		
	}
	
	//
	// _addRowsToGrid:
	//
	function _addRowsToGrid(numberOfMales,numberOfFemales,numberUnknown){
		
		for(var i=0;i<numberOfMales;i++)
			_addRow("M",_currentFather,_currentMother);
		for(var i=0;i<numberOfFemales;i++)
			_addRow("F",_currentFather,_currentMother);
		for(var i=0;i<numberUnknown;i++)
			_addRow(".",_currentFather,_currentMother);
		
	}
	
	//
	// _populateRow: parse the data received from the database onto the grid.
	//
	function _populateRow(row){
		
		var cloneRow = _rowTemplateNode.cloneNode(true);
		var tdNodes = cloneRow.getElementsByTagName("td");
		var tdValues = row.getElementsByTagName("d");
		cloneRow.id = "r"+tdValues[_individualIndex].firstChild.nodeValue;
		var numberOfColumns = _grid.getElementsByTagName("th").length;
		var count = (tdValues.length > numberOfColumns) ? numberOfColumns : tdValues.length;
		for(var i=0;i<count;i++){
			tdNodes[i].firstChild.nodeValue = tdValues[i].firstChild.nodeValue;
		}
		// Check if there is a virtual individual:
		if(tdValues[_individualIndex].firstChild.nodeValue[0] == '^'){
			
			// Update the virtual Individual array:
			var virtualId = tdValues[_individualIndex].firstChild.nodeValue;
			var fatherId = tdValues[_fatherIndex].firstChild.nodeValue;
			var motherId = tdValues[_motherIndex].firstChild.nodeValue;
			_parentsOfVirtualChild[virtualId] = new vIndividualParents(fatherId,motherId);
			tdNodes[_individualIndex].firstChild.nodeValue = virtualId;
			// Hide the virtual individual row
			//cloneRow.style.display="none";
			cloneRow.setAttributeNS(null,"class","hiddenRow");
		}
		scrollableTable.addRow(cloneRow);
	}
	
	//
	// _deleteAnyVirtualChild: is used to delete the virtual child
	// added to parents with no children for drawing purposes if the 
	// user decides to add children to that couple:
	//
	function _deleteAnyVirtualChild(){
		
		var virtualId;
		for(var i in _parentsOfVirtualChild){
			if(_parentsOfVirtualChild[i].motherId == _currentMother && _parentsOfVirtualChild[i].fatherId == _currentFather){
				var trId = "r"+i;
				virtualId = i;
				scrollableTable.deleteRow(trId);
				break;
			}
		}
		delete _parentsOfVirtualChild[virtualId];
		
	}
	
	//
	// _markSubtree: used by delete to mark all the nodes of the subtree under a selected delete node:
	//
	function _markSubtree(individualId,deleteIndividuals,deleteSpouses,index,spouseIndex){
		
		var startSpouseIndex = spouseIndex;
		var trElements = _grid.getElementsByTagName("tr");
		for(var i=1;i<trElements.length;i++){
			var tdElements = trElements[i].getElementsByTagName("td");
			if(trElements[i].id == "r"+individualId) continue;
			if(tdElements[_fatherIndex].firstChild.nodeValue == individualId || tdElements[_motherIndex].firstChild.nodeValue == individualId){
				// Save the id 
				deleteIndividuals[index++] = trElements[i].id;
				// Store the spouse too
				if(tdElements[_fatherIndex].firstChild.nodeValue != individualId){
					
					deleteSpouses[spouseIndex++] = "r"+tdElements[_fatherInex].firstChild.nodeValue;
					
				}else deleteSpouses[spouseIndex++] = "r"+tdElements[_motherIndex].firstChild.nodeValue;
				
			}
			if(spouseIndex != startSpouseIndex){
				// spouses were added -- remove duplicate entries
				for(var k=startSpouseIndex;k<spouseIndex;k++){
					if(deleteSpouses[k] == undefined) continue;
					while(deleteSpouses.indexOf(deleteSpouses[k]) != deleteSpouses.lastIndexOf(deleteSpouses[k])){
						delete deleteSpouses[deleteSpouses.lastIndexOf(deleteSpouses[k])];
					}
				}
			}
		}
		return index;
	}
	
	// 
	// _spouseHasMultipleMatings: Checks if the spouse has multiple matings:
	//
	function _spouseHasMultipleMatings(spouseId,currentId,spouseIndex,individualIndex){
		
		var trElements = _grid.getElementsByTagName("tr");
		for(var i=1;i<trElements.length;i++){
			var tdElements = trElements[i].getElementsByTagName("td");
			if(tdElements[spouseIndex].firstChild.nodeValue == spouseId){
				if(tdElements[individualIndex].firstChild.nodeValue != currentId)
					return true;
			}
		}
		return false;
	}
	
	//
	// _determineOriginalFounders:
	//
	function _determineOriginalFounders(){
		
		
		var ordinaryFounders = new Array();
		var index=0;
		var trElements = _grid.getElementsByTagName("tr");
		for(var i=1;i<trElements.length;i++){
			if(_isOrdinaryFounder(trElements[i].id.substring(1)))
				ordinaryFounders[index++] = trElements[i].id;
		}
		var ordinaryFoundersCount = ordinaryFounders.length;
		index = 0;
		var count=0;
		while(index < ordinaryFoundersCount){
			trElements = _grid.getElementsByTagName("tr");
			for(var i=1;i<trElements.length;i++){
				var tdElements = trElements[i].getElementsByTagName("td");
				if(trElements[i].id == ordinaryFounders[index]) continue;
				if(tdElements[_fatherIndex].firstChild.nodeValue == ordinaryFounders[index].substring(1) || tdElements[_motherIndex].firstChild.nodeValue == ordinaryFounders[index].substring(1)){
					// Check if the spouse is a ordinary founder also
					if(tdElements[_fatherIndex].firstChild.nodeValue != ordinaryFounders[index].substring(1)){
						var spouseId =  "r"+tdElements[_fatherIndex].firstChild.nodeValue;
						if(ordinaryFounders.indexOf(spouseId) != -1){
							if(_originalFounders.length){
								if(_originalFounders.indexOf(spouseId) == -1) _originalFounders[count++] = spouseId;
							}else _originalFounders[count++] = spouseId;
						}
					}else if(tdElements[_motherIndex].firstChild.nodeValue != ordinaryFounders[index].substring(1)){
						var spouseId = "r"+tdElements[_motherIndex].firstChild.nodeValue;
						if(ordinaryFounders.indexOf(spouseId) != -1){
							if(_originalFounders.length){
								if(_originalFounders.indexOf(spouseId) == -1) _originalFounders[count++] = spouseId;
							}else _originalFounders[count++] = spouseId;
						}
					}
				}
			}
			index++;
		}
		
		// Delete previous original founders:
		while(_originalFounders.length > count){
			_originalFounders.pop();
		}
		// DEBUG:
		//for(var k=0;k<_originalFounders.length;k++)
		//alert("ORG"+_originalFounders[k]);
		
	}
	
	//
	// _isOrdinaryFounder:
	//
	function _isOrdinaryFounder(individualId){
		
		var trId = "r"+individualId;
		var tdElements = document.getElementById(trId).getElementsByTagName("td");
		if(tdElements[_fatherIndex].firstChild.nodeValue == "." && tdElements[_motherIndex].firstChild.nodeValue == ".") return true;
		return false;
		
	}
	
	//
	// _hasSingleChild: checks if the parent has a single child:
	//
	function _hasSingleChild(parentId,parentIndex){
		
		var count=0;
		var trElements = _grid.getElementsByTagName("tr");
		for(var i=1;i<trElements.length;i++){
			var tdElements = trElements[i].getElementsByTagName("td");
			if(tdElements[parentIndex].firstChild.nodeValue == parentId){
				count++;
				if(count > 1) return false;
			}
		}
		return true;
		
	}
	
	//
	// _delete:
	//
	function _delete(){
		
		var index=0,spouseIndex=0;
		var deleteIndividuals = new Array();
		var deleteSpouses = new Array();
		var deleteIndices = new Array();
		var trElements = _grid.getElementsByTagName("tr");
		
		for(var i=1;i<trElements.length;i++){
			var tdElements = trElements[i].getElementsByTagName("td");
			
			if(_currentMother && _currentFather){
				if(trElements[i].id == "r"+_currentFather || trElements[i].id == "r"+_currentMother){
					continue;
				}
				if(tdElements[_fatherIndex].firstChild.nodeValue == _currentFather && tdElements[_motherIndex].firstChild.nodeValue == _currentMother){
					// Save the id 
					deleteIndividuals[index++] = trElements[i].id;
				}
			}else if(tdElements[_fatherIndex].firstChild.nodeValue == _currentIndividual || tdElements[_motherIndex].firstChild.nodeValue == _currentIndividual){
				
				// Save the id 
				deleteIndividuals[index++] = trElements[i].id;
				// Save the spouse id:
				if(tdElements[_fatherIndex].firstChild.nodeValue == _currentIndividual){
					if(_spouseHasMultipleMatings(tdElements[_motherIndex].firstChild.nodeValue,_currentIndividual,_motherIndex,_fatherIndex));
					else if(_isOrdinaryFounder(tdElements[_motherIndex].firstChild.nodeValue)){
						deleteSpouses[spouseIndex++] = "r"+tdElements[_motherIndex].firstChild.nodeValue;
					}
				}else{
					
					if(_spouseHasMultipleMatings(tdElements[_fatherIndex].firstChild.nodeValue,_currentIndividual,_fatherIndex,_motherIndex));
					else if(_isOrdinaryFounder(tdElements[_fatherIndex].firstChild.nodeValue)){
						deleteSpouses[spouseIndex++] = "r"+tdElements[_fatherIndex].firstChild.nodeValue;
					}
				}
			}
		}
		
		if(spouseIndex != 0){
			// spouses were added -- remove duplicate entries
			for(var k=0;k<spouseIndex;k++){
				if(deleteSpouses[k] == undefined) continue;
				while(deleteSpouses.indexOf(deleteSpouses[k]) != deleteSpouses.lastIndexOf(deleteSpouses[k])){
					delete deleteSpouses[deleteSpouses.lastIndexOf(deleteSpouses[k])];
				}
			}
		}
		var currentIndex = 0;
		while(currentIndex != index){
			// Loop through this list of delete individuals
			var tempId = deleteIndividuals[currentIndex].substr(1);
			index = _markSubtree(tempId,deleteIndividuals,deleteSpouses,index,deleteSpouses.length);
			currentIndex++;
		}
		// Delete the rows
		for(var k=0;k<deleteIndividuals.length;k++){
			scrollableTable.deleteRow(deleteIndividuals[k]);
			if(_trackDeleted) _deletedIndividuals +=  "," + deleteIndividuals[k].substr(1);
		}
		// DEBUG:
		//for(var k=0;k<deleteIndividuals.length;k++)
		//alert(deleteIndividuals[k]);
		//alert(" Spouses"+deleteSpouses.length);
		for(var k=0;k<deleteSpouses.length;k++){
			if(deleteSpouses[k] == undefined) continue;
			scrollableTable.deleteRow(deleteSpouses[k]);
			if(_trackDeleted) _deletedIndividuals +=  "," + deleteSpouses[k].substr(1);
			//alert(deleteSpouses[k]);
		}
		
		if(_currentIndividual) {
			var trId = "r"+_currentIndividual;
			// Determine if the parent, an ordinary founder should be deleted
			var tdFather = document.getElementById(trId).getElementsByTagName("td").item(_fatherIndex).firstChild.nodeValue;
			var tdMother = document.getElementById(trId).getElementsByTagName("td").item(_motherIndex).firstChild.nodeValue;
			var trFather = "r"+tdFather;
			var trMother = "r"+tdMother;
			if(document.getElementById(trFather) && _isOrdinaryFounder(tdFather) && _hasSingleChild(tdFather,_fatherIndex)){
				scrollableTable.deleteRow(trFather);
				if(_trackDeleted) _deletedIndividuals += "," + tdFather;
			}
			if(document.getElementById(trMother) && _isOrdinaryFounder(tdMother) && _hasSingleChild(tdMother,_motherIndex)){
				scrollableTable.deleteRow(trMother);
				if(_trackDeleted) _deletedIndividuals += "," + tdMother;
			}
			scrollableTable.deleteRow(trId);
			if(_trackDeleted) _deletedIndividuals += "," + _currentIndividual;
		}else{
			var trId = "r"+_currentMother;
			if(_spouseHasMultipleMatings(_currentMother,_currentFather,_motherIndex,_fatherIndex));
			else{
				scrollableTable.deleteRow(trId); 
				if(_trackDeleted) _deletedIndividuals += "," + _currentMother;
			}
			trId = "r"+_currentFather;
			if(_spouseHasMultipleMatings(_currentFather,_currentMother,_fatherIndex,_motherIndex));
			else{
				scrollableTable.deleteRow(trId);
				if(_trackDeleted) _deletedIndividuals += "," + _currentFather;
			}
		}
		// Check if only the original founders are left after the delete:
		// If yes, remove them from the grid:
		if(scrollableTable.getRowCount() == 2){
			if(_trackDeleted && _originalFounders.length == 2){
				_deletedIndividuals += ","+ _originalFounders[0].substr(1) + "," + _originalFounders[1].substr(1);
			}
			scrollableTable.deleteAllDataRows();
		}
	}
	
	//
	// _addChildren:
	//
	function _addChildren(numberOfMales,numberOfFemales,numberUnknown){
		
		// Need to check if there are no rows in the grid:
		
		_deleteAnyVirtualChild();
		_addRowsToGrid(numberOfMales,numberOfFemales,numberUnknown);
		_addChildrenFlag=false;
		_highlightIndividualInTable("");
		_currentMother="";
		_currentFather="";
		_currentIndividual="";
	}
	
	//
	// _addSibling:
	//
	function _addSibling(numberOfMales,numberOfFemales,numberUnknown){
		
		var rowId="r"+_currentIndividual;
		var rowtds = document.getElementById(rowId).getElementsByTagName("td");
		
		_currentFather = (rowtds[_fatherIndex].firstChild.nodeValue);
		_currentMother = (rowtds[_motherIndex].firstChild.nodeValue);
	
		if(_currentMother == "." && _currentFather == "."){
			// Founding individual has been selected
			// First add parents for this founding individual
			_currentFather = _addRow("M",".",".",true);
			_currentMother = _addRow("F",".",".",true);
			rowtds[_fatherIndex].firstChild.nodeValue = _currentFather;
			rowtds[_motherIndex].firstChild.nodeValue = _currentMother;
		}
		_addRowsToGrid(numberOfMales,numberOfFemales,numberUnknown);
		_currentMother ="";
		_currentFather ="";
		_addSiblingFlag = false;
	}
	
	//
	// _addSpouse:
	//
	function _addSpouse(numberOfMales,numberOfFemales,numberUnknown,noChildrenFlag){
		
		var rowId="r"+_currentIndividual;
		
		var rowtds = document.getElementById(rowId).getElementsByTagName("td");
		
		if(rowtds[_genderIndex].firstChild.nodeValue =="M"){
			_currentFather = _currentIndividual;
			// Add spouse
			_currentMother = _addRow("F",".",".",true);
			// Determine if the father is an original individual
			if(_originalFounders.indexOf("r"+_currentFather) !=-1) _originalFounders[_originalFounders.length] = "r"+_currentMother;
			
		}else if(rowtds[_genderIndex].firstChild.nodeValue == "F"){
			_currentMother = _currentIndividual;
			// Add spouse
			_currentFather = _addRow("M",".",".",true);
			// Determine if the mother is an original individual
			if(_originalFounders.indexOf("r"+_currentMother) != -1) _originalFounders[_originalFounders.length] = "r"+_currentFather;
			
		}
		
		if(noChildrenFlag){
			// add a virtual child to represent a marriage with no children
			var virtualId = _addRow(".",_currentFather,_currentMother,true,true);
			
			// Update the vIndividual
			_parentsOfVirtualChild[virtualId] = new vIndividualParents(_currentFather,_currentMother); 
			
		}else _addRowsToGrid(numberOfMales,numberOfFemales,numberUnknown);
		_currentMother ="";
		_currentFather ="";
		_addSpouseFlag = false;
		
	}
	
	//
	// _addFounderGroup:
	//
	function _addFounderGroup(numberOfMales,numberOfFemales,numberUnknown){
		
		// Add founding group
		_currentFather = _addRow("M",".",".",true);
		_currentMother = _addRow("F",".",".",true);
		
		_originalFounders[_originalFounders.length] = "r"+_currentFather;
		_originalFounders[_originalFounders.length] = "r"+_currentMother;
		_addRowsToGrid(numberOfMales,numberOfFemales,numberUnknown);
		_currentMother ="";
		_currentFather ="";
		_addFounderFlag = false;
		
	}
	
	//
	// parseGrid: sends the grid data back to the server.
	//
	function _parseGrid(saveFlag){
		
		var thColumns = _grid.getElementsByTagName("th");
		var numberOfColumns = thColumns.length;
		var tdColumns = _grid.getElementsByTagName("td");
		var tdString = "";
		// Get the column headers first
		for(var i=0;i<numberOfColumns;i++){
			tdString += "," + thColumns[i].firstChild.nodeValue;
		}
		
		for(var i=0;i<tdColumns.length;i++){
			tdString += "," + tdColumns[i].firstChild.nodeValue;
		}
		
		//
		// If a request is in a state other than complete or 
		// uninitialized abort the ongoing request
		//
		_grequest.abort();
		if(saveFlag){
			_grequest.setQueryTermsString('s='+numberOfColumns+'&d='+tdString.substr(1)+'&fid='+_familyInput.getValue()+'&di='+_deletedIndividuals);
		}else
			_grequest.setQueryTermsString('v='+numberOfColumns+'&d='+tdString.substr(1)+'&fid='+_familyId);
		
		_grequest.load();
		
	}
	
	
	//
	// _setSVGGraphHandler:
	//
	function _setSVGGraphHandler(){
		
		// Without the setTimeout, attaching the onclick event happens before the plot
		// is actually loaded in DOM and the event handler is not set.
		// setTimeOut makes sure that the svg nodes are actually loaded
		// and then assigns the handler
		//
		// Make sure the drawing is loaded onto the DOM
		//
		
		if(document.getElementById(svgNodeId)){
			_self.addSVGEvents();
			_svgDrawingNode = document.getElementById(svgNodeId);
			_setPreviousState();
		}else{
			 setTimeout(_setSVGGraphHandler,5);
		}
		
	}
	
	
	//
	// _highlightIndividualInTable
	//
	function _highlightIndividualInTable(selectedIndividualId){
		if(_currentIndividual && _currentIndividual != selectedIndividualId){
			trId = "r"+_currentIndividual;
			scrollableTable.highlightRow(trId,"");
		}else if(_currentMother && _currentFather){
			if(_currentMother != selectedIndividualId){
				trId = "r"+_currentMother;
				scrollableTable.highlightRow(trId,"");
			}
			if(_currentFather != selectedIndividualId){
				trId = "r"+_currentFather;
				scrollableTable.highlightRow(trId,"");
			}
		}
		var trId = "r"+selectedIndividualId;
		scrollableTable.highlightRow(trId,"selected",true);
		
	}
	
	
	//
	// _selectIndividual:
	//
	function _selectIndividual( individualObject, iconNode, matingFlag ){
		
		//
		// deselect previously selected individual:
		//
		if( individualObject.node){
			// Set back to "solid" class:
			individualObject.node.setAttribute("class","solid");
		}
		if(matingFlag);
		else{
			if(_selectedMother.node){
				_selectedMother.node.setAttribute("class","solid");
			}
			if(_selectedFather.node){
				_selectedFather.node.setAttribute("class","solid");
			}
		}
		//
		// select the new individual:
		//
		if(iconNode){
			individualObject.node       = iconNode;
			individualObject.node.setAttribute("class","selectedIndividual");
		}
	}
	
	//
	// _displaySavedPedigrees: If the user is logged in, display all the pedigree previously saved in the database
	//
	function _displaySavedPedigrees(request){
		
		// Delete all the existing text nodes:
		while(_viewContainer.firstChild) _viewContainer.removeChild(_viewContainer.firstChild);
		_viewWin.show(true);
		_viewWin.bringToTop("viewWin");
		var row = request.responseXML.getElementsByTagName('f');
		for(var i=0;i<row.length;i++){
			//var pElement = document.createElementNS(NS.xhtml,"p");
			//pElement.addEventListener("click",_self.retrieveSavedPedigree,false);
			//pElement.appendChild(document.createTextNode(row[i].firstChild.nodeValue));
			//_viewContainer.appendChild(pElement);
			var spanElement = document.createElementNS(NS.xhtml,"span");
			spanElement.setAttribute("class","miniButton");
			spanElement.addEventListener("click",_self.retrieveSavedPedigree,false);
			spanElement.appendChild(document.createTextNode(row[i].firstChild.nodeValue));
			_viewContainer.appendChild(spanElement);
		
		}
		
		
	}
	
	
	///////////////////////////////////////////////
	//
	// Public Functions:
	//
	///////////////////////////////////////////////
	
	//
	// updateGridOnEdit: called when the confirm event of the table editor is clicked.
	//
	this.updateGridOnEdit = function(oldValue,newValue,tdClassName){
		
		if(tdClassName == "bubble"){
			
			// An id was changed 
			// Update the td elements
			
			// First check if the newValue already exists as a row
			var trId = "r"+newValue;
			
			if(document.getElementById(trId)) {
				
				trIdOld = "r"+oldValue;
				// In some cases the row with the oldValue has values for father and mother id
				// Copy them over to the newValue row
				var fatherId = document.getElementById(trId).getElementsByTagName("td")[_fatherIndex].firstChild.nodeValue;
				if(fatherId == "" || fatherId == "."){
					document.getElementById(trId).getElementsByTagName("td")[_fatherIndex].firstChild.nodeValue = document.getElementById(trIdOld).getElementsByTagName("td")[_fatherIndex].firstChild.nodeValue;
					document.getElementById(trId).getElementsByTagName("td")[_motherIndex].firstChild.nodeValue = document.getElementById(trIdOld).getElementsByTagName("td")[_motherIndex].firstChild.nodeValue;
				}
				// Delete the row with oldValue
				scrollableTable.deleteRow(trIdOld);
			}
			
			// Check if there is a row with old Value
			trId="r"+oldValue;
			if(document.getElementById(trId)){
				 document.getElementById(trId).getElementsByTagName("td")[_individualIndex].firstChild.nodeValue = newValue;
				// Update the old row id to the new id
				var newtrId = "r"+newValue;
				//document.getElementById(trId).id = newtrId;
				scrollableTable.replaceId(trId,newtrId);
			}
			// Update the parents columns:
			var trElements = _grid.getElementsByTagName("tr");
			for(var i=1;i<trElements.length;i++){
				var tdElements = trElements[i].getElementsByTagName("td");
				if(tdElements[_fatherIndex].firstChild.nodeValue == oldValue)
					tdElements[_fatherIndex].firstChild.nodeValue = newValue;
				else if(tdElements[_motherIndex].firstChild.nodeValue == oldValue)
					tdElements[_motherIndex].firstChild.nodeValue = newValue;
			}
			
			if(_currentMother == oldValue) _currentMother = newValue;
			else if(_currentFather == oldValue) _currentFather = newValue;
			else if(_currentIndividual == oldValue) _currentIndividual = newValue;
			// Update the SVG pedigree too:
			if(_grid.getElementsByTagName("tr").length > _minimumRows)
				_parseGrid();
			
		}else if(tdClassName == "redraw"){
			
			// Need to update the SVG pedigree too...
			if(_grid.getElementsByTagName("tr").length > _minimumRows)
				_parseGrid();
		}
		_hasBeenTouched = true;
		if(_loggedIn) _myToolBar.enableSave();
		
	}
	
	//
	// addChildrenHandler:
	//
	this.addChildrenHandler = function(){
		
		_resetFlags();
		// Enable add Children flag
		_addChildrenFlag=true;
		// Display input Form Section
		_myToolBar.showUserInputSection();
		
	}
	
	//
	// addSiblingHandler:
	//
	this.addSiblingHandler = function(){
		
		_resetFlags();
		// Enable add Sibling flag
		_addSiblingFlag=true;
		// Display input Form Section
		_myToolBar.showUserInputSection(true);
		
		
	}
	
	//
	// addSpouseHandler:
	//
	this.addSpouseHandler = function(){
		
		_resetFlags();
		// Enable add Sibling flag
		_addSpouseFlag=true;
		// Display input Form Section
		_myToolBar.showUserInputSection(false,true);
		
		
	}
	
	//
	// addFounderHandler:
	//
	this.addFounderHandler = function(){
		
		_resetFlags();
		// Enable add founder flag
		_addFounderFlag = true;
		// Display input Form Section
		_myToolBar.showUserInputSection();
		
		
	}
	
	//
	// deleteHandler:
	// 
	this.deleteHandler = function(){
		
		_myToolBar.hideUserInputSection();
		_resetFlags();
		_delete();
		
		// Check if the only founding group was deleted
		if(_grid.getElementsByTagName("tr").length == _minimumRows){
			
			if(document.getElementById(svgNodeId))
				svgContainer.removeChild(document.getElementById(svgNodeId));
		}else{
			_parseGrid();
			
			// Update the table editor row count
		gte.activateTable(_grid);
		}
		_highlightIndividualInTable("");
		_currentIndividual = _currentMother = _currentFather = "";
		_myToolBar.updateDisplay(_currentMother,_currentIndividual);
		if(!_hasBeenTouched){
			_hasBeenTouched = true;
			if(_loggedIn) _myToolBar.enableSave();
		}
		
	}
	
	//
	// addRowsToPedigree: called by draw to add new entries onto the grid and drawing
	//
	this.addRowsToPedigree = function(){
		
		// Get the count of the number of males to be added
		var numberOfMales = parseInt(document.getElementById("males").value,10);
		if(isNaN(numberOfMales) || numberOfMales < 0) numberOfMales=0;
		var numberOfFemales = parseInt(document.getElementById("females").value,10);
		if(isNaN(numberOfFemales) || numberOfFemales < 0) numberOfFemales = 0;
		var numberUnknown = parseInt(document.getElementById("unknown").value,10);
		if(isNaN(numberUnknown) || numberUnknown < 0) numberUnknown = 0;
		if(numberOfMales == 0 && numberOfFemales == 0 && numberUnknown == 0 && !document.getElementById("nochildren").checked){
			return;
		}
		var updateWidths = false;
		// Determine which button was clicked
		if(_addChildrenFlag){
			_addChildren(numberOfMales,numberOfFemales,numberUnknown);
			// Bring toolbar to default state
			_myToolBar.updateDisplay(_currentMother,_currentIndividual);
		}else
		if(_addSiblingFlag){
			_addSibling(numberOfMales,numberOfFemales,numberUnknown);
		}else
		if(_addSpouseFlag){
			_addSpouse(numberOfMales,numberOfFemales,numberUnknown,document.getElementById("nochildren").checked);
		}else
		if(_addFounderFlag){
			_addFounderGroup(numberOfMales,numberOfFemales,numberUnknown);
			updateWidths = true;
		

		}
		
		// Send the grid data to the server
		_parseGrid();
		
		// Update the table editor row count
		gte.activateTable(_grid);
		
		// Hide the input form section:
		_myToolBar.hideUserInputSection();
		if(!_hasBeenTouched){
			_hasBeenTouched = true;
			if(_loggedIn) _myToolBar.enableSave();
		}
		
		_myToolBar.resetSpinValues();
		if(updateWidths){
			window.setTimeout(scrollableTable.updateHeaderWidths,1000);	
		}
	}
	
	//
	// getFamilyFromDatabase: called by retrieve to get the records in the database for a family input by the user.
	//
	this.getFamilyFromDatabase = function(){
		
		gte.myDismiss();
		_hasBeenTouched = false;
		if(!_familyInput.getValue() || _familyInput.getValue == ".") return false;
		
		_myToolBar.show();
		if(!_familyId){
			_showPedigreeWindows();
		}
		_myToolBar.updateDisplay();
		_myToolBar.disableSave();
		// Check if the entered family id is the same as the previous
		if(_familyId == _familyInput.getValue()) return;
		_resetFlags();
		_resetDrawingParameters();
		_newPedigree = true;
		_familyId = _familyInput.getValue();
		var tempUnsampledPrefix = _unsampledPrefixInput.getValue();
		if(tempUnsampledPrefix.length < 6) _unsampledPrefix = tempUnsampledPrefix;
		else                               _unsampledPrefix = tempUnsampledPrefix.substring(0,6);
		
		//_sampledPrefix = _sampledPrefixInput.getValue();
		
		//
		// If a request is in a state other than complete or 
		// uninitialized abort the ongoing request
		//
		_grequest.abort();
		_grequest.setQueryTermsString('f='+_familyId+'&up='+_unsampledPrefix);
		_grequest.load();
		
	}
	
	
	
	//
	// saveFamily:
	//
	this.saveFamily = function(){
		_parseGrid(1);
		
	}
	
	
	// Methods used to interact with the SVG Drawing:
	//
	// setSelectedIndividual: highlight the selected individual on the grid and SVG drawing
	//
	this.setSelectedIndividual = function( evt ){
		
		var iconNode = evt.target;
		_selectIndividual( _selectedIndividual, iconNode );
		_highlightIndividualInTable(iconNode.id);
		_currentIndividual = iconNode.id;
		_currentMother="";
		_currentFather="";
		// Determine if the selected individual is an ordinary founder:
		var trId = "r"+_currentIndividual;
		var tdElements = document.getElementById(trId).getElementsByTagName("td");
		if(tdElements[_genderIndex].firstChild.nodeValue == ".")
			_myToolBar.updateDisplay(_currentMother,_currentIndividual,false,false,true);
		else if(tdElements[_fatherIndex].firstChild.nodeValue == "." && tdElements[_motherIndex].firstChild.nodeValue == "."){
			
			// Determine if the individual is a original or ordinary founder
			if(_originalFounders.indexOf(trId) != -1){
				_myToolBar.updateDisplay(_currentMother,_currentIndividual,false,true);
			}else{
				_myToolBar.updateDisplay(_currentMother,_currentIndividual,true);
			}
		}else _myToolBar.updateDisplay(_currentMother,_currentIndividual);
		
	}
	
	//
	// findSVGIndividual: find the SVG individual drawing node by id
	//
	this.findSVGIndividual = function( id ){
		
		//
		// Look at the women first:
		//
		var females = _svgDrawingNode.getElementsByTagName("circle");
		for(i=0;i<females.length;i++){
			if(females[i].id==id) return females[i];
		}
		//
		// Get here if not found among the women: look among the males:
		//
		var males = _svgDrawingNode.getElementsByTagName("rect");
		for(i=0;i<males.length;i++){
			if(males[i].id==id) return males[i];
		}
		
	}
	
	//
	// setSelectedParents: highlight the selected pair on the grid and SVG drawing
	//
	this.setSelectedParents = function( evt ){
		
		var lineId = evt.target.id;
		
		var idArray = lineId.split(":");
		
		if(_selectedIndividual.node){
			_selectedIndividual.node.setAttribute("class","solid");
		}
		var momNode = _self.findSVGIndividual( idArray[0] );
		var dadNode = _self.findSVGIndividual( idArray[1] );
		//alert(momNode.id + " " + dadNode.id);
		if(_currentIndividual == momNode.id || _currentIndividual == dadNode.id) _currentIndividual = "";
		_selectIndividual( _selectedMother, momNode,true );
		_highlightIndividualInTable(momNode.id);
		_selectIndividual( _selectedFather, dadNode ,true);
		_highlightIndividualInTable(dadNode.id);
		_currentMother = momNode.id;
		_currentFather = dadNode.id;
		_currentIndividual = "";
		_myToolBar.updateDisplay(_currentMother,_currentIndividual);
		
	}
	
	//
	// resetSelection:
	//
	this.resetSelection = function(){
		
		_selectIndividual(_selectedIndividual);
		_highlightIndividualInTable("");
		_currentIndividual = _currentMother = _currentFather = "";
		_myToolBar.updateDisplay(_currentMother,_currentIndividual);
		
	}
	
	//
	// addSVGEvents: adds 'onclick' events on the SVG drawing icon nodes 
	//
	this.addSVGEvents = function(){
		
		document.getElementById(svgNodeId).addEventListener("dblclick",_self.resetSelection,false);
		addIconEventMethod("click",_self.setSelectedIndividual);
		addLineEventMethod("click",_self.setSelectedParents);
		
	}
	
	// Method used by AJAX 
	// 
	// populate: method called when the ajax request is complete to process the grid and svg drawing data.
	//
	this.populate = function(request){
		
		// DEBUG:
		//alert(request.responseText);
		if(request.responseXML.getElementsByTagName('i').length==1) return;
		// Check if the user requested to view the pedigrees saved in db
		var viewFlag = request.responseXML.getElementsByTagName('vp').length;
		// Check if the user was registered:
		var registerFlag = request.responseXML.getElementsByTagName('rf').length;
		if(viewFlag || registerFlag){
			// Check for errors:
			var errCount = request.responseXML.getElementsByTagName("err").length;
			if(errCount){
				var err = request.responseXML.getElementsByTagName("err")[0].firstChild.nodeValue;
				alert(err);
			}else if(viewFlag){
				_displaySavedPedigrees(request);
			}else if(registerFlag){
				alert("You can login to save the pedigrees.");
				_registerSection.hide();
			}
			return;
		}
		
		// Check if the save flag was passed:
		var saveFlag=request.responseXML.getElementsByTagName('sf').length;
		
		if(!saveFlag){
			// Check if the svgContainer has children;If yes, delete them:
			if(svgContainer.hasChildNodes())
			while(svgContainer.firstChild){
				svgContainer.removeChild(svgContainer.firstChild);
			}
		}
		
		
		// Update the familyid,  counter and prefixes:
		var temp = request.responseXML.getElementsByTagName('dp');
		if(temp.length){
			if(temp[0].hasAttributeNS(null,'fid')) _familyId=temp[0].getAttributeNS(null,'fid');
			if(temp[0].hasAttributeNS(null,'uc')) _unsampledCount = temp[0].getAttributeNS(null,'uc');
			if(temp[0].hasAttributeNS(null,'up')) _unsampledPrefix = temp[0].getAttributeNS(null,'up');
			//if(temp[0].hasAttributeNS(null,'sp')) _sampledPrefix = temp[0].getAttributeNS(null,'sp');
			
		}
		
		
		// Update the window titles:
		_svgWin.setTitle(_familyId+" Pedigree Drawing");
		_tableWin.setTitle(_familyId+" Pedigree Data Table"); 
		
		// Check for errors:
		var errCount = request.responseXML.getElementsByTagName("err").length;
		if(errCount){
			var err = request.responseXML.getElementsByTagName("err")[0].firstChild.nodeValue;
			if(saveFlag){
				_myToolBar.disableSave();
				_hasBeenTouched = false;
				_trackDeleted = true;
				_deletedIndividuals="";
			}else{
				// Delete the grid rows from the previous family if the previous operation was not save:
				scrollableTable.deleteAllDataRows();
				scrollableTable.hide();
				_hasBeenTouched = false;
				_mainWin.iconify();
			}
			alert(err);
			return;
		}
		
		
		// Populate the svg container:
		var nodes = new DOMParser().parseFromString(request.responseText,'text/xml').documentElement;
		for(var i=0;i<nodes.childNodes.length;i++){
			if(nodes.childNodes[i].nodeName == "svg"){
				//svgContainer.appendChild(document.importNode(nodes.childNodes[i],true));
				svgContainer.appendChild(document.adoptNode(nodes.childNodes[i],true));
				break;
			}
		}
		if(svgContainer.hasChildNodes()) _setSVGGraphHandler();
		
		_myToolBar.enableDownload();
		// Populate the grid:
		scrollableTable.show();
		var gridCount = request.responseXML.getElementsByTagName("grid").length;
		
		if(gridCount){
			
			// Delete the grid rows from the previous family:
			scrollableTable.deleteAllDataRows();
			var row = request.responseXML.getElementsByTagName('r');
			for(var i=0;i<row.length;i++){
				_populateRow(row[i]);
			}
			// Do not activate the table if an example pedigree is currently being loaded:
			if(_isExample) _isExample = false;
			else{
				// Update the table editor row count
				gte.activateTable(_grid);
			}
			// Show the UI elements
			if(_showToolBar){
				_showToolBar=false;
				_myToolBar.show();
				_showPedigreeWindows();
			}
			// Update the header widths of the recently loaded grid
			scrollableTable.updateHeaderWidths();
			_mainWin.iconify();
		}
		if(_newPedigree){
			_trackDeleted=true;
			_deletedIndividuals="";
			_determineOriginalFounders();
			_newPedigree = false;
			
		}
		// If the gender of the currentIndividual has changed, update the toolbar display
		if(_currentIndividual){
			var trId = "r"+_currentIndividual;
			var gender = document.getElementById(trId).getElementsByTagName("td")[_genderIndex].firstChild.nodeValue;
			_myToolBar.updateDisplay(_currentMother,_currentIndividual,"","",(gender=="."));
		}
		if(_hasBeenTouched && _loggedIn) _myToolBar.enableSave();
	}
	
	// Methods called from outside:
	//
	// setFamilyDrawingParameters: set the parameters retrieved from the database:
	//
	this.setFamilyDrawingParameters = function(sampledPrefix,unsampledPrefix,familyPrefix,unsampledCount){
		
		_sampledPrefix = sampledPrefix;
		_unsampledPrefix = unsampledPrefix;
		_familyPrefix = familyPrefix;
		_unsampledCount = unsampledCount;
		
	}
	
	//
	// requestFiles: called to display the files processed when a .ged file was input.
	//
	this.requestFiles = function(type){
			
		//alert("Requesting Files");
		_showToolBar = true;
		_hasBeenTouched = true;
		_newPedigree = true;
		//
		// If a request is in a state other than complete or 
		// uninitialized abort the ongoing request
		//
		_grequest.abort();
		if(type == 1) _grequest.setQueryTermsString('g='+1);
		else          _grequest.setQueryTermsString('u='+1);
		_grequest.load();
	}
	
	//
	// formatFamilyId: Wrapper around the main.js formatFamilyId
	//
	this.formatFamilyId = function(){
		
		formatFamilyId(_familyPrefix);
		
	}
	
	//
	// initializeNewPedigreeDisplay:
	//
	this.initializeNewPedigreeDisplay = function(){
		
		gte.myDismiss();
		if(!_familyInput.getValue() || _familyInput.getValue == ".") return false;
		//if(!validateFamilyId(_familyPrefix)) return false;
		_myToolBar.show();
		_showPedigreeWindows();
		
		_myToolBar.updateDisplay();
		_myToolBar.disableDownload();
		
		// Check if the entered family id is the same as the previous
		if(_familyId == _familyInput.getValue()) return;
		_resetFlags();
		_resetDrawingParameters();
		_familyId = _familyInput.getValue();
		
		if(_peds.getSelectedText() != "."){
			_peds.setSelection(0);
		}
		// Update the window titles:
		_svgWin.setTitle(_familyId+" Pedigree Drawing");
		_tableWin.setTitle(_familyId+" Pedigree Data Table"); 
		_mainWin.iconify();
		
		// Update the prefixes:
		var tempUnsampledPrefix = _unsampledPrefixInput.getValue();
		if(tempUnsampledPrefix.length < 6) _unsampledPrefix = tempUnsampledPrefix;
		else                               _unsampledPrefix = tempUnsampledPrefix.substring(0,6);
		//_sampledPrefix   = _sampledPrefixInput.getValue();
		
		// Delete existing nodes from the svg container:
		if(svgContainer.hasChildNodes())
		while(svgContainer.firstChild){
			svgContainer.removeChild(svgContainer.firstChild);
		}
		// Delete the data rows:
		scrollableTable.deleteAllDataRows();
		scrollableTable.hide();
		
	}
	
	//
	// loadExampleFile:
	//
	this.loadExampleFile = function(e){
		
		gte.myDismiss();
		e = gEvent(e);
		var prefix = e.targetElement.value;
		_familyInput.setValue("");
		_showPedigreeWindows();
		// prevent users from changing the  examples
		_myToolBar.hide();
		_resetDrawingParameters();
		if(prefix == "."){
			_hidePedigreeWindows();
			_myToolBar.updateDisplay();
			return;
		}
		
		_isExample = true;
		//
		// If a request is in a state other than complete or 
		// uninitialized abort the ongoing request
		//
		_grequest.abort();
		_grequest.setQueryTermsString('e='+prefix);
		_grequest.load();
		
	}
	
	//
	// registerUser:
	//
	this.registerUser = function(){
		
		//
		// If a request is in a state other than complete or 
		// uninitialized abort the ongoing request
		//
		var queryString = _registerSection.getQueryStringParameters();
		if(!queryString) return;
		_grequest.abort();
		_grequest.setQueryTermsString(queryString);
		_grequest.load();
		
		
	}
	
	//
	// retrieveHandler:
	//
	this.retrieveHandler = function(){
		                             
		if(hasDemo && !_loggedIn) _self.initializeNewPedigreeDisplay();
		else                          _self.getFamilyFromDatabase();
		
	}
	
	//
	// registerHandler: 
	//
	this.registerHandler = function(){
		
		_registerSection.show();
		
	}
	
	//
	// getSVGDocumentFragment: used by print
	//
	this.getSVGDocumentFragment = function(){
		
		return _browserWindowManager.svgDocumentFragment;
		
	}
	
	//
	// requestSavedPedigreeList:
	// User has logged in. Show all the pedigree that are in the database under that user:
	//
	this.requestSavedPedigreesList = function(){
		
		//
		// If a request is in a state other than complete or 
		// uninitialized abort the ongoing request
		//
		_grequest.abort();
		_grequest.setQueryTermsString('vp='+1);
		_grequest.load();
		
		
	}
	
	//
	// retrieveSavedPedigree: get pedigree clicked by the user on the Saved Pedigrees window:
	//
	this.retrieveSavedPedigree = function(e){
		var familyId = e.target.firstChild.nodeValue;
		_familyInput.setValue(e.target.firstChild.nodeValue);
		_self.getFamilyFromDatabase();
		_viewWin.iconify();
	}
	
	
	
	//
	// setLoggedIn:
	//
	this.setLoggedIn = function(userid){
		_loggedIn = true;
		if(_hasBeenTouched) _myToolBar.enableSave();
		// Let the user know about being logged in
		//_loginStatus.appendChild(document.createTextNode(userid + ", you are logged in."));
		//_contentWin.getCanvas().setAttribute("class","windowCanvasHighlighted");
		_mainWin.setTitleNodeIconTrayClass("highlighted","iconTrayHighlighted");
		_mainWin.setTitle("Madeline 2.0 PDE: " + userid);
		// Change the tab to edit pedigrees:
		_mtc.selectTab(2);
		// Change the login button label to logout:
		_loginButton.changeLabel("Logout");
		// Enable viewing saved pedigree ids
		_viewSaved.enable();
	}
	
	//
	// showLoginWidget:
	//
	this.showLoginWidget = function(){
		if(!_loggedIn){
			_loginWidget.show(true);
		}else{
			_logout();
		}
	}
	
	// If the core pedigree drawing fields are absent from the table return
	if(!_createRowTemplateNode()){
		_myToolBar.hide();
		return false;
	}
	
	// Set event handlers on input toolbar buttons/ toolbar menu items:
	_retrieve.addEventMethod(this.retrieveHandler);
	_viewSaved.addEventMethod(this.requestSavedPedigreesList);
	//_loginButton.addEventMethod(this.showLoginWidget);
	_loginButton.addEventListener("click",this.showLoginWidget);
	_registerSection.setRegisterHandler("click",this.registerUser);
	if(hasDemo){
		_peds.addEventListener("change",this.loadExampleFile);
	}
	// Add a event handler on the table editor confirm event
	gte.addConfirmEventHandler(_self.updateGridOnEdit);
	
	_myToolBar.setDrawHandler("click",this.addRowsToPedigree);
	_myToolBar.setMenuItemAction("spouse",_self.addSpouseHandler);
	_myToolBar.setMenuItemAction("sibling",_self.addSiblingHandler);
	_myToolBar.setMenuItemAction("children",_self.addChildrenHandler);
	_myToolBar.setMenuItemAction("founders",_self.addFounderHandler);
	_myToolBar.setMenuItemAction("delete",_self.deleteHandler);
	_myToolBar.setMenuItemAction("save",_self.saveFamily);
	_myToolBar.setMenuItemAction("savesvg",_browserWindowManager.saveSVG);
	_myToolBar.setMenuItemAction("printsvg",_browserWindowManager.printSVG);
	_myToolBar.setDataSubMenuItemAction("tab",_browserWindowManager.getTableInTabDelimitedFormat);
	_myToolBar.setDataSubMenuItemAction("madeline",_browserWindowManager.getTableInMadelineFlatFormat);
	_myToolBar.setDataSubMenuItemAction("madelinexml",_browserWindowManager.getTableInMadelineXMLFormat);
	_myToolBar.updateDisplay();
	_myToolBar.hide();
	
	// gRequest object
	_grequest = new gRequest(URL,this.populate,"post",_waitIndicator);
	_createLoginWidget();
	
}

