/**
 * Global variables
 */
var nodesTabs; // Node tabs
var nodesDataTable; // Datatable containing all nodes within a group

/**
 * Set the nodes tab
 * 
 * @param obj
 *            Tab object
 * @return Nothing
 */
function setNodesTab(obj) {
	nodesTabs = obj;
}

/**
 * Get the nodes tab
 * 
 * @param Nothing
 * @return Tab object
 */
function getNodesTab() {
	return nodesTabs;
}

/**
 * Get the nodes datatable
 * 
 * @param Nothing
 * @return Data table object
 */
function getNodesDataTable() {
	return nodesDataTable;
}

/**
 * Set the nodes datatable
 * 
 * @param table
 *            Data table object
 * @return Nothing
 */
function setNodesDataTable(table) {
	nodesDataTable = table;
}

/**
 * Load nodes page
 * 
 * @return Nothing
 */
function loadNodesPage() {
	// If groups are not already loaded
	if (!$('#groups').length) {
		// Create a groups division
		groupDIV = $('<div id="groups"></div>');
		nodesDIV = $('<div id="nodes"></div>');
		$('#nodes_page').append(groupDIV);
		$('#nodes_page').append(nodesDIV);

		// Create info bar
		var info = createInfoBar('Select a group to view its nodes');
		$('#nodes').append(info);

		// Get groups
		$.ajax( {
			url : 'lib/cmd.php',
			dataType : 'json',
			data : {
				cmd : 'extnoderange',
				tgt : '/.*',
				args : 'subgroups',
				msg : ''
			},

			success : loadGroups
		});
	}
}

/**
 * Load groups
 * 
 * @param data
 *            Data returned from HTTP request
 * @return
 */
function loadGroups(data) {
	var groups = data.rsp;
	setGroupsCookies(data);

	// Create a list of groups
	var ul = $('<ul></ul>');
	var item = $('<li><ins></ins><h3>Groups</h3></li>');
	ul.append(item);
	var subUL = $('<ul></ul>');
	item.append(subUL);

	// Create a link for each group
	for ( var i = groups.length; i--;) {
		var subItem = $('<li></li>');
		var link = $('<a href="#"><ins></ins>' + groups[i] + '</a>');

		subItem.append(link);
		subUL.append(subItem);
	}

	// Turn groups list into a tree
	$('#groups').append(ul);
	$('#groups').tree( {
		callback : {
			// Open the group onclick
		onselect : function(node, tree) {
			var thisGroup = tree.get_text(node);
			if (thisGroup) {
				// Clear the nodes DIV
				$('#nodes').children().remove();
				// Create loader
				var loader = $('<center></center>').append(createLoader());

				// Create a tab for this group
				var tab = new Tab();
				setNodesTab(tab);
				tab.init();
				$('#nodes').append(tab.object());
				tab.add('nodesTab', 'Nodes', loader);

				// Get nodes within selected group
				$.ajax( {
					url : 'lib/cmd.php',
					dataType : 'json',
					data : {
						cmd : 'lsdef',
						tgt : '',
						args : thisGroup,
						msg : thisGroup
					},

					success : loadNodes
				});
			} // End of if (thisGroup)
		} // End of onselect
	}
// End of callback
}   );
}

/**
 * Load nodes belonging to a given group
 * 
 * @param data
 *            Data returned from HTTP request
 * @return Nothing
 */
