var LOGINNODE_INIT = 'init';
var LOGINNODE_USER = 'user';
var LOGINNODE_DATABASE = 'database';
var LOGINNODE_CLIENT = 'client';
var LOGINNODE_NEWUSER = 'newuser';
var saNodeButId = 
[	'nodebutton' + LOGINNODE_USER,  
	'nodebutton' + LOGINNODE_DATABASE, 
	'nodebutton' + LOGINNODE_CLIENT, 
	'nodebutton' + LOGINNODE_INIT

];
var baNodeEnabled = [ false, false, false, true ];
var LOG_SRC_CLI	= "CLIWEB";

var LOGINLEVEL_USER = '1';
var LOGINLEVEL_DATABASE = '2';
var LOGINLEVEL_CLIENT = '3';
var LOGINLEVEL_NEWUSER = '9';
var LOGINLEVEL_INIT = '99';

var LOGINACTION_REGISTER = 'register';
var LOGINACTION_NEWUSER = 'newuser';
var LOGINACTION_LOGIN = 'login';
var LOGINACTION_CONFIGUSER = 'configuser';
var LOGINACTION_NEWDB = 'newdb';
var LOGINACTION_CONFIGDB = 'configdb';
var LOGINACTION_CONFIGCLIENTDB = 'configclientdb';
var LOGINACTION_NEWCLIENT = 'newclient';
var LOGINACTION_LOADDBSKEL = 'loaddbskel';
var LOGINACTION_FORMCREATOR = 'formcreator';
var LOGINACTION_SYNC = 'sync';
var LOGINACTION_FORM = 'form';
var LOGINACTION_VIEWLOG = 'viewlog';

var iLoginLevel = LOGINLEVEL_INIT;
var sLoginCode = '';
var sLastUserLoginCode = null;
var sLastDatabaseLoginCode = null;
var sLastClientLoginCode = null;
var sCurLoginNode = null;
var sCurAction = null;
var sCurActionPanId = null;
var sCurMainPanId = null;
var sCurNodeButtonText = null;
var bActionPanelOpen = false;
var sLastPassword = null;
var sActionDivId = null;
var elemStore = null;
var sConfigDbResponseText = '';
var bNeedDatabase = false;
var bNeedClient = false;
var saUserDatabases = [];
var saaDatabaseClients = [[]];
var regexLetNum = /[^0-9a-z]/;
var sErrMsgLetNum = 'may only contain letters or numbers';


function setLoginNode(sNewLoginNode, sNewAction)
{
	var	sNewNodeButtonId = 'nodebutton' + sNewLoginNode;
	var sNewMainPanId = 'mainpan' + sNewLoginNode;

	switch (sNewLoginNode)
	{
		case LOGINNODE_USER: 
			if (! baNodeEnabled [0])
				return;
			break;
		case LOGINNODE_DATABASE: 
			if (! baNodeEnabled [1])
				return;
			break;
		case LOGINNODE_CLIENT: 
			if (! baNodeEnabled [2])
				return;
			break;
	}

	if (bActionPanelOpen)
	{
		if (sNewLoginNode == sCurLoginNode)
		{
			// The currently pressed (active) button has been clicked. The button was "CLOSE" 
			// which means an Action was open and the action panel was showing, so close the 
			// Action, re-enable all Node buttons and continue with this function which will 
			// close the action panel and redisplay the current Node panel.
			setActionStatusClosed();
			if (sCurLoginNode == LOGINNODE_NEWUSER)
				// A new User has just been registered. Switch to the Initial Login Action.
				sNewLoginNode = LOGINNODE_INIT;
			if (sNewAction == null)
				// sNewAction is only null if a Node button has been clicked
				sNewAction = sCurAction;
		}
		else
			// One of the other Node buttons was clicked, but an Action is open on the current
			// button. Ignore the click.
			return;
	}
	else
	{
		if (sNewLoginNode == sCurLoginNode)
			// The button was clicked when it was already down. Switch to the Initial Login Action.
			sNewLoginNode = LOGINNODE_INIT;
	}

	if (sNewLoginNode == LOGINNODE_INIT)
	{
		replaceClass(sNewNodeButtonId, 'buttonon', 'buttonoff');
		sNewAction = null;
		sNewNodeButtonId = 'nodebutton' + sNewLoginNode;
		sNewMainPanId = 'mainpan' + sNewLoginNode;
	}

	// Show the Login Action Panel
	showActionPanel('panlogin');

	// If this is not the first call, disable the current button
	// and hide the current main panel.
	if (sCurLoginNode != null)
	{
		var	sCurNodeButtonId = null;

		sCurNodeButtonId = 'nodebutton' + sCurLoginNode;
		replaceClass(sCurNodeButtonId, 'buttonon', 'buttonoff');
		elemOpen(sCurMainPanId, false);
	}

	// Enable the new button and show the new main panel.
	replaceClass(sNewNodeButtonId, 'buttonoff', 'buttonon');
	elemOpen(sNewMainPanId, true); // "mainpannewuser"

	// Set the default action for the new login node
	if (sNewAction == null)
	{
		switch (sNewLoginNode)
		{
			case LOGINNODE_INIT :
				sNewAction = LOGINACTION_LOGIN;
				break;
			case LOGINNODE_USER :
				sNewAction = LOGINACTION_CONFIGUSER;
				break;
			case LOGINNODE_DATABASE :
				sNewAction = LOGINACTION_CONFIGDB;
				break;
			case LOGINNODE_CLIENT :
				sNewAction = LOGINACTION_SYNC;
				break;
			case LOGINNODE_NEWUSER :
				sNewAction = LOGINACTION_REGISTER;
				break;
		}
	}

	setAction(sNewLoginNode, sNewAction);
	sCurLoginNode = sNewLoginNode;
	sCurMainPanId = sNewMainPanId;
//	setLocation(['Login', cap(sCurLoginNode)]);
}