function loadNodes(data) {
	// Data returned
	var rsp = data.rsp;
	// Group name
	var group = data.msg;
	// Node attributes hash
	var attrs = new Object();
	// Node attributes
	var headers = new Object();

	var node;
	var args;
	for ( var i in rsp) {
		// Get the node
		var pos = rsp[i].indexOf('Object name:');
		if (pos > -1) {
			var temp = rsp[i].split(': ');
			node = jQuery.trim(temp[1]);

			// Create a hash for the node attributes
			attrs[node] = new Object();
			i++;
		}

		// Get key and value
		args = rsp[i].split('=');
		var key = jQuery.trim(args[0]);
		var val = jQuery.trim(args[1]);

		// Create a hash table
		attrs[node][key] = val;
		headers[key] = 1;
	}

	// Sort headers
	var sorted = new Array();
	for ( var key in headers) {
		sorted.push(key);
	}
	sorted.sort();

	// Add column for check box, node, ping, and power
	sorted.unshift('', 'node', 'ping', 'power');

	// Create a datatable
	var dTable = new DataTable('nodesDataTable');
	dTable.init(sorted);

	// Go through each node
	for ( var node in attrs) {
		// Create a row
		var row = new Array();
		// Create a check box
		var checkBx = '<input type="checkbox" name="' + node + '"/>';
		// Open node onclick
		var nodeLink = $(
			'<a class="node" id="' + node + '" href="#">' + node + '</a>')
			.bind('click', loadNode);
		row.push(checkBx, nodeLink, '', '');

		// Go through each header
		for ( var i = 4; i < sorted.length; i++) {
			// Add the node attributes to the row
			var key = sorted[i];
			var val = attrs[node][key];
			if (val) {
				row.push(val);
			} else {
				row.push('');
			}
		}

		// Add the row to the table
		dTable.add(row);
	}

	// Clear the tab before inserting the table
	$('#nodesTab').children().remove();

	// Create action buttons
	var actionBar = $('<div class="actionBar"></div>');

	/**
	 * The following actions are available to perform against a given node:
	 * power, clone, delete, unlock, and advanced
	 */

	/*
	 * Power
	 */
	var powerLnk = $('<a href="#">Power</a>');

	/*
	 * Power on
	 */
	var powerOnLnk = $('<a href="#">Power on</a>');
	powerOnLnk.bind('click', function(event) {
		var tgtNodes = '';

		// Get node that was checked
		var nodes = $('#nodesDataTable input[type=checkbox]:checked');
		for ( var i = 0; i < nodes.length; i++) {
			tgtNodes += nodes.eq(i).attr('name');

			// Add a comma in front of each node
		if (i < nodes.length - 1) {
			tgtNodes += ',';
		}
	}

	if (tgtNodes) {
		powerNode(tgtNodes, 'on');
	}
}   );

	/*
	 * Power off
	 */
	var powerOffLnk = $('<a href="#">Power off</a>');
	powerOffLnk.bind('click', function(event) {
		var tgtNodes = '';

		// Get node that was checked
		var nodes = $('#nodesDataTable input[type=checkbox]:checked');
		for ( var i = 0; i < nodes.length; i++) {
			tgtNodes += nodes.eq(i).attr('name');

			// Add a comma in front of each node
		if (i < nodes.length - 1) {
			tgtNodes += ',';
		}
	}

	if (tgtNodes) {
		powerNode(tgtNodes, 'off');
	}
}   );

	/*
	 * Clone
	 */
	var cloneLnk = $('<a href="#">Clone</a>');
	cloneLnk.bind('click', function(event) {
		// Get node that was checked
		var nodes = $('#nodesDataTable input[type=checkbox]:checked');
		for ( var i = 0; i < nodes.length; i++) {
			var node = nodes.eq(i).attr('name');

			// Load clone page
		if (node) {
			var mgt = getNodeMgt(node);
			if (mgt == 'zvm') {
				loadZClonePage(node);
			} else {
				// TODO: Add clone for other platforms
			}
		}
	}
}   );

	/*
	 * Delete
	 */
	var deleteLnk = $('<a href="#">Delete</a>');
	deleteLnk.bind('click', function(event) {
		var tgtNodes = '';

		// Get node that was checked
		var nodes = $('#nodesDataTable input[type=checkbox]:checked');
		for ( var i = 0; i < nodes.length; i++) {
			tgtNodes += nodes.eq(i).attr('name');

			// Add a comma in front of each node
		if (i < nodes.length - 1) {
			tgtNodes += ',';
		}
	}

	// Load delete page
	if (tgtNodes) {
		deleteNode(tgtNodes);
	}
}   );

	/*
	 * Unlock
	 */
	var unlockLnk = $('<a href="#">Unlock</a>');
	unlockLnk.bind('click', function(event) {
		var tgtNodes = '';

		// Get node that was checked
		var nodes = $('#nodesDataTable input[type=checkbox]:checked');
		for ( var i = 0; i < nodes.length; i++) {
			tgtNodes += nodes.eq(i).attr('name');

			// Add a comma in front of each node
		if (i < nodes.length - 1) {
			tgtNodes += ',';
		}
	}

	// Load unlock page
	if (tgtNodes) {
		loadUnlockPage(tgtNodes);
	}
}   );

	/*
	 * Run script
	 */
	var scriptLnk = $('<a href="#">Run script</a>');
	scriptLnk.bind('click', function(event) {
		// Get node that was checked
		var tgtNodes = '';
		var nodes = $('#nodesDataTable input[type=checkbox]:checked');
		for ( var i = 0; i < nodes.length; i++) {
			tgtNodes += nodes.eq(i).attr('name');

			// Add a comma in front of each node
		if (i < nodes.length - 1) {
			tgtNodes += ',';
		}
	}

	// Load script page
	if (tgtNodes) {
		loadScriptPage(tgtNodes);
	}
}   );

	/*
	 * Update node
	 */
	var updateLnk = $('<a href="#">Update</a>');
	updateLnk.bind('click', function(event) {
		// Get node that was checked
		var tgtNodes = '';
		var nodes = $('#nodesDataTable input[type=checkbox]:checked');
		for ( var i = 0; i < nodes.length; i++) {
			tgtNodes += nodes.eq(i).attr('name');

			// Add a comma in front of each node
		if (i < nodes.length - 1) {
			tgtNodes += ',';
		}
	}

	// TODO: Load update page
	if (tgtNodes) {

	}
}   );

	/*
	 * Set boot state
	 */
	var setBootStateLnk = $('<a href="#">Set boot state</a>');
	setBootStateLnk.bind('click', function(event) {
		// Get node that was checked
		var nodes = $('#nodesDataTable input[type=checkbox]:checked');
		for ( var i = 0; i < nodes.length; i++) {
			// Get node that was checked
		var tgtNodes = '';
		var nodes = $('#nodesDataTable input[type=checkbox]:checked');
		for ( var i = 0; i < nodes.length; i++) {
			tgtNodes += nodes.eq(i).attr('name');

			// Add a comma in front of each node
			if (i < nodes.length - 1) {
				tgtNodes += ',';
			}
		}

		// Load nodeset page
		if (tgtNodes) {
			loadNodesetPage(tgtNodes);
		}
	}
}   );

	/*
	 * Boot to network
	 */
	var boot2NetworkLnk = $('<a href="#">Boot to network</a>');
	boot2NetworkLnk.bind('click', function(event) {
		// Get node that was checked
		var nodes = $('#nodesDataTable input[type=checkbox]:checked');
		for ( var i = 0; i < nodes.length; i++) {
			// Get node that was checked
		var mgt;
		var tgtNodes = '';
		var nodes = $('#nodesDataTable input[type=checkbox]:checked');
		for ( var i = 0; i < nodes.length; i++) {
			tgtNodes += nodes.eq(i).attr('name');

			// Add a comma in front of each node
			if (i < nodes.length - 1) {
				tgtNodes += ',';
			}

			var node = nodes.eq(i).attr('name');
			mgt = getNodeMgt(node);
		}

		// Load nodeset page
		if (tgtNodes) {
			if (mgt == 'zvm') {
				loadZNetbootPage(tgtNodes);
			} else {
				// TODO: Add boot to network for other platforms
			}
		}
	}
}   );

	/*
	 * Advanced
	 */
	var advancedLnk = $('<a href="#">Advanced</a>');

	// Power actions
	var powerActions = [ powerOnLnk, powerOffLnk ];
	var powerActionMenu = createMenu(powerActions);

	// Advanced actions
	var advancedActions = [ boot2NetworkLnk, scriptLnk, setBootStateLnk,
		updateLnk ];
	var advancedActionMenu = createMenu(advancedActions);

	/**
	 * Create an action menu
	 */
	var actionsDIV = $('<div></div>');
	var actions = [ [ powerLnk, powerActionMenu ], cloneLnk, deleteLnk,
		unlockLnk, [ advancedLnk, advancedActionMenu ] ];
	var actionMenu = createMenu(actions);
	actionMenu.superfish();
	actionsDIV.append(actionMenu);
	actionBar.append(actionsDIV);

	/*
	 * Select all or none
	 */
	var selectDIV = $('<div></div>');
	actionBar.append(selectDIV);

	var selectLabel = $('<span>Select: </span>');
	var selectAllLnk = $('<span><a href="#">All</a></span>');
	selectAllLnk.bind('click', function(event) {
		// Check all nodes
		var nodes = $('#nodesDataTable input[type=checkbox]');
		nodes.attr('checked', true);
	});

	var selectNoneLnk = $('<span><a href="#">None</a></span>');
	selectNoneLnk.bind('click', function(event) {
		// Check no nodes
		var nodes = $('#nodesDataTable input[type=checkbox]');
		nodes.attr('checked', false);
	});

	selectDIV.append(selectLabel);
	selectDIV.append(selectAllLnk);
	selectDIV.append(selectNoneLnk);

	$('#nodesTab').append(actionBar);

	// Insert table
	$('#nodesTab').append(dTable.object());

	// Turn table into a datatable
	var myDataTable = $('#nodesDataTable').dataTable();
	setNodesDataTable(myDataTable);

	/**
	 * Get power and ping status for each node
	 */

	// Get the power status
	$.ajax( {
		url : 'lib/cmd.php',
		dataType : 'json',
		data : {
			cmd : 'rpower',
			tgt : group,
			args : 'stat',
			msg : ''
		},

		success : loadPowerStatus
	});

	// Get the ping status
	$.ajax( {
		url : 'lib/cmd.php',
		dataType : 'json',
		data : {
			cmd : 'webrun',
			tgt : '',
			args : 'pping ' + group,
			msg : ''
		},

		success : loadPingStatus
	});

	/**
	 * Only for zVM
	 */

	// Get the index of the HCP column
	var i = $.inArray('hcp', sorted);
	if (i) {
		var rows = dTable.object().find('tbody tr');

		// Get HCP
		var hcps = new Object();
		for ( var j = 0; j < rows.length; j++) {
			var val = rows.eq(j).find('td').eq(i).html();
			hcps[val] = 1;
		}

		var args;
		for ( var h in hcps) {
			// Get node without domain name
			args = h.split('.');

			// Get disk pools
			$.ajax( {
				url : 'lib/cmd.php',
				dataType : 'json',
				data : {
					cmd : 'lsvm',
					tgt : args[0],
					args : '--diskpoolnames',
					msg : args[0]
				},

				success : setDiskPoolCookies
			});

			// Get network names
			$.ajax( {
				url : 'lib/cmd.php',
				dataType : 'json',
				data : {
					cmd : 'lsvm',
					tgt : args[0],
					args : '--getnetworknames',
					msg : args[0]
				},

				success : setNetworkCookies
			});
		}
	}
}

/**
 * Load the power status for each node
 * 
 * @param data
 *            Data returned from HTTP request
 * @return Nothing
 */
function loadPowerStatus(data) {
	// Get datatable
	var dTable = getNodesDataTable();

	// Power state of each node
	// where power[0] = nodeName and power[1] = state
	var power = data.rsp;

	var row, rowPos;
	var node, nodeLink;
	var status, statusLink;
	var args;

	// Get all nodes within the datatable
	var rows = dTable.fnGetNodes();

	for ( var i in power) {
		args = power[i].split(':');

		// Update the power status column
		node = jQuery.trim(args[0]);
		status = jQuery.trim(args[1]);

		// Get the row containing the node
		row = getNodeRow(node, rows);
		rowPos = dTable.fnGetPosition(row);
		dTable.fnUpdate(status, rowPos, 3);
	}
}

/**
 * Load the ping status for each node
 * 
 * @param data
 *            Data returned from HTTP request
 * @return Nothing
 */
function loadPingStatus(data) {
	// Get data table
	var dTable = getNodesDataTable();

	// Power state of each node
	// where ping[0] = nodeName ping[1] = state
	var ping = data.rsp;

	var row, rowPos;
	var node, nodeLink;
	var status, statusLink;
	var args;

	// Get all nodes within the datatable
	var rows = dTable.fnGetNodes();
	for ( var i in ping) {
		args = ping[i][0];

		// Update the power status column
		node = jQuery.trim(ping[i][0]);
		status = jQuery.trim(ping[i][1]);

		// Get the row containing the node
		row = getNodeRow(node, rows);
		rowPos = dTable.fnGetPosition(row);

		// Update the power status column
		status = jQuery.trim(ping[i][1]);
		dTable.fnUpdate(status, rowPos, 2);
	}
}

/**
 * Load inventory for given node
 * 
 * @param e
 *            Windows event
 * @return Nothing
 */