function setAction(sNewLoginNode, sNewAction)
{
	var	sNewLoginNodeAction;
	var	sNewRadioId;

	if (sNewLoginNode == null)
		sNewLoginNode = sCurLoginNode;

	sNewLoginNodeAction = sNewLoginNode + sNewAction;
	sNewRadioId = sNewLoginNodeAction + 'radio';
	sActionDivId = sNewLoginNodeAction + 'act';

	setLoginMsg('', false);

	// Hide the current action details
	if (sCurLoginNode != null && sCurAction != null)
	{
		var	sCurElemId = sCurLoginNode + sCurAction;
		var	sCurRadioId = sCurElemId + 'radio';

		elemOpen(sCurElemId, false);
		setChecked(sCurRadioId, false);
	}

	// Re-enable all action selection panels
	setActionSelectionEnabled(true, LOGINNODE_USER, LOGINACTION_CONFIGUSER)
	setActionSelectionEnabled(true, LOGINNODE_USER, LOGINACTION_NEWDB)
	setActionSelectionEnabled(true, LOGINNODE_DATABASE, LOGINACTION_CONFIGDB)
	setActionSelectionEnabled(true, LOGINNODE_DATABASE, LOGINACTION_NEWCLIENT)
	setActionSelectionEnabled(true, LOGINNODE_DATABASE, LOGINACTION_CONFIGCLIENTDB)
	setActionSelectionEnabled(true, LOGINNODE_DATABASE, LOGINACTION_LOADDBSKEL)
	setActionSelectionEnabled(true, LOGINNODE_DATABASE, LOGINACTION_FORMCREATOR)
	setActionSelectionEnabled(true, LOGINNODE_CLIENT, LOGINACTION_SYNC)
	setActionSelectionEnabled(true, LOGINNODE_CLIENT, LOGINACTION_FORM)
	setActionSelectionEnabled(true, LOGINNODE_CLIENT, LOGINACTION_VIEWLOG)
	setActionSelectionEnabled(true, LOGINNODE_NEWUSER, LOGINACTION_REGISTER)

	// Show the new action details
	elemOpen(sNewLoginNodeAction, true);
	setChecked(sNewRadioId, true);

	// Common defaults
	elemMove('loginactdatabase', elemStore);
	elemMove('loginactclient', elemStore);
	elemMove('loginactnewuser', elemStore);
	elemMove('loginactnewdatabase', elemStore);
	elemMove('loginactnewclient', elemStore);
	elemMove('loginactemail', elemStore);
	setAttValue('loginbuttontext', 'value', 'Login');

	bNeedDatabase = false;
	bNeedClient = false;

	switch (sNewLoginNodeAction)
	{
		case LOGINNODE_INIT + LOGINACTION_LOGIN :
			setAttValue('loginbuttontext', 'value', 'LOGIN');
			setElemValue('logincode', '');
			setLoggedIn(false);
			break;
		case LOGINNODE_USER + LOGINACTION_CONFIGUSER :
			setAttValue('loginbuttontext', 'value', 'Configure');
			break;
		case LOGINNODE_USER + LOGINACTION_NEWDB :
			setContent('actnewdatabasenamelabel', 'New Database Name:');
			sDatabase = '';
			sClient = '';
			elemMove('loginactnewdatabase', sActionDivId);
			setAttValue('loginbuttontext', 'value', 'Create New Database');
			break;
		case LOGINNODE_DATABASE + LOGINACTION_CONFIGDB :
			showNodeSelections(false);
			bNeedDatabase = true;
			setAttValue('loginbuttontext', 'value', 'Configure Database');
			break;
		case LOGINNODE_DATABASE + LOGINACTION_CONFIGCLIENTDB :
			showNodeSelections(true);
			setContent('actclientnamelabel', 'Config-User Name:');
			bNeedDatabase = true;
			bNeedClient = true;
			setAttValue('loginbuttontext', 'value', 'Configure User');
			break;
		case LOGINNODE_DATABASE + LOGINACTION_NEWCLIENT :
			showNodeSelections(false);
			setContent('actnewclientnamelabel', 'New Login Name:');
			sClient = '';
			bNeedDatabase = true;
			elemMove('loginactnewclient', sActionDivId);
			setElemValue('actnewclientname', '');
			elemMove('loginactemail', sActionDivId);
			setAttValue('loginbuttontext', 'value', 'Create New Login');
			break;
		case LOGINNODE_DATABASE + LOGINACTION_LOADDBSKEL :
			showNodeSelections(true);
			setContent('actclientnamelabel', 'Login to load from:');
			bNeedDatabase = true;
			setAttValue('loginbuttontext', 'value', 'Load Skeleton Database');
			break;
		case LOGINNODE_DATABASE + LOGINACTION_FORMCREATOR :
			showNodeSelections(false);
			bNeedDatabase = true;
			setAttValue('loginbuttontext', 'value', 'Open Form Creator');
			break;
		case LOGINNODE_CLIENT + LOGINACTION_SYNC :
			showNodeSelections(true);
			bNeedDatabase = true;
			bNeedClient = true;
			setAttValue('loginbuttontext', 'value', 'Start Sync');
			break;
		case LOGINNODE_CLIENT + LOGINACTION_FORM :
			showNodeSelections(true);
			bNeedDatabase = true;
			bNeedClient = false;
			setAttValue('loginbuttontext', 'value', 'Open Form');
			break;
		case LOGINNODE_CLIENT + LOGINACTION_VIEWLOG :
			showNodeSelections(true);
			bNeedDatabase = true;
			bNeedClient = true;
			setAttValue('loginbuttontext', 'value', 'View Sync Log');
			break;
		case LOGINNODE_NEWUSER + LOGINACTION_REGISTER :
			sUser = '';
			sDatabase = '';
			sClient = '';
			//setLoggedIn(false);
			elemMove('loginactnewuser', sActionDivId);
			elemMove('loginactnewdatabase', sActionDivId);
			elemMove('loginactnewclient', sActionDivId);
			elemMove('loginactemail', sActionDivId);
			setAttValue('loginbuttontext', 'value', 'Register');
			break;
	}

	if (! sLoginCode.length)
	{
		switch (sNewLoginNode)
		{
			case LOGINNODE_USER:
				if (sLastUserLoginCode)
					sLoginCode = sLastUserLoginCode;
				break;
			case LOGINNODE_DATABASE:
				if (sLastDatabaseLoginCode)
					sLoginCode = sLastDatabaseLoginCode;
				break;
			case LOGINNODE_CLIENT:
				if (sLastClientLoginCode)
					sLoginCode = sLastClientLoginCode;
				break;
		}
	}

	elemMove('loginbutton', sActionDivId);

	sCurAction = sNewAction;
}


var blkActClientForm;
var butOpenForm;
var selFormId;
var selPublicFormId;
var bPublicForm = 0;
var cfSelectedFormId;
var butAddPublicForm;
var blkCfForm;
var blkCfRootForm;
var cfOpenedFormId;


function retLoadFormIds(sRetVal, iStatus)
{
	clearSelectElement(selFormId.elem);

	if (iStatus != RPC_OK)
	{
		setStatus(sRetVal, C_ERROR);
		return;
	}

	var saFormId = JSON.parse(sRetVal);

	if (saFormId)
	{
		var saFormName = [];
		for (var i = 0; i < saFormId.length; i ++)
		{
			var sName = saFormId [i].replace(/~/g, ' ');
			saFormName.push(sName);
		}
		loadSelectElement(selFormId.elem, saFormName, '');
		selFormId.elem.selectedIndex = -1;
	}
}


function cfSelectFormClick(ev)
{
	ev = getEventProps(ev);
	ev.stopPropagation();

	if	(	selFormId.elem.selectedIndex != -1 &&
			selFormId.elem.options[selFormId.elem.selectedIndex].text.length
		)
	{
		cfSelectedFormId = selFormId.elem.options[selFormId.elem.selectedIndex].text;
		cfSelectedFormId = cfSelectedFormId.replace(/ /g, '~');
		butOpenForm.setEnabled(1);
		bPublicForm = 0;
	}
	else
		butOpenForm.setEnabled(0);
}


function cfOpenFormClick(ev)
{
	ev = getEventProps(ev);
	ev.stopPropagation();

	if (selFormId.elem.selectedIndex == -1)
		return;

	cfOpenedFormId = null;

	if (blkCfRootForm)
		blkCfRootForm.deleteForm();

	// Load the Form from the formTemplates store, or the server, 
	// and display in the Form page.
	cfOpenedFormId = cfSelectedFormId;
	if (formTemplates [cfSelectedFormId])
		cfLoadOpenedForm();
	else
	{
		// Try server.
		// Set the callback for retLoadFormTplatesSvr
		retRetLoadFormTplatesSvr = cfLoadOpenedForm;
		loadFormTplatesSvr(cfSelectedFormId);
	}
}


function cfLoadOpenedForm(iStatus, sResult)
{
	if (set(iStatus) && iStatus != RPC_OK)
	{
		setStatus('Error opening Form: ' + sResult, C_ERROR);
		return;
	}
		
	if (! cfOpenedFormId)
		return;

	blkCfRootForm = loadFormFromTplateStore(cfOpenedFormId, blkCfForm.elem);
	if (! blkCfRootForm)
	{
		setStatus('Form ' + cfOpenedFormId + ' not found. ' + sResult, C_ERROR);
		cfOpenedFormId = null;
		return;
	}
}


function retLoadPublicFormIds(sRetVal, iStatus)
{
	if (! selPublicFormId || ! selPublicFormId.elem)
		return;

	clearSelectElement(selPublicFormId.elem);

	if (iStatus != RPC_OK)
	{
		setStatus(sRetVal, C_ERROR);
		return;
	}

	var saFormId = JSON.parse(sRetVal);

	if (saFormId)
	{
		var saFormName = [];
		for (var i = 0; i < saFormId.length; i ++)
		{
			var sName = saFormId [i].replace(/~/g, ' ');
			saFormName.push(sName);
		}
		loadSelectElement(selPublicFormId.elem, saFormName, '');
		selPublicFormId.elem.selectedIndex = -1;
	}
}


function cfSelectPublicFormClick(ev)
{
	ev = getEventProps(ev);
	ev.stopPropagation();

	if	(	selPublicFormId.elem.selectedIndex != -1 &&
			selPublicFormId.elem.options[selPublicFormId.elem.selectedIndex].text.length
		)
	{
		cfSelectedFormId = selPublicFormId.elem.options[selPublicFormId.elem.selectedIndex].text;
		cfSelectedFormId = cfSelectedFormId.replace(/ /g, '~');
		butAddPublicForm.setEnabled(1);
		bPublicForm = 1;
	}
	else
		butAddPublicForm.setEnabled(0);
}


function retLinkPublicForm(sRetVal, iStatus)
{
	if (iStatus != RPC_OK && iStatus != RPC_IDLE)
	{
		setStatus(sRetVal, C_ERROR);
		return;
	}

	var sName = cfSelectedFormId.replace(/~/g, ' ');
	if (iStatus == RPC_IDLE)
	{
		setStatus(sRetVal, C_WARN);
		setSelectedOption(selFormId.elem, sName);
	}
	else
	{
		var option = new Option(sName);
		if (selFormId.elem.options)
			selFormId.elem.options[selFormId.elem.options.length] = option;
		selFormId.elem.selectedIndex = selFormId.elem.options.length - 1;
	}
	butOpenForm.setEnabled(1);
}


function cfLinkPublicFormClick(ev)
{
	ev = getEventProps(ev);
	ev.stopPropagation();

	if (! cfSelectedFormId)
		return;

	// Load the Form from the formTemplates store, or the server, 
	rpc('linkPublicForm', [ cfSelectedFormId ], retLinkPublicForm);
	butAddPublicForm.setEnabled(0);
	selPublicFormId.elem.selectedIndex = -1;
}