function loadNode(e) {
	if (!e) {
		e = window.event;
	}

	// Get node that was clicked
	var node = (e.target) ? e.target.id : e.srcElement.id;
	var mgt = getNodeMgt(node);

	// Get tab area where a new tab will be inserted
	var myTab = getNodesTab();
	var newTabId = node + 'Tab';

	/**
	 * Only for zVM
	 */
	if (mgt == 'zvm') {
		// Reset node process
		$.cookie(node + 'Processes', 0);

		// Add new tab, only if one does not exist
		if (!$('#' + newTabId).length) {
			var loader = createLoader(node + 'TabLoader');
			loader = $('<center></center>').append(loader);
			myTab.add(newTabId, node, loader);

			// Get node inventory
			var msg = 'out=' + newTabId + ',node=' + node;
			$.ajax( {
				url : 'lib/cmd.php',
				dataType : 'json',
				data : {
					cmd : 'rinv',
					tgt : node,
					args : 'all',
					msg : msg
				},

				success : loadZInventory
			});
		}
	} else {
		// Add new tab, only if one does not exist
		if (!$('#' + newTabId).length) {
			var p = $('<p>No supported</p>');
			myTab.add(newTabId, node, p);

			// TODO: Add inventory for other platforms
		}
	}

	// Select new tab
	myTab.select(newTabId);
}

/**
 * Unlock a node by exchanging the SSH keys between the xCAT MN and the target
 * node
 * 
 * @param tgtNodes
 *            Nodes to unlock
 * @return Nothing
 */
function loadUnlockPage(tgtNodes) {
	// Get nodes tab
	var tab = getNodesTab();

	// Generate new tab ID
	var instance = 0;
	var newTabId = 'UnlockTab' + instance;
	while ($('#' + newTabId).length) {
		// If one already exists, generate another one
		instance = instance + 1;
		newTabId = 'UnlockTab' + instance;
	}

	var unlockForm = $('<div class="form"></div>');

	// Create status bar, hide on load
	var statBarId = 'UnlockStatusBar' + instance;
	var statusBar = createStatusBar(statBarId).hide();
	unlockForm.append(statusBar);

	// Create loader
	var loader = createLoader('');
	statusBar.append(loader);

	// Create info bar
	var infoBar = createInfoBar('Give the root password for this node range to exchange its SSH keys');
	unlockForm.append(infoBar);

	unlockForm
		.append('<div><label>Node range:</label><input type="text" id="node" name="node" readonly="readonly" value="' + tgtNodes + '"/></div>');
	unlockForm
		.append('<div><label>Password:</label><input type="password" id="password" name="password"/></div>');

	/**
	 * Ok
	 */
	var okBtn = createButton('Ok');
	okBtn.bind('click', function(event) {
		// If the form is complete
		var ready = formComplete(newTabId);
		if (ready) {
			var password = $('#' + newTabId + ' input[name=password]').val();

			// Exchange SSH keys
		$.ajax( {
			url : 'lib/cmd.php',
			dataType : 'json',
			data : {
				cmd : 'webrun',
				tgt : '',
				args : 'unlock;' + tgtNodes + ';' + password,
				msg : 'out=' + statBarId + ';cmd=unlock;tgt=' + tgtNodes
			},

			success : updateStatusBar
		});

		// Show status bar
		statusBar.show();

		// Stop this function from executing again
		// Unbind event
		$(this).unbind(event);
		$(this).css( {
			'background-color' : '#F2F2F2',
			'color' : '#BDBDBD'
		});
	}
}   );

	unlockForm.append(okBtn);
	tab.add(newTabId, 'Unlock', unlockForm);
	tab.select(newTabId);
}

/**
 * Load script page
 * 
 * @param tgtNodes
 *            Targets to run script against
 * @return Nothing
 */
function loadScriptPage(tgtNodes) {
	// Get nodes tab
	var tab = getNodesTab();

	// Generate new tab ID
	var inst = 0;
	var newTabId = 'scriptTab' + inst;
	while ($('#' + newTabId).length) {
		// If one already exists, generate another one
		inst = inst + 1;
		newTabId = 'scriptTab' + inst;
	}

	// Open new tab
	// Create remote script form
	var scriptForm = $('<div class="form"></div>');

	// Create status bar
	var barId = 'scriptStatusBar' + inst;
	var statBar = createStatusBar(barId);
	statBar.hide();
	scriptForm.append(statBar);

	// Create loader
	var loader = createLoader('scriptLoader');
	statBar.append(loader);

	// Create info bar
	var infoBar = createInfoBar('Run a script against this node range');
	scriptForm.append(infoBar);

	// Target node or group
	var tgt = $('<div><label for="target">Target node or group:</label><input type="text" name="target" value="' + tgtNodes + '"/></div>');
	scriptForm.append(tgt);

	// Upload file
	var upload = $('<form action="lib/upload.php" method="post" enctype="multipart/form-data"></form>');
	var label = $('<label for="file">Remote file:</label>');
	var file = $('<input type="file" name="file" id="file"/>');
	var subBtn = createButton('Load');
	upload.append(label);
	upload.append(file);
	upload.append(subBtn);
	scriptForm.append(upload);

	// Script
	var script = $('<div><label>Script:</label><textarea/>');
	scriptForm.append(script);

	// Ajax form options
	var options = {
		// Output to text area
		target : '#' + newTabId + ' textarea'
	};
	upload.ajaxForm(options);

	/**
	 * Run
	 */
	var runBtn = createButton('Run');
	runBtn.bind('click', function(event) {
		var ready = true;

		// Check script
		var textarea = $('#' + newTabId + ' textarea');
		for ( var i = 0; i < textarea.length; i++) {
			if (!textarea.eq(i).val()) {
				textarea.eq(i).css('border', 'solid #FF0000 1px');
				ready = false;
			} else {
				textarea.eq(i).css('border', 'solid #424242 1px');
			}
		}

		// If no inputs are empty
		if (ready) {
			// Run script
			runScript(inst);

			// Stop this function from executing again
			// Unbind event
			$(this).unbind(event);
			$(this).css( {
				'background-color' : '#F2F2F2',
				'color' : '#424242'
			});

			// Show status bar
			statBar.show();
		} else {
			alert('You are missing some values');
		}
	});
	scriptForm.append(runBtn);

	// Append to discover tab
	tab.add(newTabId, 'Script', scriptForm);

	// Select new tab
	tab.select(newTabId);
}

/**
 * Load nodeset page
 * 
 * @param trgtNodes
 *            Targets to run nodeset against
 * @return Nothing
 */
function loadNodesetPage(trgtNodes) {
	// Get the OS images
	$.ajax( {
		url : 'lib/cmd.php',
		dataType : 'json',
		data : {
			cmd : 'tabdump',
			tgt : '',
			args : 'osimage',
			msg : ''
		},

		success : setOSImageCookies
	});

	// Get nodes tab
	var tab = getNodesTab();

	// Generate new tab ID
	var inst = 0;
	var tabId = 'nodesetTab' + inst;
	while ($('#' + tabId).length) {
		// If one already exists, generate another one
		inst = inst + 1;
		tabId = 'nodesetTab' + inst;
	}

	// Open new tab
	// Create nodeset form
	var nodesetForm = $('<div class="form"></div>');

	// Create status bar
	var barId = 'nodesetStatusBar' + inst;
	var statusBar = createStatusBar(barId);
	statusBar.hide();
	nodesetForm.append(statusBar);

	// Create loader
	var loader = createLoader('nodesetLoader');
	statusBar.append(loader);

	// Create info bar
	var infoBar = createInfoBar('Set the boot state for a node range');
	nodesetForm.append(infoBar);

	// Target node or group
	var tgt = $('<div><label for="target">Target node or group:</label><input type="text" name="target" value="' + trgtNodes + '"/></div>');
	nodesetForm.append(tgt);

	// Boot method (boot, install, stat, iscsiboot, netboot, statelite)
	var method = $('<div></div>');
	var methodLabel = $('<label for="method">Boot method:</label>');
	var methodSelect = $('<select id="bootMethod" name="bootMethod"></select>');
	methodSelect.append('<option value="boot">boot</option>');
	methodSelect.append('<option value="install">install</option>');
	methodSelect.append('<option value="iscsiboot">iscsiboot</option>');
	methodSelect.append('<option value="netboot">netboot</option>');
	methodSelect.append('<option value="statelite">statelite</option>');
	method.append(methodLabel);
	method.append(methodSelect);
	nodesetForm.append(method);

	// Boot type (zvm, pxe, yaboot)
	var type = $('<div></div>');
	var typeLabel = $('<label for="type">Boot type:</label>');
	var typeSelect = $('<select id="bootType" name="bootType"></select>');
	typeSelect.append('<option value="zvm">zvm</option>');
	typeSelect.append('<option value="install">pxe</option>');
	typeSelect.append('<option value="iscsiboot">yaboot</option>');
	type.append(typeLabel);
	type.append(typeSelect);
	nodesetForm.append(type);

	// Operating system
	var os = $('<div></div>');
	var osLabel = $('<label for="os">Operating system:</label>');
	var osInput = $('<input type="text" name="os"/>');

	// Get the OS versions on-focus
	var tmp;
	osInput.focus(function() {
		tmp = $.cookie('OSVers');

		// If there are any, turn on auto-complete
		if (tmp) {
			$(this).autocomplete(tmp.split(','));
		}
	});
	os.append(osLabel);
	os.append(osInput);
	nodesetForm.append(os);

	// Architecture
	var arch = $('<div></div>');
	var archLabel = $('<label for="arch">Architecture:</label>');
	var archInput = $('<input type="text" name="arch"/>');

	// Get the OS architectures on-focus
	archInput.focus(function() {
		tmp = $.cookie('OSArchs');

		// If there are any, turn on auto-complete
		if (tmp) {
			$(this).autocomplete(tmp.split(','));
		}
	});
	arch.append(archLabel);
	arch.append(archInput);
	nodesetForm.append(arch);

	// Profiles
	var profile = $('<div></div>');
	var profileLabel = $('<label for="profile">Profile:</label>');
	var profileInput = $('<input type="text" name="profile"/>');

	// Get the profiles on-focus
	profileInput.focus(function() {
		tmp = $.cookie('Profiles');

		// If there are any, turn on auto-complete
		if (tmp) {
			$(this).autocomplete(tmp.split(','));
		}
	});
	profile.append(profileLabel);
	profile.append(profileInput);
	nodesetForm.append(profile);

	/**
	 * Ok
	 */
	var okBtn = createButton('Ok');
	okBtn.bind('click', function(event) {
		var ready = true;

		// Check state, OS, arch, and profile
		var inputs = $('#' + tabId + ' input');
		for ( var i = 0; i < inputs.length; i++) {
			if (!inputs.eq(i).val() && inputs.eq(i).attr('name') != 'diskPw') {
				inputs.eq(i).css('border', 'solid #FF0000 1px');
				ready = false;
			} else {
				inputs.eq(i).css('border', 'solid #BDBDBD 1px');
			}
		}

		// If no inputs are empty
		if (ready) {
			// Get nodes
			var tgts = $('#' + tabId + ' input[name=target]').val();

			// Get boot method
			var method = $('#' + tabId + ' select[id=bootMethod]').val();

			// Get boot type
			var type = $('#' + tabId + ' select[id=bootType]').val();

			// Get OS, arch, and profile
			var os = $('#' + tabId + ' input[name=os]').val();
			var arch = $('#' + tabId + ' input[name=arch]').val();
			var profile = $('#' + tabId + ' input[name=profile]').val();

			// Stop this function from executing again
			// Unbind event
			$(this).unbind(event);
			$(this).css( {
				'background-color' : '#F2F2F2',
				'color' : '#424242'
			});

			/**
			 * 1. Set the OS, arch, and profile
			 */
			$.ajax( {
				url : 'lib/cmd.php',
				dataType : 'json',
				data : {
					cmd : 'nodeadd',
					tgt : '',
					args : tgts + ';noderes.netboot=' + type + ';nodetype.os='
						+ os + ';nodetype.arch=' + arch + ';nodetype.profile='
						+ profile,
					msg : 'cmd=nodeadd;inst=' + inst
				},

				success : updateNodesetStatus
			});

			// Show status bar
			statusBar.show();
		} else {
			alert('You are missing some values');
		}
	});
	nodesetForm.append(okBtn);

	// Append to discover tab
	tab.add(tabId, 'Nodeset', nodesetForm);

	// Select new tab
	tab.select(tabId);
}