function createActionClientForm()
{
	frmInit();

	blkActClientForm = new Block( { id: 'actclientform', tabval: 'View Forms', 
		style: { border: 'none', 'background-color': '#FFFFFF' } } );
	blkActClientForm.tabval = 'View Forms';
	// Create Client Form
	var blkClientForm = new Block( { id: 'clientform', style: { border: 'none' } } );
	blkActClientForm.add(blkClientForm);
	// Create Button line
	var linButton = new Line({ id: 'cfbutton', style: { height: '2em', 
		backgroundColor: '#F1F5F9', 'border-width': '0', 'border-bottom': '1px solid #A3BBDB' } });
	blkClientForm.add(linButton);
	// Create Open Database Form Button and Select
	butOpenForm = new Button( { value: 'Open ' + sDatabase.toUpperCase() + ' Forms', 
		eventFuncs: [['click', cfOpenFormClick ]], style: { 'margin-left': '0.2em', 
		'margin-top': '0.2em', backgroundColor: '#DEE7F1' } } );
	linButton.add(butOpenForm);
	butOpenForm.setEnabled(0);
	selFormId = new Select( { id: 'cfformname', style: { 'margin-left': '0.2em', 
		'margin-top': '0.2em', backgroundColor: '#FFFFFF', borderColor: '#678EC2',  
		width: '15em' } } );
	selFormId.setEventFuncs([['change', cfSelectFormClick]]);
	linButton.add(selFormId);
	// Load Database Forms
	rpc('loadFormIds', [ 'database' ], retLoadFormIds);
	// If login level not Client, create Public Form Button and Select
	if (iLoginLevel < LOGINLEVEL_CLIENT || iLoginLevel == LOGINLEVEL_NEWUSER)
	{
		selPublicFormId = new Select( { id: 'cfpublicformname', label: 'Public Forms:',
			labelFormWidth: '15em', style: { 'margin-left': '0.4em', 'margin-top': '0.2em', 
			backgroundColor: '#FFFFFF', borderColor: '#678EC2',  width: '20em' } } );
		selPublicFormId.setEventFuncs([['change', cfSelectPublicFormClick]]);
		linButton.add(selPublicFormId);
		butAddPublicForm = new Button( { value: 'Add to ' + sDatabase.toUpperCase() + ' Forms', 
			eventFuncs: [['click', cfLinkPublicFormClick ]], style: { 'margin-left': '0.2em', 
			'margin-top': '0.2em', backgroundColor: '#DEE7F1' } } );
		linButton.add(butAddPublicForm);
		butAddPublicForm.setEnabled(0);
		// Load Public Forms
		rpc('loadFormIds', [ 'public' ], retLoadPublicFormIds);
	}

	blkCfForm = new Block( { id: 'cfform', style: { border: 'none', 'min-height': '5em' } } );
	blkClientForm.add(blkCfForm);

	blkMainActionAct.add(blkActClientForm);
}

var blkActClientSync;
var butSync;
var blkSyncStatus;


function createActionClientSync()
{
	blkActClientSync = new Block( { id: 'actclientsync',
		style: { border: 'none', 'background-color': '#FFFFFF' } } );
	blkActClientSync.tabval = 'Database Sync';
	var txtHeading = new Text( { value: 'Sync your local Database with the Server',
		style: { 'font-weight': 'bold', border: '1px solid #678EC2', width: '25em', 
		margin: '0.2em auto 0 auto', 'background-color': '#DEE7F1' } } );
	blkActClientSync.add(txtHeading);
	var txtMain = new Text( { value: 'The computer on which your database is installed ' +
		'must be connected to the Internet and its ispan program must be started.',
		style: { width: '45em', margin: '2em auto auto auto' } } );
	blkActClientSync.add(txtMain);
	butSync = new Button( { id: 'csbutsync', value: 'Start Data Sync',
		style: { width: '12em', margin: '2em auto auto auto'  } } );
	blkActClientSync.add(butSync);
	butSync.setEnabled(false);
	blkSyncStatus = new Block( { id: 'csstatus', 
		style: { height: '1.5em', 'font-size': '120%', padding: '0.2em', overflow: 'auto',
		margin: '1em 0 1em 0'} } );
	blkActClientSync.add(blkSyncStatus);

	// Load the clientsync.js functions
	loadResource('/script/clientsync.js', 'script', 'text/javascript',
		'csInit', ['bClientSyncLoaded', 'bChannelLoaded'], null);
		//bOldIE ? retClientSyncScript : null);

	blkMainActionAct.add(blkActClientSync);
}

var blkActConfigClientDb;
var blkConfCliDbMain;
var selConfCliDatabase;
var selConfCliClient;
var butConfCliLogin;
var sConfCliSelectedDb;
var sConfCliSelectedCli;
//var blkSyncStatus; configclientdb.js has its own


function ccLoginClick(ev)
{
	ev = getEventProps(ev);
	ev.stopPropagation();

	sDatabase = sConfCliSelectedDb;
	sClient = sConfCliSelectedCli;
	sCurLoginNode = LOGINNODE_DATABASE;
	sCurAction = LOGINACTION_CONFIGCLIENTDB;
	login();
}


function ccSelectDatabaseClick(ev)
{
	ev = getEventProps(ev);
	ev.stopPropagation();

	sConfCliSelectedDb = getSelectedOption(selConfCliDatabase.elem);
	loginConfigClientDb();
}


function ccSelectClientClick(ev)
{
	ev = getEventProps(ev);
	ev.stopPropagation();

	sConfCliSelectedCli = getSelectedOption(selConfCliClient.elem);
	loginConfigClientDb();
}


function loginConfigClientDb()
{
	if (! sConfCliSelectedDb)
	{
		if (saUserDatabases.length > 1)
		{
			selConfCliDatabase = new Select( { label: 'Database:', labelFormWidth: '13em', 
				classname: 'frmfloatright', style: { margin: '0.3em', width: '25em' } } );
			selConfCliDatabase.setEventFuncs([['change', ccSelectDatabaseClick]]);
			blkConfCliDbMain.add(selConfCliDatabase, butConfCliLogin);
			loadSelectElement(selConfCliDatabase.elem, saUserDatabases, '');
			return;
		}
		else
		{
			if (saUserDatabases.length)
				sConfCliSelectedDb = saUserDatabases [0];
			else
				sConfCliSelectedDb = sDatabase;
		}
	}
	if (! sConfCliSelectedCli)
	{
		if (saaDatabaseClients [sConfCliSelectedDb] && saaDatabaseClients [sConfCliSelectedDb].length)
		{
			if (saaDatabaseClients [sConfCliSelectedDb].length > 1)
			{
				selConfCliClient = new Select( { label: 'Local Database Login Name:', 
					labelFormWidth: '13em', classname: 'frmfloatright', 
					style: { margin: '0.3em', width: '25em' } } );
				selConfCliClient.setEventFuncs([['change', ccSelectClientClick]]);
				blkConfCliDbMain.add(selConfCliClient, butConfCliLogin);
				loadClientSelect(selConfCliClient.elem, sConfCliSelectedDb);
				return;
			}
			else
				sConfCliSelectedCli = saaDatabaseClients [sConfCliSelectedDb][0];
		}
		else
			sConfCliSelectedCli = sClient;
	}

	butConfCliLogin.setEnabled(true);
}


function createActionConfigClientDb(htmlConfigClientDb)
{
	if (! blkActConfigClientDb)
	{
		blkActConfigClientDb = new Block( { id: 'actconfigclientdb',
			style: { border: 'none', 'background-color': '#FFFFFF' } } );
		blkActConfigClientDb.tabval = 'Local Database Setup';
		blkConfCliDbMain = new Block( { style: { border: 'none' } } );
		blkActConfigClientDb.add(blkConfCliDbMain);
		blkMainActionAct.add(blkActConfigClientDb);
	}
	else
	{
		blkConfCliDbMain.deleteChildForms();
		blkConfCliDbMain.elem.innerHTML = '';
	}

	if (htmlConfigClientDb)
	{
		blkConfCliDbMain.elem.innerHTML = htmlConfigClientDb;

		// configclientdb.js has its own:
		//var blkConfigStatus = new Block( { id: 'csstatus', 
		//	style: { height: '1.5em', 'font-size': '120%', padding: '0.2em', overflow: 'auto',
		//	margin: '1em 0 1em 0'} } );
		//blkActConfigClientDb.add(blkConfigStatus);

		// Load the client configclientdb.js functions
		loadResource('/script/configclientdb.js', 'script', 'text/javascript', 
			'cfgInit', 'bConfigClientDbLoaded', null);
	}
	else
	{
		sConfCliSelectedDb = null;
		sConfCliSelectedCli = null;

		butConfCliLogin = new Button( { id: 'cfgLoadCfgCliDb', value: 'Setup Local Database',
			style: { margin: '1em auto 1em auto' } } );
		butConfCliLogin.setEventFuncs([['click', ccLoginClick]]);
		butConfCliLogin.setEnabled(false);
		blkConfCliDbMain.add(butConfCliLogin);

		loginConfigClientDb();
	}
}


function retConfigClientDb(responseText, responseStatus)
{
	// This callback opens the ConfigClientDb action tab. 
	//
	// It is called indirectly createNewUser() calls login() with action REGISTER 
	// whose callback is retNewUser() which calls login() with action CONFIGCLIENTDB 
	// whose callback is this function.
	//
	// It is also called from within createActionConfigClientDb itself, when
	// the only thing displayed is the Setup Local Database button, via ccLoginClick()
	// which also calls login() with action CONFIGCLIENTDB.
	if (responseStatus == HTTP_STATUS_OK)
	{
		// Strip ludc prefix from the configclientdb.html page sent by login.c
		var htmlConfigClientDb = setLoggedIn(responseText);
		// Open the Config Client Action tab
		createActionConfigClientDb(htmlConfigClientDb);
	}
	else
		showResponse(responseText, false);
}


function downloadIspanClick(ev)
{
	ev = getEventProps(ev, butDownload.elem);
	ev.stopPropagation();

	if (blkActConfigClientDb)
		openTab(blkActConfigClientDb);
}


var blkActNewUser;
var fldUsername;
var fldDatabasename;
var fldEmail;
var sRegisterEmail;
var blkRegisterStatus;
var butRegister;
var butDownload;
var txtDownload = null;


function retNewUser(responseText, responseStatus)
{
	if (txtDownload)
	{
		txtDownload.elem.innerHTML = '';
	}
	else
	{
		txtDownload = new Text( { style: { width: '45em', margin: '1em auto 1em auto', 
				'text-align': 'left', 'background-color': '#F1F5F9', color: '#2B4763' } } );
		blkActNewUser.add(txtDownload, blkRegisterStatus);
	}

	if (responseStatus == HTTP_STATUS_OK)
	{
		setLoggedIn(responseText);
		butRegister.setEnabled(false);

		txtDownload.elem.innerHTML = '<p><span style="color: #008000">' +
			'Registration successful.</span> An email with your Login Code has ' +
			'been sent to you. Meanwhile you can continue by downloading ' +
			'ispan and setting up your database.</p>' +
			'<p>If you would rather do that later, you can login at any time with your ' +
			'User Name and Login Code. This connection will automatically timeout in ' +
			'10 minutes unless you click the Download button.</b>';

		butDownload = new Button( { id: 'nuregister', 
			value: '<a href="/download/ispansetup.exe" style="color: #2B4763">Download ispan</a>',
			style: { width: '12em', margin: '2em auto auto auto'  } } );
		blkActNewUser.add(butDownload, blkRegisterStatus);
		butDownload.setEventFuncs([['click', downloadIspanClick ]]);

		createActionClientForm();
		createActionClientSync();

		// Call createActionConfigClientDb() indirectly via login() so that
		// htmlConfigClientDb can be generated by the server with any pre-populated
		// content necessary.
		sCurLoginNode = LOGINNODE_DATABASE;
		sCurAction = LOGINACTION_CONFIGCLIENTDB;
		login();
	}
	else
	{
		sUser = '';
		sDatabase = '';
		sClient = '';
		txtDownload.elem.innerHTML = '<span style="color: #800000">' + responseText + '</span>';
	}
}


function createNewUser(ev)
{
	ev = getEventProps(ev);
	ev.stopPropagation();

	// Validate fields
	if	(	! (sUser = validateLoginField(fldUsername.elem, fldUsername.label, 
				40, regexLetNum, sErrMsgLetNum)) ||
			! (sDatabase = validateLoginField(fldDatabasename.elem, fldDatabasename.label, 
				40, regexLetNum, sErrMsgLetNum)) ||
			! (sRegisterEmail = validateEmailField(fldEmail.elem, fldEmail.label))
		)
	{
		return;
	}

	// At registration, the 1st client is the Master Client and defaults to the same
	// name as the Database. The Master Client can be changed in the Database config 
	// at any time.
	sClient = sDatabase;
	sCurLoginNode = LOGINNODE_NEWUSER;
	sCurAction = LOGINACTION_REGISTER;
	login();
}


function createActionNewUser()
{
	blkActNewUser = new Block( { id: 'actnewuser',
		style: { border: 'none', 'background-color': '#FFFFFF' } } );
	blkActNewUser.tabval = 'New User';
	var txtHeading = new Text( { value: 'Register as a new ispan user',
		style: { 'font-weight': 'bold', border: '1px solid #678EC2', width: '25em', 
		margin: '0.2em auto 0 auto', 'background-color': '#DEE7F1' } } );
	blkActNewUser.add(txtHeading);
	var txtMain = new Text( { value: '<p>View your local database privately from anywhere. ' +
		'Share it with acquaintances or employees. Update it remotely.' +
		'Once you register, you can download ispan to your computer and try ' +
		'it out straight away.</p>' +
		'<p>Please note that you can\'t use spaces in the fields below, ' +
		'only letters or numbers. Names must be 40 characters or less.</b>',
		style: { width: '45em', margin: '1em auto 1em auto', 'text-align': 'left', 
			   'background-color': '#F1F5F9', color: '#2B4763' } } );
	blkActNewUser.add(txtMain);

	var linUsername = new Line({ style: { height: '2em', width: '55em', margin: '1em auto 0 auto',
		backgroundColor: '#F1F5F9', border: '1px solid #A3BBDB' } });
	blkActNewUser.add(linUsername);
	fldUsername = new Field( { id: 'nuusername', label: 'User Name:', labelFormWidth: '13em',
		classname: 'frmfloatright', style: { 'margin-left': '1em', 'margin-top': '0.2em', 
		backgroundColor: '#FFFFFF', borderColor: '#678EC2',  width: '20em' } } );
	linUsername.add(fldUsername);
	var txtUsername = new Text( { value: 'Any name you like. For example ' +
		'<q>fredtheparrot</q> or <q>xyzinc</q>.', style: { width: '30em', padding: '0.3em',
		margin: 'auto auto auto 2em', 'text-align': 'left', color: '#2B4763' } } );
	linUsername.add(txtUsername);
	blkActNewUser.add(linUsername);

	var linDatabasename = new Line({ style: { height: '2em',  width: '55em', margin: '1em auto 0 auto',
		backgroundColor: '#F1F5F9', border: '1px solid #A3BBDB' } });
	blkActNewUser.add(linDatabasename);
	fldDatabasename = new Field( { id: 'nudatabasename', label: 'Database Name:', 
		labelFormWidth: '13em', classname: 'frmfloatright', style: { 'margin-left': '1em', 
		'margin-top': '0.2em',  backgroundColor: '#FFFFFF', borderColor: '#678EC2', 
		width: '20em' } } );
		//width: '20em', float: 'right' } } );
	linDatabasename.add(fldDatabasename);
	var txtDatabasename = new Text( { value: 'Again, any name you like, e.g. ' +
		'<q>mycontacts</q> or <q>accounts</q>.', style: { width: '30em', padding: '0.3em', 
		margin: 'auto auto auto 2em', 'text-align': 'left', color: '#2B4763' } } );
	linDatabasename.add(txtDatabasename);
	blkActNewUser.add(linDatabasename);

	var linEmail = new Line({ style: { height: '2em',  width: '55em', margin: '1em auto 0 auto',
		backgroundColor: '#F1F5F9', border: '1px solid #A3BBDB' } });
	blkActNewUser.add(linEmail);
	fldEmail = new Field( { id: 'nuemail', label: 'Email address:', labelFormWidth: '13em',
		classname: 'frmfloatright', style: { 'margin-left': '1em', 'margin-top': '0.2em', 
		backgroundColor: '#FFFFFF', borderColor: '#678EC2',  width: '20em', float: 'right' } } );
	linEmail.add(fldEmail);
	var txtEmail = new Text( { value: 'The email address to which your logincode should be sent.',
		style: { width: '30em', padding: '0.3em', margin: 'auto auto auto 2em', 'text-align': 'left',
		color: '#2B4763'} } );
	linEmail.add(txtEmail);
	blkActNewUser.add(linEmail);

	butRegister = new Button( { id: 'nuregister', value: 'Register',
		style: { width: '12em', margin: '2em auto auto auto'  } } );
	blkActNewUser.add(butRegister);
	butRegister.setEventFuncs([['click', createNewUser ]]);

	blkRegisterStatus = new Block( { id: 'nustatus', 
		style: { height: '1.5em', 'font-size': '120%', padding: '0.2em', overflow: 'auto',
		color: '#2B4763', margin: '1em 0 1em 0'} } );
	blkActNewUser.add(blkRegisterStatus);

	blkMainActionAct.add(blkActNewUser);
	openTab(blkActNewUser);
}


var blkMainActionAct;