/**
 * Sort a list
 * 
 * @return Sorted list
 */
jQuery.fn.sort = function() {
	return this.pushStack( [].sort.apply(this, arguments), []);
};

function sortAlpha(a, b) {
	return a.innerHTML > b.innerHTML ? 1 : -1;
};

/**
 * Power on a given node
 * 
 * @param node
 *            Node to power on or off
 * @param power2
 *            Power node to given state
 * @return Nothing
 */
function powerNode(node, power2) {
	node = node.replace('Power', '');

	// Power on/off node
	$.ajax( {
		url : 'lib/cmd.php',
		dataType : 'json',
		data : {
			cmd : 'rpower',
			tgt : node,
			args : power2,
			msg : node
		},

		success : updatePowerStatus
	});
}

/**
 * Delete a given node
 * 
 * @param tgtNodes
 *            Nodes to delete
 * @return Nothing
 */
function deleteNode(tgtNodes) {
	// Get datatable
	var myTab = getNodesTab();

	// Generate new tab ID
	var inst = 0;
	newTabId = 'DeleteTab' + inst;
	while ($('#' + newTabId).length) {
		// If one already exists, generate another one
		inst = inst + 1;
		newTabId = 'DeleteTab' + inst;
	}

	// Create status bar, hide on load
	var statBarId = 'DeleteStatusBar' + inst;
	var statBar = $('<div class="statusBar" id="' + statBarId + '"></div>')
		.hide();

	// Create loader
	var loader = createLoader('');
	statBar.append(loader);
	statBar.hide();

	// Create target nodes string
	var tgtNodesStr = '';
	var nodes = tgtNodes.split(',');
	// Loop through each node
	for ( var i in nodes) {
		// If it is the 1st and only node
		if (i == 0 && i == nodes.length - 1) {
			tgtNodesStr += nodes[i];
		}
		// If it is the 1st node of many nodes
		else if (i == 0 && i != nodes.length - 1) {
			// Append a comma to the string
			tgtNodesStr += nodes[i] + ', ';
		} else {
			// If it is the last node
			if (i == nodes.length - 1) {
				// Append nothing to the string
				tgtNodesStr += nodes[i];
			} else {
				// For every 10 nodes, append a break
				if ((i % 10) > 0) {
					tgtNodesStr += nodes[i] + ', ';
				} else {
					tgtNodesStr += nodes[i] + ', <br>';
				}
			}
		}
	}

	var deleteForm = $('<div class="form"></div>');
	deleteForm.append(statBar);
	deleteForm.append('<p>Do you want to delete ' + tgtNodesStr + '?</p>');

	/**
	 * Delete
	 */
	var deleteBtn = createButton('Delete');
	deleteBtn.bind('click', function(event) {
		// Delete the virtual server
		$.ajax( {
			url : 'lib/cmd.php',
			dataType : 'json',
			data : {
				cmd : 'rmvm',
				tgt : tgtNodes,
				args : '',
				msg : 'out=' + statBarId + ';cmd=rmvm;tgt=' + tgtNodes
			},

			success : updateStatusBar
		});

		// Show status bar loader
		statBar.show();

		// Stop this function from executing again
		// Unbind event
		$(this).unbind(event);
		$(this).css( {
			'background-color' : '#F2F2F2',
			'color' : '#BDBDBD'
		});
	});

	deleteForm.append(deleteBtn);
	myTab.add(newTabId, 'Delete', deleteForm);

	myTab.select(newTabId);
}

/**
 * Update nodeset status
 * 
 * @param data
 *            Data returned from HTTP request
 * @return Nothing
 */