function createMainActionBlock(bNewUser, sOpenTab)
{
	var panAction = document.getElementById('panaction');
	while (panAction.firstChild)
		panAction.removeChild(panAction.firstChild);

	var blkMainAction = new Block( { id: 'mainaction', style: { border: '1px solid #678EC2' } } );
	panAction.appendChild(blkMainAction.elem);
	blkMainActionAct = new Block({ id: 'mainactionact', style: { 
		'background-color': '#CAD8E8', border: 'none', padding: '0.5em' } });
	blkMainAction.add(blkMainActionAct);
	blkMainAction.addTabs(blkMainActionAct);

	if (bNewUser)
	{
		elemOpen('mainpaninit', false);
		createActionNewUser();
		sOpenTab = LOGINACTION_NEWUSER;
		openTab(blkActNewUser);
		return;
	}

	createActionClientForm();

	createActionClientSync();

	if (iLoginLevel < LOGINLEVEL_CLIENT)
	{
		createActionConfigClientDb(null);
	}

	if (iLoginLevel < LOGINLEVEL_DATABASE)
	{
	}

	if (! sOpenTab)
		sOpenTab = LOGINACTION_FORM;
	var form = blkActClientForm;
	switch (sOpenTab)
	{
		case LOGINACTION_CONFIGCLIENTDB: form = blkActConfigClientDb; break;
		case LOGINACTION_SYNC: form = blkActClientSync; break;
	}
	openTab(form);
}


function setMainActionTab(form, bOpen)
{
	// 'form' will replace any previous form with the same id
	blkMainActionAct.replace(form, form);
	if (bOpen)
		openTab(form);
}


function enableNodeButtons()
{
	for (var i = 0; i < 4 && i < arguments.length; i ++)
	{
		if (arguments [i])
		{
			delClass(saNodeButId [i], 'greyed');
			baNodeEnabled [i] = true;
		}
		else
		{
			addClass(saNodeButId [i], 'greyed');
			baNodeEnabled [i] = false;
		}
	}
}


function setActionStatusOpen()
{
	var	sCurNodeButtonId = null;
	sCurNodeButtonId = 'nodebutton' + sCurLoginNode;

	sCurNodeButtonText = getContent(sCurNodeButtonId);
	setContent(sCurNodeButtonId, 'CLOSE');
	replaceClass(sCurNodeButtonId, 'buttonon', 'buttonoff');

	for (i = 0; i < 4; i ++)
	{
		if (sCurNodeButtonId != saNodeButId [i])
			addClass(saNodeButId [i], 'greyed');
	}
	bActionPanelOpen = true;
}


function setActionStatusClosed()
{
	var	sCurNodeButtonId = null;

	sCurNodeButtonId = 'nodebutton' + sCurLoginNode;
	setContent(sCurNodeButtonId, sCurNodeButtonText);

	for (i = 0; i < 4; i ++)
	{
		delClass(saNodeButId [i], 'greyed');
	}
	bActionPanelOpen = false;
}


function setActionSelectionEnabled(bEnabled, sNode, sAction)
{
	var sPanel = sNode + sAction + 'pan';
	var sRadio = sNode + sAction + 'radio';

	if (bEnabled)
	{
		delClass(sPanel, 'greyed');
		delAtt(sRadio, 'disabled');
	}
	else
	{
		addClass(sPanel, 'greyed');
		setAttValue(sRadio, 'disabled', 'disabled');
	}
}


function setLoggedIn(responseText)
{
	// Extract the LoginCode, User, Database and Client returned by login.c
	// and remove the LUDC prefix string from responseText.
	if (responseText && responseText.substring(0, 8) == '<!-- lc=')
	{
		// // Sample LUDC prefix string:
		// <!-- lc=d4ej8nk9 us=abcshoes db=accounts cl=durban -->
		var sLUDC, saLUDC;
		var i;
		var re;
		
		i = responseText.indexOf(' -->');
		if (i == -1)
			return responseText;
		sLUDC = responseText.substring(0, i + 4);
		responseText = responseText.substring(i + 4);
		re = /<!-- lc=(\w*) us=(\w*) db=(\w*) cl=(\w*) -->/;
		saLUDC = sLUDC.match(re);
		if (saLUDC)
		{
			if (saLUDC [1])
				sLoginCode = saLUDC [1]; 
			if (saLUDC [2])
				sUser = saLUDC [2]; 
			if (saLUDC [3])
				sDatabase = saLUDC [3]; 
			if (saLUDC [4])
				sClient = saLUDC [4]; 
		}
	}
	if (sUser && sUser.length != 0)
	{
		delClass('usernamelab', 'greyed');
		setContent('username', sUser);
		elemVisible('username', true);
	}
	else
	{
		addClass('usernamelab', 'greyed');
		setContent('username', '');
		elemVisible('username', false);
	}
	if (sDatabase && sDatabase.length != 0)
	{
		delClass('databasenamelab', 'greyed');
		setContent('databasename', sDatabase);
		elemVisible('databasename', true);
	}
	else
	{
		addClass('databasenamelab', 'greyed');
		setContent('databasename', '');
		elemVisible('databasename', false);
	}
	if (sClient && sClient.length != 0)
	{
		delClass('clientnamelab', 'greyed');
		setContent('clientname', sClient);
		elemVisible('clientname', true);
	}
	else
	{
		addClass('clientnamelab', 'greyed');
		setContent('clientname', '');
		elemVisible('clientname', false);
	}
	// Logged in now - hide Login Code field in all Actions
//	if (sLoginCode)
//		elemMove('loginactcode', elemStore);
	if (sLoginCode.charAt(0) != 'x')
	{
		switch (sCurLoginNode)
		{
			case LOGINNODE_USER: sLastUserLoginCode = sLoginCode; break;
			case LOGINNODE_DATABASE: sLastDatabaseLoginCode = sLoginCode; break;
			case LOGINNODE_INIT:
			case LOGINNODE_CLIENT: sLastClientLoginCode = sLoginCode; break;
		}
	}
	return responseText;
}


//function openLoginCode()
//{
//	sLoginCode = '';
//	setElemValue('logincode', sLoginCode);
//	elemMove('loginactcode', sActionDivId);
//	setFocus('logincode');
//}


function showActionPanel(sNewActionPanId)
{
	// Show the Action Panel for the current Action 
	// Close the current Action Panel and open the new one.
	var sPlace = null;

	if (sCurActionPanId != null && sNewActionPanId != sCurActionPanId)
	{
		elemOpen(sCurActionPanId, false);
		elemOpen(sNewActionPanId, true);
	}
	sCurActionPanId = sNewActionPanId;
	switch(sCurActionPanId)
	{
		case 'pageconfigclientdb': sPlace = 'Client Configuration'; break;
		case 'pageformcreator': sPlace = 'Form Creator'; break;
		case 'pageclientform': sPlace = 'Open Form'; break;
//>>>add the rest - make switch unnecessary by setting sPlace from sCurActionPanId using
// <span class="actiontitle">Client Configuration</span>
	}
	if (sPlace)
		setLocation(sPlace);
}

function downloadclient()
{
	// NOT USED...
	// This function results in the client exe being retrieved by XMLHttpRequest.
	// If a callback function is supplied it gets passed the client exe in the
	// first arg, responseText. It would then be nice to store it on the local
	// drive, and even better if it could then be run. But since we don't know
	// how to do that, or even if it's possible, we must just provide a normal
	// link in the page. This is done by replacing "onclick=downloadclient()"
	// in showNewUserDownloadPage() with a simple link in login.c.
	callServer(sHostDocRoot + '/download/ispansetup.exe', 'GET');
}


function setLoginMsg(sText, sStyle)
{
	if (sStyle == null)
		sStyle = 'info';
	if (set(sText) && sText.length)
		setContent('loginmsg', '<p/><div class="' + sStyle + '">' + sText + '</div>');
	else
		setContent('loginmsg', '');
}


function showResponse(responseText, bHideAction, sStyle)
{
	if (sStyle == null)
		sStyle = 'info';
	// If bHideAction is true, show the response in place of the
	// Action panel, else append the response to the current Action pane.
	if (bHideAction)
	{
		var sNewMainPanId = 'mainpanresponse';

		if (sCurMainPanId == sNewMainPanId)
			return;
		// Hide the current main panel.
		if (sCurLoginNode != null)
			elemOpen(sCurMainPanId, false);
		// Show the Response panel.
		setContent('response', responseText);
		elemOpen(sNewMainPanId, true);
		sCurMainPanId = sNewMainPanId;
	}
	else
	{
		setLoginMsg(responseText, sStyle);
	}
}


function setNeedDatabaseClient(responseText)
{
	// If the user logs in with a Node usercode that is higher than the Action
	// he is trying to perform, and the server cannot determine the Database
	// and/or Client from his usercode (e.g. there is more than one DB for 
	// a User usercode or more than one Client for a Database usercode), then
	// the callback will will be returned an HTTP_STATUS_NEEDMORE status.
	//
	// This function determines which Nodes are missing.
	var sDbCli = responseText, iSpace, bNeed = false;

	// Skip LUDC prefix in responseText
	if (sDbCli.substring(0, 8) == '<!-- lc=')
	{
		// // Sample LUDC prefix string:
		// <!-- lc=d4ej8nk9 us=abcshoes db=accounts cl=durban -->
		var i = sDbCli.indexOf(' -->');
		if (i == -1)
			return false;
		sDbCli = sDbCli.substring(i + 4);
	}
	if	((iSpace = sDbCli.indexOf(' ')) != -1)
	{
		sDbCli = sDbCli.substr(0, iSpace);
		if (sDbCli.indexOf('D') != -1)
			bNeed = bNeedDatabase = true;
		if (sDbCli.indexOf('C') != -1)
			bNeed = bNeedClient = true;
	}
	return bNeed;
}


function loadClientSelect(elemSelect, sDb)
{
	// Load the Client select element for sDb. If sDb is null, use
	// the current Database select element selection. If the Database 
	// select element is empty, use the current database (sDatabase).
	clearSelectElement(elemSelect);
	if (! set(sDb) || ! sDb.length)
	{
		sDb = sDatabase;
		if (! set(sDb) || ! sDb.length)
			return;
	}
	var saClients = saaDatabaseClients [sDb];
	if (saClients)
		loadSelectElement(elemSelect, saClients, '');
}


function loadNodeSelections(xNodeLL)
{
	// xNodeLL contains all Databases for User, and all Clients for each Database.
	// xNodeLL is a list containing zero or more xNodeL lists.
	// An xNodeL list contains a nodetype, a nodename, and an xNodeNaL 
	// A nodetype is either 'user' or 'database'.
	// A nodename is either a username, if the nodetype is 'user', or a 
	// username/databasename if the nodetype is 'database'.
	// An xNodeNaL is a Node Name List that is a list of all child nodes of that 
	// parent nodename.
	// 
	// E.G:
	//
	//	[
	//		[ 'user','parrot', ['accs','stock','cust']]
	//		[ 'database','parrot/accs', ['pta','ctn']]
	//		[ 'database','parrot/stock', ['jhb','ctn','dbn','pe']]
	//		[ 'database','parrot/cust', ['jhb','pta','ctn','dbn']]
	//	]
	//
	// Create the User-Databases Node Selection list and one Database-Clients
	// Node Selection list for each Database.
	var iNextNodeLL = 0;
	//args = { xChild:'', iType:0, bLeaf:false };
	NodeLLArgs = { };

	while (iNextNodeLL = elemxGet(xNodeLL, iNextNodeLL, NodeLLArgs))
	{
		var sNodeType, sNodeName, saNodeNaL = new Array();
		var xNodeL;
		var iNextNodeL = 0, iChild = 0;
		NodeLArgs = { };

		xNodeL = NodeLLArgs.xChild;

		while (iNextNodeL = elemxGet(xNodeL, iNextNodeL, NodeLArgs))
		{
			iChild ++;
			if (NodeLArgs.bLeaf)
			{
				if (iChild == 1)
					sNodeType = NodeLArgs.xChild;
				else if (iChild == 2)
					sNodeName = NodeLArgs.xChild;
				else
				{
					debug('loadNodeSelections: Got > 2 leaf args in [' + xNodeLL + ']');
					return;
				}
			}
			else
			{
				var xNodeNaL;
				var iNextNodeNaL = 0;
				NodeNaLArgs = { };

				xNodeNaL = NodeLArgs.xChild;

				while (iNextNodeNaL = elemxGet(xNodeNaL, iNextNodeNaL, NodeNaLArgs))
					saNodeNaL.push(NodeNaLArgs.xChild);
			}
		}

		// Create the Node Selection list
		if (sNodeType == 'user')
			saUserDatabases = saNodeNaL;
		else if (sNodeType == 'database')
		{
			var sDbName, iSlash;

			if ((iSlash = sNodeName.indexOf('/')) == -1)
			{
				debug('loadNodeSelections: Invalid Db nodename [' + sNodeName + '] in [' + xNodeLL + ']');
				return;
			}
			sDbName = sNodeName.substring(iSlash + 1);
			saaDatabaseClients [sDbName] = saNodeNaL;
		}
		else
		{
			debug('loadNodeSelections: Invalid nodetype [' + sNodeType + '] in [' + xNodeLL + ']');
			return;
		}

	}
	var debugDummy = 0; // Else debugger won't go into above loop
}


function showNodeSelections(bShowClient)
{
	var sNode = LOGINNODE_DATABASE, bContinue = true, bDbShown = false;

	clearSelectElement('actclientname');
	while (bContinue)
	{
		var select, iNonEmptyOptions = 0, sSingleDb = null;

		select = document.getElementById('act' + sNode + 'name');
		if (select.length)
		{
			var i = 0;

			while (i < select.options.length && iNonEmptyOptions < 2)
			{
				if (select.options[i].text.length)
				{
					++ iNonEmptyOptions;
					if (sNode == LOGINNODE_DATABASE)
					{
						if (iNonEmptyOptions == 1)
							sSingleDb = select.options[i].text;
						else
							sSingleDb = null;
					}
				}
				++ i;
			}
		}
		if (iNonEmptyOptions > 1 || bDbShown)
		{
			elemMove('loginact' + sNode, sActionDivId);
			select.selectedIndex = 0;
			if (sNode == LOGINNODE_DATABASE)
				bDbShown = true;
		}
		if (sNode == LOGINNODE_DATABASE && bShowClient)
		{
			sNode = LOGINNODE_CLIENT;
			if (! bDbShown)
			{
				if (! sSingleDb)
					sSingleDb = sDatabase;
				loadClientSelect('actclientname', sSingleDb);
			}
		}
		else
			bContinue = false;
	}
	var debugDummy = 0; // Else debugger won't go into above loop
}


function retInitLogin(responseText, responseStatus)
{
	if (responseStatus == HTTP_STATUS_OK || responseStatus == HTTP_STATUS_CREATED)
	{
		responseText = setLoggedIn(responseText);
		loadNodeSelections(responseText);
		//loadSelectElement('actdatabasename', saUserDatabases, '');
		if (sClient.length)
			sNewLoginNode = LOGINNODE_CLIENT;
		else if (sDatabase.length)
			sNewLoginNode = LOGINNODE_DATABASE;
		else if (sUser.length)
			sNewLoginNode = LOGINNODE_USER;
		else
			sNewLoginNode = LOGINNODE_INIT;
		sNewAction = null;
		setLoginNode(sNewLoginNode, null);

		elemOpen('mainpaninit', false);

		var sOpenAction = null;
		if	(	responseStatus == HTTP_STATUS_CREATED &&
				(sNewLoginNode == LOGINNODE_DATABASE || sNewLoginNode == LOGINNODE_DATABASE)
			)
			sOpenAction = LOGINACTION_CONFIGCLIENTDB;

		createMainActionBlock(false, sOpenAction);
	}
	else if (responseStatus == HTTP_STATUS_INVALIDDATA) 
	{
		enableNodeButtons(true, true, true, true);
		setLoggedIn(responseText);
		showResponse(responseText, false, 'info');
	}
	else
		showResponse(responseText, false, 'error');
}


function retDbConfigDb(responseText, responseStatus)
{
	if (responseStatus == HTTP_STATUS_OK)
	{
		setLoggedIn(responseText);
		sConfigDbResponseText = responseText;
		showActionPanel('pageform');
		setActionStatusOpen();
		loadResource('/script/configdb.js', 'script', 'text/javascript', 
			'cfdbInit', 'bConfigDbLoaded', null);
	}
	else
		showResponse(responseText, false);
}


function retDbConfigScript(responseText, responseStatus)
{
	if (responseText == null || responseStatus == HTTP_STATUS_OK)
	{
		// If responseText is null the script is already loaded
		if (responseText != null)
			setScriptText('configclientdb.js', responseText)

		cfgInit();
	}
	else
	{
		popup('loadScript returned status: ' + responseStatus + ' : ' + responseText, C_ERROR);
		return false;
	}
}


function configClientdb()
{
	// Called from responseText in retInitLogin or retClientSync() 
	// or retNewClient() via login.c

	// This method opens the DbAdmin page for the user to click the Configure Client button
	//setLoginNode(LOGINNODE_DATABASE, LOGINACTION_CONFIGCLIENTDB);
	//setActionSelectionEnabled(false, LOGINNODE_DATABASE, LOGINACTION_CONFIGDB)
	//setActionSelectionEnabled(false, LOGINNODE_DATABASE, LOGINACTION_NEWCLIENT)
	//setActionSelectionEnabled(false, LOGINNODE_DATABASE, LOGINACTION_LOADDBSKEL)

	// This method logs in directly to the Configure Client page
	// after first opening the Database node panel and ConfigClientDb Action
	setLoginNode(LOGINNODE_DATABASE, LOGINACTION_CONFIGCLIENTDB);
	login();
}


function retNewClient(responseText, responseStatus)
{
	if (responseStatus == HTTP_STATUS_OK)
	{
		setLoggedIn(responseText);
		showResponse(responseText, false);
		setActionStatusOpen();
	}
	else if (responseStatus == HTTP_STATUS_NEEDMORE)
	{
		if (! setNeedDatabaseClient(responseText))
		{
			log('retNewClient.setNeedDatabaseClient: false, response: [' + responseText + ']');
			return;
		}
		// Need Database and/or Client entered manually.
		login();
	}
	else
		showResponse(responseText, false);
}