function updateNodesetStatus(data) {
	var rsp = data.rsp;
	var args = data.msg.split(';');
	var cmd = args[0].replace('cmd=', '');

	// Get nodeset instance
	var inst = args[1].replace('inst=', '');
	var statBarId = 'nodesetStatusBar' + inst;
	var tabId = 'nodesetTab' + inst;

	// Get nodes
	var tgts = $('#' + tabId + ' input[name=target]').val();

	// Get boot method
	var method = $('#' + tabId + ' select[id=bootMethod]').val();

	/**
	 * 2. Update /etc/hosts
	 */
	if (cmd == 'nodeadd') {
		// If no output, no errors occurred
		if (rsp.length) {
			$('#' + statBarId).append(
				'<p>(Error) Failed to create node definition</p>');
		} else {
			// Create target nodes string
			var tgtNodesStr = '';
			var nodes = tgts.split(',');
			// Loop through each node
			for ( var i in nodes) {
				// If it is the 1st and only node
				if (i == 0 && i == nodes.length - 1) {
					tgtNodesStr += nodes[i];
				}
				// If it is the 1st node of many nodes
				else if (i == 0 && i != nodes.length - 1) {
					// Append a comma to the string
					tgtNodesStr += nodes[i] + ', ';
				} else {
					// If it is the last node
					if (i == nodes.length - 1) {
						// Append nothing to the string
						tgtNodesStr += nodes[i];
					} else {
						// For every 10 nodes, append a break
						if ((i % 10) > 0) {
							tgtNodesStr += nodes[i] + ', ';
						} else {
							tgtNodesStr += nodes[i] + ', <br>';
						}
					}
				}
			}

			$('#' + statBarId).append(
				'<p>Node definition created for ' + tgtNodesStr + '</p>');
		}

		// Update /etc/hosts
		$.ajax( {
			url : 'lib/cmd.php',
			dataType : 'json',
			data : {
				cmd : 'makehosts',
				tgt : '',
				args : '',
				msg : 'cmd=makehosts;inst=' + inst
			},

			success : updateNodesetStatus
		});
	}

	/**
	 * 4. Update DNS
	 */
	else if (cmd == 'makehosts') {
		// If no output, no errors occurred
		if (rsp.length) {
			$('#' + statBarId).append(
				'<p>(Error) Failed to update /etc/hosts</p>');
		} else {
			$('#' + statBarId).append('<p>/etc/hosts updated</p>');
		}

		// Update DNS
		$.ajax( {
			url : 'lib/cmd.php',
			dataType : 'json',
			data : {
				cmd : 'makedns',
				tgt : '',
				args : '',
				msg : 'cmd=makedns;inst=' + inst
			},

			success : updateNodesetStatus
		});
	}

	/**
	 * 5. Update DHCP
	 */
	else if (cmd == 'makedns') {
		// Separate output into lines
		var p = $('<p></p>');
		for ( var i = 0; i < rsp.length; i++) {
			if (rsp[i]) {
				p.append(rsp[i]);
				p.append('<br>');
			}
		}

		$('#' + statBarId).append(p);

		// Update DHCP
		$.ajax( {
			url : 'lib/cmd.php',
			dataType : 'json',
			data : {
				cmd : 'makedhcp',
				tgt : '',
				args : '-a',
				msg : 'cmd=makedhcp;inst=' + inst
			},

			success : updateNodesetStatus
		});
	}

	/**
	 * 6. Prepare node for boot
	 */
	else if (cmd == 'makedhcp') {
		var failed = false;

		// Separate output into lines
		var p = $('<p></p>');
		for ( var i = 0; i < rsp.length; i++) {
			if (rsp[i]) {
				// Find the node name and insert a break before it
				rsp[i] = rsp[i].replace(new RegExp(node + ': ', 'g'), '<br>');

				p.append(rsp[i]);
				p.append('<br>');

				// If the call failed
				if (rsp[i].indexOf('Failed') > -1
					|| rsp[i].indexOf('Error') > -1) {
					failed = true;
				}
			}
		}

		$('#' + statBarId).append(p);

		// Prepare node for boot
		$.ajax( {
			url : 'lib/cmd.php',
			dataType : 'json',
			data : {
				cmd : 'nodeset',
				tgt : tgts,
				args : method,
				msg : 'cmd=nodeset;inst=' + inst
			},

			success : updateNodesetStatus
		});
	}

	/**
	 * 7. Boot node from network
	 */
	else if (cmd == 'nodeset') {
		var tgtsArray = tgts.split(',');

		// Separate output into lines
		var p = $('<p></p>');
		for ( var i = 0; i < rsp.length; i++) {
			if (rsp[i]) {
				// Find the node name and insert a break before it
				for ( var j = 0; j < tgtsArray.length; j++) {
					rsp[i] = rsp[i].replace(new RegExp(tgtsArray[j], 'g'),
						'<br>' + tgtsArray[j]);
				}

				p.append(rsp[i]);
				p.append('<br>');
			}
		}

		$('#' + statBarId).append(p);

		// Hide loader
		$('#' + statBarId).find('img').hide();
	}
}

/**
 * Update the status bar
 * 
 * @param data
 *            Data returned from HTTP request
 * @return Nothing
 */
function updateStatusBar(data) {
	var rsp = data.rsp;
	var args = data.msg.split(';');
	var statBarId = args[0].replace('out=', '');
	var cmd = args[1].replace('cmd=', '');
	var tgts = args[2].replace('tgt=', '').split(',');

	if (cmd == 'unlock') {
		// Hide loader
		$('#' + statBarId).find('img').hide();

		// Separate output into lines
		var p = $('<p></p>');
		for ( var i = 0; i < rsp.length; i++) {
			if (rsp[i]) {
				p.append(rsp[i]);
				p.append('<br>');
			}
		}

		$('#' + statBarId).append(p);
	} else if (cmd == 'rmvm') {
		// Get data table
		var dTable = getNodesDataTable();
		var failed = false;

		// Hide loader
		$('#' + statBarId).find('img').hide();

		// Separate output into lines
		var p = $('<p></p>');
		for ( var i = 0; i < rsp.length; i++) {
			if (rsp[i]) {
				// Determine if the command failed
				if (rsp[i].indexOf("Error") > -1
					|| rsp[i].indexOf("Failed") > -1) {
					failed = true;
				}

				// Find the node name and insert a break before it
				for ( var j = 0; j < tgts.length; j++) {
					rsp[i] = rsp[i].replace(new RegExp(tgts[j] + ': ', 'g'),
						'<br>');
				}

				p.append(rsp[i]);
				p.append('<br>');
			}
		}

		$('#' + statBarId).append(p);

		// Update data table
		for ( var i = 0; i < tgts.length; i++) {
			if (!failed) {
				// Get the row containing the node link and delete it
				var row = $('#' + tgts[i]).parent().parent();
				var rowPos = dTable.fnGetPosition(row.get(0));
				dTable.fnDeleteRow(rowPos);
			}
		}
	} else if (cmd == 'xdsh') {
		// Hide loader
		$('#' + statBarId).find('img').hide();

		// Separate output into lines
		var p = $('<p></p>');
		for ( var i = 0; i < rsp.length; i++) {
			if (rsp[i]) {
				// Find the node name and insert a break before it
				for ( var j = 0; j < tgts.length; j++) {
					rsp[i] = rsp[i].replace(new RegExp(tgts[j], 'g'),
						'<br>' + tgts[j]);
				}

				p.append(rsp[i]);
				p.append('<br>');
			}
		}

		$('#' + statBarId).append(p);
	} else {
		return;
	}
}

/**
 * Check the completeness of the form
 * 
 * @param tabId
 *            Tab ID containing form
 * @return True: If the form is complete, False: Otherwise
 */