//function retClientSyncScript(responseText, responseStatus)
//{
//	if (responseText == null || responseStatus == HTTP_STATUS_OK)
//	{
//		// If responseText is null the script is already loaded
//		if (responseText != null)
//			setScriptText('clientsync.js', responseText)
//
//		runWhenReady("csInit", ["bClientSyncLoaded", "bChannelLoaded"]);
//		//csInit();
//	}
//	else
//	{
//		popup('loadResource returned status: ' + responseStatus + ' : ' + responseText);
//		return false;
//	}
//}


function retLoadDbSkel(responseText, responseStatus)
{
	if (responseStatus == HTTP_STATUS_OK)
	{
		setLoggedIn(responseText);
		// Show the Load Database Skeleton Action panel
		showActionPanel('pageloaddbskel');
		// Set its content to the loaddbskel.html page sent by login.c
		setContent('pageloaddbskel', responseText);
		// Load the loaddbskel.js functions
		loadResource('/script/loaddbskel.js', 'script', 'text/javascript',
			'skelInit', ['bLoadDbSkelLoaded', 'bChannelLoaded'], null);
			//bOldIE ? retClientSyncScript : null);
		setActionStatusOpen();
	}
	else if (responseStatus == HTTP_STATUS_NEEDMORE)
	{
		if (! setNeedDatabaseClient(responseText))
		{
			log('retLoadDbSkel.setNeedDatabaseClient: false, response: [' + responseText + ']');
			return;
		}
		// Need Database and/or Client entered manually.
		login();
	}
	else
		showResponse(responseText, false);
}


function retFormCreator(responseText, responseStatus)
{
	if (responseStatus == HTTP_STATUS_OK)
	{
		setLoggedIn(responseText);
		// Show the Form Creator Action panel
		showActionPanel('pageformcreator');

		// Load the formcreator.js functions
		//loadResource('/script/formcreator.js', 'script', 'text/javascript',
		//	'fcInit', 'bFormCreatorLoaded', null);
		//bOldIE ? retFormCreatorScript : null);
		fcInit();

testForm();

		setActionStatusOpen();
	}
	else
		showResponse(responseText, false);
}


function retClientLog(responseText, responseStatus)
{
	if (responseStatus == HTTP_STATUS_NOTFOUND)
	{
		// Auto-login with OneTimeCode failed. Need the user to enter the LoginCode manually.
		showResponse(responseText, false);
	}
	else if (responseStatus == HTTP_STATUS_OK)
	{
		setLoggedIn(responseText);
		showResponse(responseText, true);
		// Load the sql script
		loadResource('/script/sql.js', 'script', 'text/javascript', null, null, null);
		// Show the Log page
		loadResource('/script/log.js', 'script', 'text/javascript',
			'logViewClientLog', [ bSqlLoaded, bLogLoaded ], null);
			//bOldIE ? retClientLogScript : null);
		setActionStatusOpen();
	}
	else
		showResponse(responseText, false);
}


function retServerTime(responseText, responseStatus)
{
	var saRetVal;
	var iHostTime;

	if (responseStatus == HTTP_STATUS_OK)
	{
		var date = new Date();

		saRetVal = rpcGetRetVal(responseText);
		if (saRetVal && saRetVal [0])
		{
			iHostTime = Number(saRetVal [0]);
			// Test for reasonable value
			if (iHostTime > 1218189600 && iHostTime < 2147483647)
				iSrvrTimeDif = date.getTime() - (iHostTime * 1000);
		}
	}
}


function retLogin(responseText, responseStatus)
{
	// Default callback - shouldn't ever get called if login() is coded OK
}


function validateLoginField(elem, sFieldLabel, iMaxLen, regex, sErrMsg)
{
	var	sError = '', sFieldValue;

	if ((sFieldValue = getElemValue(elem)) == null)
		return false;
	sFieldValue = sFieldValue.toLowerCase();
	//setAttValue(elem, 'value', sFieldValue);
	setElemValue(elem, sFieldValue);
	if (sFieldValue == '')
		sError = 'Please enter your ' + sFieldLabel;
	else if (sFieldValue.indexOf(' ') != -1)
		sError = 'Your ' + sFieldLabel + ' must not contain any spaces.';
	else if (sFieldValue.length > iMaxLen)
		sError = 'Your ' + sFieldLabel + ' exceeds ' + iMaxLen + ' characters.';
	else if (sFieldValue.search(regex) != -1)
		sError = 'Your ' + sFieldLabel + ' ' + sErrMsg;
	if (sError != '')
	{
		setStatus(sError, 'error');
		return false;
	}
	return sFieldValue;
}


function validateEmailField(elem, sFieldLabel)
{
	var	sError = '', sFieldValue;

	if ((sFieldValue = getElemValue(elem)) == null)
		return false;
	//setAttValue(elem, 'value', sFieldValue.toLowerCase())
	setElemValue(elem, sFieldValue.toLowerCase());
	if (sFieldValue == '')
		sError = ' is blank.';
	else if (sFieldValue.indexOf(' ') != -1)
		sError = ' must not contain any spaces. ';
	else if (sFieldValue.search(/^[0-9a-z@.-_]+$/) == -1)
		sError = ' contains invalid characters.';
	else if (	sFieldValue.search(/^.+@.+[.].+$/) == -1 ||
				sFieldValue.charAt(0) == '.' ||
				sFieldValue.charAt(sFieldValue.length - 1) == '.'
			)
		sError = ' is not in a valid address format.';
	if (sError != '')
	{
		setStatus('Your ' + sFieldLabel + sError, 'error');
		return false;
	}
	return sFieldValue;
}


function loginEnd()
{
	// Called by <body ... onunload()>
}