function formComplete(tabId) {
	var ready = true;

	// Check all inputs within the form
	var inputs = $('#' + tabId + ' input');
	for ( var i = 0; i < inputs.length; i++) {
		// If there is no value given in the input
		if (!inputs.eq(i).val()) {
			inputs.eq(i).css('border', 'solid #FF0000 1px');
			// It is not complete
			ready = false;
		} else {
			inputs.eq(i).css('border', 'solid #BDBDBD 1px');
		}
	}

	return ready;
}

/**
 * Update the power status of the node
 * 
 * @param data
 *            Data from HTTP request
 * @return Nothing
 */
function updatePowerStatus(data) {
	// Get datatable
	var dTable = getNodesDataTable();

	// Get all nodes within the datatable
	var rows = dTable.fnGetNodes();

	// Get xCAT response
	var rsp = data.rsp;
	// Loop through each line
	for ( var i = 0; i < rsp.length; i++) {
		// Get the node
		var node = rsp[i].split(":")[0];

		// If there is no error
		var status;
		if (rsp[i].indexOf("Error") < 0 || rsp[i].indexOf("Failed") < 0) {
			// Get the row containing the node link
			var row = getNodeRow(node, rows);
			var rowPos = dTable.fnGetPosition(row);

			// If it was power on, then the data return would contain "Starting"
			var strPos = rsp[i].indexOf("Starting");
			if (strPos > -1) {
				status = 'on';
			} else {
				status = 'off';
			}

			// Update the power status column
			dTable.fnUpdate(status, rowPos, 3);
		} else {
			// Power on/off failed
			alert(rsp[i]);
		}
	}
}

/**
 * Run a script
 * 
 * @param inst
 *            Remote script tab instance
 * @return Nothing
 */
function runScript(inst) {
	var tabId = 'scriptTab' + inst;

	// Get node name
	var tgts = $('#' + tabId + ' input[name=target]').val();
	// Get script
	var script = $('#' + tabId + ' textarea').val();

	// Disable all fields
	$('#' + tabId + ' input').attr('readonly', 'readonly');
	$('#' + tabId + ' input').css( {
		'background-color' : '#F2F2F2'
	});

	$('#' + tabId + ' textarea').attr('readonly', 'readonly');
	$('#' + tabId + ' textarea').css( {
		'background-color' : '#F2F2F2'
	});

	// Run script
	$.ajax( {
		url : 'lib/zCmd.php',
		dataType : 'json',
		data : {
			cmd : 'xdsh',
			tgt : tgts,
			args : '-e',
			att : script,
			msg : 'out=scriptStatusBar' + inst + ';cmd=xdsh;tgt=' + tgts
		},

		success : updateStatusBar
	});
}

/**
 * Get the hardware management of a given node
 * 
 * @param node
 *            The node
 * @return The hardware management of the node
 */
function getNodeMgt(node) {
	// Get the row
	var row = $('#' + node).parent().parent();

	// Search for the mgt column
	var mgtCol = row.parent().parent().find('th:contains("mgt")');
	// Get the mgt column index
	var mgtIndex = mgtCol.index();

	// Get the mgt for the given node
	var mgt = row.find('td:eq(' + mgtIndex + ')');

	return mgt.text();
}

/**
 * Set a cookie for the OS images
 * 
 * @param data
 *            Data from HTTP request
 * @return Nothing
 */
function setOSImageCookies(data) {
	var rsp = data.rsp;

	var imageNames = new Array;
	var profilesHash = new Object();
	var osVersHash = new Object();
	var osArchsHash = new Object();

	for ( var i = 1; i < rsp.length; i++) {
		// osimage table columns: imagename, profile, imagetype, provmethod,
		// osname, osvers, osdistro, osarch, synclists, comments, disable
		// e.g. sles11.1-s390x-statelite-compute, compute, linux, statelite,
		// Linux, sles11.1, , s390x, , s,

		// Get the image name
		var cols = rsp[i].split(',');
		var osImage = cols[0].replace(new RegExp('"', 'g'), '');
		var profile = cols[1].replace(new RegExp('"', 'g'), '');
		var osVer = cols[5].replace(new RegExp('"', 'g'), '');
		var osArch = cols[7].replace(new RegExp('"', 'g'), '');
		imageNames.push(osImage);
		profilesHash[profile] = 1;
		osVersHash[osVer] = 1;
		osArchsHash[osArch] = 1;
	}

	// Save image names in a cookie
	$.cookie('ImageNames', imageNames);

	// Save profiles in a cookie
	var tmp = new Array;
	for ( var key in profilesHash) {
		tmp.push(key);
	}
	$.cookie('Profiles', tmp);

	// Save OS versions in a cookie
	tmp = [];
	for ( var key in osVersHash) {
		tmp.push(key);
	}
	$.cookie('OSVers', tmp);

	// Save OS architectures in a cookie
	tmp = [];
	for ( var key in osArchsHash) {
		tmp.push(key);
	}
	$.cookie('OSArchs', tmp);
}

/**
 * Set a cookie for the groups
 * 
 * @param data
 *            Data from HTTP request
 * @return Nothing
 */
function setGroupsCookies(data) {
	var rsp = data.rsp;

	// Save image names in a cookie
	$.cookie('Groups', rsp);
}

/**
 * Get the row element that contains the given node
 * 
 * @param tgtNode
 *            Node to find
 * @param rows
 *            Rows within the datatable
 * @return Row element
 */
function getNodeRow(tgtNode, rows) {
	// Get nodes datatable
	var dTable = getNodesDataTable();

	// Find the row
	for ( var i in rows) {
		// Get all columns within the row
		var cols = rows[i].children;
		// Get the 1st column (node name)
		var cont = cols[1].children;
		var node = cont[0].innerHTML;

		// If the node matches the target node
		if (node == tgtNode) {
			// Return the row
			return rows[i];
		}
	}

	return;
}