function login()
{
	var	sLoginNodeAction = sCurLoginNode + sCurAction;
	var iNodeLevel;
	var	funcCallback = retLogin;
	// What was this used for?
	//var bOpenClientChannel = false;
	var sActEmail = '';
	var bGetSelectedDatabase = false;
	var bGetSelectedClient = false;
	var sEnterPrompt = '';
	var selDatabase, selClient;

// TEST
//retFormCreator('', HTTP_STATUS_OK);
//if (sLoginCode = getElemValue('logincode'))
//	testForm();
//return;


	setLoginMsg('', null);

	// ------------ Login Code -----------------
	if (sCurLoginNode == LOGINNODE_NEWUSER)
	{
		iLoginLevel = LOGINLEVEL_NEWUSER;
		//if	(	! (sUser = validateLoginField('actnewusername', 40, regexLetNum, sErrMsgLetNum)) ||
		//		! (sDatabase = validateLoginField('actnewdatabasename', 40, regexLetNum, sErrMsgLetNum)) ||
		//		! (sClient = validateLoginField('actnewclientname', 40, regexLetNum, sErrMsgLetNum)) ||
		//		! (sActEmail = validateEmailField('actemail'))
		//	)
		//{
		//	return;
		//}
	}
	else
	{
		if (! sLoginCode.length)
		{
			// Get the Login Code
			var sFieldLabel = getContent('logincodelabel');
			if (! (sLoginCode = validateLoginField('logincode', sFieldLabel, 20, 
					regexLetNum, sErrMsgLetNum)))
				return;
		}
		// Get the Login Level
		iLoginLevel = 0;
		switch (sLoginCode.charAt(0))
		{
			case 'u':	iLoginLevel = LOGINLEVEL_USER; break;
			case 'd':	iLoginLevel = LOGINLEVEL_DATABASE; break;
			case 'c':	
			// OneTimeCode sent by client
			case 'x':	iLoginLevel = LOGINLEVEL_CLIENT; break;
		}
		if (! iLoginLevel)
		{
			setLoginMsg('Your Login Code is invalid', 'error');
			sLoginCode = '';
			setElemValue('logincode', '');
			return;
		}

		// Set the Node Level
		switch (sCurLoginNode)
		{
			case LOGINNODE_INIT: iNodeLevel = LOGINLEVEL_INIT; break;
			case LOGINNODE_USER: iNodeLevel = LOGINLEVEL_USER; break;
			case LOGINNODE_DATABASE: iNodeLevel = LOGINLEVEL_DATABASE; break;
			case LOGINNODE_CLIENT: iNodeLevel = LOGINLEVEL_CLIENT; break;
		}

		// If the Login Code Level is lower (greater than) than the Login Node, reject the LoginCode
		if (iLoginLevel > iNodeLevel)
		{
			var sOrDbAdmin = '';

			if (iNodeLevel > LOGINLEVEL_USER)
				sOrDbAdmin = ' or Database Admin ';
			setLoginMsg('Login Code has no authority for this action. ' +
				'Please log in with the User ' + sOrDbAdmin + ' Login Code.', 'error');
			return;
		}

		// Set sLoginLevel, used to display the location bar by main.js
		// Close any open Action Database or Action Client that are not needed as a result of the user
		// changing their LoginCode.
		if	(iLoginLevel == LOGINLEVEL_USER)
			sLoginLevel = LOGINNODE_USER;
		else if	(iLoginLevel == LOGINLEVEL_DATABASE)
		{
			sLoginLevel = LOGINNODE_DATABASE;
//			elemMove('loginactdatabase', elemStore);
		}
		else if	(iLoginLevel == LOGINLEVEL_CLIENT)
		{
			sLoginLevel = LOGINNODE_CLIENT;
//			elemMove('loginactclient', elemStore);
		}

		// If bNeedDatabase or bNeedClient is set, either because the server has requested the 
		// Database and/or the Client Nodes by responding to the 1st login call with 
		// HTTP_STATUS_NEEDMORE, or because bNeedDatabase or bNeedClient was set in setAction(),
		// show the Node entry field. If the Node is already set, show it in the field, else 
		// prompt for it.

		if (bNeedDatabase && (! set(sDatabase) || sDatabase.length == 0))
		{
			bGetSelectedDatabase = true;
			selDatabase = document.getElementById('actdatabasename');
			if (selDatabase.selectedIndex <= 0)
			{
				if (sDatabase.length != 0)
					setSelectedOption('actdatabasename', sDatabase);
				else
				{
					sEnterPrompt = 'Please select the Database';
					bGetSelectedDatabase = false;
				}
			}
		}
		if (bNeedClient && (! set(sClient) || sClient.length == 0))
		{
			bGetSelectedClient = true;
			selClient = document.getElementById('actclientname');
			if (selClient.selectedIndex <= 0)
			{
				if (sClient.length != 0)
					setSelectedOption('actclientname', sClient);
				else
				{
					if (sEnterPrompt.length == 0)
						sEnterPrompt = 'Please select';
					else
						sEnterPrompt += ' and';
					sEnterPrompt += ' the Login name';
					bGetSelectedClient = false;
				}
			}
		}

		if (sEnterPrompt.length != 0)
		{
			setLoginMsg(sEnterPrompt, 'info');
			return;
		}
	}

	if (bGetSelectedDatabase)
		sDatabase = selDatabase.options[selDatabase.selectedIndex].text;
	if (bGetSelectedClient)
		sClient = selClient.options[selClient.selectedIndex].text;


	var saRequest = new Array();
	var iReq = 0;
	saRequest [iReq ++] = 'loginnode';
	saRequest [iReq ++] = sCurLoginNode;
	saRequest [iReq ++] = 'action';
	saRequest [iReq ++] = sCurAction;
	if (sCurLoginNode != LOGINNODE_NEWUSER)
	{
		saRequest [iReq ++] = 'logincode';
		saRequest [iReq ++] = sLoginCode;
	}

	if (sCurLoginNode == LOGINNODE_DATABASE || sCurLoginNode == LOGINNODE_CLIENT || 
		sCurLoginNode == LOGINNODE_NEWUSER)
	{
		if (iLoginLevel == LOGINLEVEL_USER || iLoginLevel == LOGINLEVEL_NEWUSER)
		{
			saRequest [iReq ++] = 'actiondatabase';
			saRequest [iReq ++] = sDatabase;
		}
		if (iLoginLevel == LOGINLEVEL_USER || iLoginLevel == LOGINLEVEL_DATABASE || 
			iLoginLevel == LOGINLEVEL_NEWUSER)
		{
			saRequest [iReq ++] = 'actionclient';
			saRequest [iReq ++] = sClient;
		}
	}

	//if (sCurLoginNode == LOGINNODE_CLIENT)
	//	bOpenClientChannel = true;

	switch (sLoginNodeAction)
	{
		case LOGINNODE_INIT + LOGINACTION_LOGIN :
			sLoginCode = '';
			sUser = '';
			sDatabase = '';
			sClient = '';
			funcCallback = retInitLogin;
			break;
		case LOGINNODE_USER + LOGINACTION_CONFIGUSER :
			break;
		case LOGINNODE_USER + LOGINACTION_NEWDB :
			break;
		case LOGINNODE_DATABASE + LOGINACTION_CONFIGDB :
			funcCallback = retDbConfigDb;
			break;
		case LOGINNODE_DATABASE + LOGINACTION_CONFIGCLIENTDB :
			funcCallback = retConfigClientDb;
			//bOpenClientChannel = true;
			break;
		case LOGINNODE_DATABASE + LOGINACTION_NEWCLIENT :
			if (! (sActEmail = validateEmailField('actemail')))
				return;
			saRequest [iReq ++] = 'actionemail';
			saRequest [iReq ++] = sActEmail;
			funcCallback = retNewClient;
			break;
		case LOGINNODE_DATABASE + LOGINACTION_LOADDBSKEL :
			funcCallback = retLoadDbSkel;
			//bOpenClientChannel = true;
			break;
		case LOGINNODE_DATABASE + LOGINACTION_FORMCREATOR :
			funcCallback = retFormCreator;
			//bOpenClientChannel = true;
			break;
		//case LOGINNODE_CLIENT + LOGINACTION_SYNC :
		//	funcCallback = retClientSync;
		//	break;
		//case LOGINNODE_CLIENT + LOGINACTION_FORM :
		//	funcCallback = retClientForm;
		//	break;
		case LOGINNODE_CLIENT + LOGINACTION_VIEWLOG :
			funcCallback = retClientLog;
			break;
		case LOGINNODE_NEWUSER + LOGINACTION_REGISTER :
			saRequest [iReq ++] = 'actionemail';
			saRequest [iReq ++] = sRegisterEmail;
			saRequest [iReq ++] = 'actionuser';
			saRequest [iReq ++] = sUser;
			funcCallback = retNewUser;
			break;
	}

	callServer(sHostDocRoot + '/bin/login.cgi', 'POST', saRequest, funcCallback);
}


function MyFunc()
{
	var x = 1;
	if (x == 1)
		return 1;
	else
		return 9;
}
function MyObj()
{
	this.s = 'abcdef';
	this.MyFunc = MyFunc;
	this.a = ['qqq','www'];
	this.i = 123;
}

var bOldIE = false, bIE = false;

function loginInit()
{
	var saDefaultParams = new Array();
	var i;

	if (navigator.appName.indexOf('Explorer') != -1)
	{
		bIE = true;
		var ua = navigator.userAgent;
		var re = /MSIE\s+([^\);]+)(\)|;)/;
		re.test(ua);
		var version = Number(RegExp.$1);
		if (version < 8)
			bOldIE = true;
	}

	// Init the Form system
	frmInit();

	elemStore = document.getElementById('elemstore');
	logring = document.getElementById('logring');
	panStatus = document.getElementById('panstatus');
	panDebug = document.getElementById('pandebug');

	// Set the origin URL for this web page for use by XMLHttpRequest
	if (document.documentURI)
		sHostDocRoot = document.documentURI;
	else
		sHostDocRoot = document.URL;
	if	(	(i = sHostDocRoot.indexOf('//')) != -1 &&
			(i = sHostDocRoot.indexOf('/', i + 2)) != -1
		)
		sHostDocRoot = sHostDocRoot.substr(0, i);

	// Set the time to the server time.
	rpc('time', null, retServerTime);

	// Load scripts
	loadResource('script/channel.js', 'script', 'text/javascript', 
			'monitorClientChannel', 'bChannelLoaded', null);

	// Load any query string params
	loadQueryStringParams(saDefaultParams);
	// Action the params
	sUser = '';
	sDatabase = '';
	sClient = '';
	sLoginLevel = '';
	if (saQueryStringParams ['logincode'])
	{
		sLoginCode = saQueryStringParams ['logincode'];
		setElemValue('logincode', sLoginCode);
	}

	// Disable all node buttons until we have a valid login
	enableNodeButtons(false, false, false, true);

	if (sLoginCode.length)
	{
		// Don't fake the login just because the PcClient has logged in OK
		// and passed the onetime logincode plus U/D/C details. Actually login
		// properly so the onetime code gets resolved to the real code and allows
		// monitorClientChannel() to call rpc() for ping, etc.
		switch (sLoginCode.charAt(0))
		{
			case 'u':	sCurLoginNode = LOGINNODE_USER; break;
			case 'd':	sCurLoginNode = LOGINNODE_DATABASE; break;
			case 'c':	
			// OneTimeCode sent by client
			case 'x':	sCurLoginNode = LOGINNODE_CLIENT; break;
		}
		setLoggedIn(null);

		// Call setLoginNode() so that a default login panel gets displayed.
		// Use LOGINNODE_INIT to avoid picking a particular Node. But LOGINNODE_INIT
		// clears the Login Code field, so save & restore it.
		var sSaveloginCode = sLoginCode;
		setLoginNode(LOGINNODE_INIT, LOGINACTION_LOGIN);
		sLoginCode = sSaveloginCode;

		login();
	}
	else
		setLoginNode(LOGINNODE_INIT, LOGINACTION_LOGIN);
}

