Index: trunk/web/addons/toga/image.php
===================================================================
--- trunk/web/addons/toga/image.php	(revision 116)
+++ trunk/web/addons/toga/image.php	(revision 117)
@@ -2,5 +2,5 @@
 include_once "./libtoga.php";
 
-$httpvars = new HTTPVariables( $HTTP_GET_VARS );
+$httpvars = new HTTPVariables( $HTTP_GET_VARS, $_GET );
 $view = $httpvars->getHttpVar( "view" );
 $clustername = $httpvars->getClusterName();
Index: trunk/web/addons/toga/index.php
===================================================================
--- trunk/web/addons/toga/index.php	(revision 116)
+++ trunk/web/addons/toga/index.php	(revision 117)
@@ -1,20 +1,260 @@
 <?php
 
+if ( !empty( $_GET ) ) {
+	extract( $_GET );
+}
+
 $my_dir = getcwd();
 
 include_once "./libtoga.php";
 
-global $GANGLIA_PATH, $context;
+global $GANGLIA_PATH;
 chdir( $GANGLIA_PATH );
-$context = 'cluster';
-
-$title = "Torque Report";
-include_once "./get_context.php";
+
 include_once "./class.TemplatePower.inc.php";
 chdir( $my_dir );
-include_once "header.php";
-
-include_once "overview.php";
-
-include_once "footer.php";
+
+$httpvars = new HTTPVariables( $HTTP_GET_VARS, $_GET );
+$clustername = $httpvars->getClusterName();
+$view = $httpvars->getHttpVar( "view" );
+
+if( !isset($view) ) $view = "overview";
+if( !isset($sortorder) ) $sortorder = "asc";
+if( !isset($sortby) ) $sortby = "id";
+
+function makeHeader() {
+
+	global $tpl, $grid, $context, $initgrid;
+	global $jobrange, $jobstart, $title;
+	global $page, $gridwalk, $clustername;
+	global $parentgrid, $physical, $hostname;
+	global $self;
+
+	if ( $context == "control" && $controlroom < 0 )
+		$header = "header-nobanner";
+	else
+		$header = "header";
+
+	# Maintain our path through the grid tree.
+	$me = $self . "@" . $grid[$self][AUTHORITY];
+
+	if ($initgrid) {
+		$gridstack = array();
+		$gridstack[] = $me;
+	} else if ($gridwalk=="fwd") {
+		# push our info on gridstack, format is "name@url>name2@url".
+		if (end($gridstack) != $me) {
+			$gridstack[] = $me;
+		}
+	} else if ($gridwalk=="back") {
+		# pop a single grid off stack.
+		if (end($gridstack) != $me) {
+			array_pop($gridstack);
+		}
+	}
+
+	$gridstack_str = join(">", $gridstack);
+	$gridstack_url = rawurlencode($gridstack_str);
+
+	if ($initgrid or $gridwalk) {
+		# Use cookie so we dont have to pass gridstack around within this site.
+		# Cookie values are automatically urlencoded. Expires in a day.
+		setcookie("gs", $gridstack_str, time() + 86400);
+	}
+
+	# Invariant: back pointer is second-to-last element of gridstack. Grid stack never
+	# has duplicate entries.
+	list($parentgrid, $parentlink) = explode("@", $gridstack[count($gridstack)-2]);
+
+	# Setup a redirect to a remote server if you choose a grid from pulldown menu. Tell
+	# destination server that we're walking foward in the grid tree.
+	if (strstr($clustername, "http://")) {
+		$tpl->assign("refresh", "0");
+		$tpl->assign("redirect", ";URL=$clustername?gw=fwd&gs=$gridstack_url");
+		echo "<h2>Redirecting, please wait...</h2>";
+		$tpl->printToScreen();
+		exit;
+	}
+
+	$tpl->assign( "refresh", $default_refresh );
+	$tpl->assign( "date", date("r") );
+	$tpl->assign( "page_title", $title );
+
+	# The page to go to when "Get Fresh Data" is pressed.
+	if (isset($page))
+		$tpl->assign("page",$page);
+	else
+		$tpl->assign("page","./");
+
+	# Templated Logo image
+	$tpl->assign("images","./templates/$template_name/images");
+
+	#
+	# Used when making graphs via graph.php. Included in most URLs
+	#
+	$sort_url=rawurlencode($sort);
+	$get_metric_string = "m=$metric&r=$range&s=$sort_url&hc=$hostcols";
+
+	if ($jobrange and $jobstart)
+		$get_metric_string .= "&jr=$jobrange&js=$jobstart";
+
+	# Set the Alternate view link.
+	$cluster_url=rawurlencode($clustername);
+	$node_url=rawurlencode($hostname);
+
+	# Make some information available to templates.
+	$tpl->assign("cluster_url", $cluster_url);
+	# Build the node_menu
+	$node_menu = "";
+
+	if ($parentgrid) {
+		$node_menu .= "<B>$parentgrid $meta_designator</B> ";
+		$node_menu .= "<B>&gt;</B>\n";
+	}
+
+	# Show grid.
+	$mygrid =  ($self == "unspecified") ? "" : $self;
+	$node_menu .= "<B>$mygrid $meta_designator</A> ";
+	$node_menu .= "<B>&gt;</B>\n";
+
+	if ($physical)
+		$node_menu .= hiddenvar("p", $physical);
+
+	if ( $clustername ) {
+		$url = rawurlencode($clustername);
+		$node_menu .= "<B>$clustername</B> ";
+		//$node_menu .= "<B>&gt;</B>\n";
+		$node_menu .= hiddenvar("c", $clustername);
+	}
+
+	$tpl->assign("node_menu", $node_menu);
+
+	# Make sure that no data is cached..
+	header ("Expires: Mon, 26 Jul 1997 05:00:00 GMT");    # Date in the past
+	header ("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); # always modified
+	header ("Cache-Control: no-cache, must-revalidate");  # HTTP/1.1
+	header ("Pragma: no-cache");                          # HTTP/1.0
+}
+
+function makeFooter() {
+	global $tpl, $version, $parsetime;
+
+	$tpl->assign("webfrontend-version",$version["webfrontend"]);
+	$tpl->assign("togaweb-version", "0.1");
+	$tpl->assign("togaarch-version", "0.1");
+	$tpl->assign("togaplug-version", "0.1");
+
+	if ($version["gmetad"]) {
+		$tpl->assign("webbackend-component", "gmetad");
+		$tpl->assign("webbackend-version",$version["gmetad"]);
+	} else if ($version["gmond"]) {
+		$tpl->assign("webbackend-component", "gmond");
+		$tpl->assign("webbackend-version", $version["gmond"]);
+	}
+
+	$tpl->assign("parsetime", sprintf("%.4f", $parsetime) . "s");
+}
+
+function includeJobview() {
+	global $tpl;
+
+	$tpl->assignInclude( "main", "templates/jobview.tpl" );
+}
+
+function includeOverview() {
+	global $tpl;
+
+	$tpl->assignInclude( "main", "templates/overview.tpl" );
+}
+
+function makeJobview() {
+
+}
+
+//function makeOverview() {
+//
+//	global $jobs, $nodes, $heartbeat, $clustername;
+
+//	foreach( $jobs as $jobid => $jobattrs ) {
+//
+//		$report_time = $jobattrs[reported];
+
+//		if( $report_time == $heartbeat ) {
+
+//			$tpl->newBlock("node");
+//			$tpl->assign( "clustername", $clustername );
+//			$tpl->assign("id", $jobid );
+//			$tpl->assign("state", $jobattrs[status] );
+//			$tpl->assign("user", $jobattrs[owner] );
+//			$tpl->assign("queue", $jobattrs[queue] );
+//			$tpl->assign("name", $jobattrs[name] );
+//			$tpl->assign("req_cpu", $jobattrs[requested_time] );
+//			$tpl->assign("req_memory", $jobattrs[requested_memory] );
+//			$nodes = count( $jobattrs[nodes] );
+//			$ppn = (int) $jobattrs[ppn] ? $jobattrs[ppn] : 1;
+//			$cpus = $nodes * $ppn;
+//			$tpl->assign("nodes", $nodes );
+//			$tpl->assign("cpus", $cpus );
+//			$start_time = (int) $jobattrs[start_timestamp];
+
+//			if( $start_time ) {
+
+//				$runningtime = makeTime( $report_time - $start_time );
+//				$tpl->assign("started", makeDate( $start_time ) );
+//				$tpl->assign("runningtime", $runningtime );
+//			}
+//		}
+//	}
+//}
+
+$tpl = new TemplatePower( "templates/index.tpl" );
+
+$tpl->assignInclude( "header", "templates/header.tpl" );
+
+switch( $view ) {
+
+	case "overview":
+
+		includeOverview();
+		break;
+
+	case "jobview":
+
+		includeJobview();
+		break;
+
+	default:
+
+		includeOverview();
+		break;
+}
+
+$tpl->assignInclude( "footer", "templates/footer.tpl" );
+$tpl->prepare();
+
+$title = "Torque Report";
+makeHeader();
+
+switch( $view ) {
+
+	case "overview":
+
+		include "./overview.php";
+		makeOverview();
+		break;
+
+	case "jobview":
+
+		makeJobview();
+		break;
+
+	default:
+
+		makeOverview();
+		break;
+}
+
+makeFooter();
+
+$tpl->printToScreen();
 ?>
Index: trunk/web/addons/toga/libtoga.php
===================================================================
--- trunk/web/addons/toga/libtoga.php	(revision 116)
+++ trunk/web/addons/toga/libtoga.php	(revision 117)
@@ -1,3 +1,9 @@
 <?php
+// If php is compiled without globals
+//
+if ( !empty( $_GET ) ) {
+        extract( $_GET );
+}
+
 class HTTPVariables {
 
@@ -5,15 +11,22 @@
 	var $restvars, $httpvars;
 
-	function HTTPVariables( $vars ) {
+	function HTTPVariables( $httpvars, $getvars ) {
 
 		$this->restvars = array();
 
-		$this->clustername = $vars["c"] ? $vars["c"] : null;
-		$this->metricname = $vars["m"] ? $vars["m"] : null;
-
-		foreach( $vars as $httpvar => $httpval ) {
+		$this->clustername = $httpvars["c"] ? $httpvars["c"] : null;
+		$this->metricname = $httpvars["m"] ? $httpvars["m"] : null;
+
+		foreach( $httpvars as $httpvar => $httpval ) {
 			
 			if( $httpval ) {
 				$this->restvars[$httpvar] = $httpval;
+			}
+		}
+
+		foreach( $getvars as $getvar => $getval ) {
+
+			if( $getval ) {
+				$this->restvars[$getvar] = $getval;
 			}
 		}
@@ -40,12 +53,22 @@
 include_once "./conf.php";
 
-global $GANGLIA_PATH, $SMALL_CLUSTERIMAGE_MAXWIDTH, $SMALL_CLUSTERIMAGE_NODEWIDTH, $DATA_SOURCE;
-
-include_once "$GANGLIA_PATH/conf.php";
-include_once "$GANGLIA_PATH/functions.php";
-include_once "$GANGLIA_PATH/ganglia.php";
-
-global $HTTP_GET_VARS;
-$httpvars = new HTTPVariables( $HTTP_GET_VARS );
+global $GANGLIA_PATH;
+
+$my_dir = getcwd();
+
+// Load Ganglia's PHP
+chdir( $GANGLIA_PATH );
+
+include_once "./conf.php";
+include_once "./functions.php";
+include_once "./ganglia.php";
+include_once "./get_context.php";
+include_once "./get_ganglia.php";
+
+// Back to our PHP
+chdir( $my_dir );
+
+global $SMALL_CLUSTERIMAGE_MAXWIDTH, $SMALL_CLUSTERIMAGE_NODEWIDTH, $DATA_SOURCE, $HTTP_GET_VARS, $_GET;
+$httpvars = new HTTPVariables( $HTTP_GET_VARS, $_GET );
 
 // Set cluster context so that Ganglia will
@@ -53,8 +76,6 @@
 //
 global $context, $clustername;
-$clustername = $httpvars->getClusterName();
-$context = 'cluster';
-
-include_once "$GANGLIA_PATH/get_ganglia.php";
+//$clustername = $httpvars->getClusterName();
+//$context = 'cluster';
 
 // Ganglia's array of host metrics
@@ -62,9 +83,4 @@
 global $metrics;
 
-// If php is compiled without globals
-//
-if ( !empty( $_GET ) ) {
-        extract( $_GET );
-}
 
 class DataSource {
Index: trunk/web/addons/toga/overview.php
===================================================================
--- trunk/web/addons/toga/overview.php	(revision 116)
+++ trunk/web/addons/toga/overview.php	(revision 117)
@@ -1,30 +1,13 @@
 <?php
-
-$my_dir = getcwd();
-
-include_once "./libtoga.php";
-
-global $GANGLIA_PATH;
-chdir( $GANGLIA_PATH );
-include_once "./class.TemplatePower.inc.php";
-chdir( $my_dir );
-
-$httpvars = new HTTPVariables( $HTTP_GET_VARS );
-$clustername = $httpvars->getClusterName();
-printf( "clustername = %s\n", $clustername );
-$queue_select = $httpvars->getHttpVar( "queue" );
-printf( "queue = %s\n", $queue );
+global $GANGLIA_PATH, $clustername, $tpl;
 
 $data_gatherer = new DataGatherer();
 
-$tpl = new TemplatePower("templates/overview.tpl");
-$tpl->prepare();
-
-$tpl->assign( "self", "./index.php" );
+//$tpl->assign( "self", "./index.php" );
 $tpl->assign( "clustername", $clustername );
-
 $tpl->assign( "clusterimage", "./image.php?c=".rawurlencode($clustername)."&view=big-clusterimage" );
 
 $data_gatherer->parseXML();
+
 $heartbeat = $data_gatherer->getHeartbeat();
 $jobs = $data_gatherer->getJobs();
@@ -214,36 +197,130 @@
 }
 
-foreach( $jobs as $jobid => $jobattrs ) {
-
-	$report_time = $jobattrs[reported];
-
-	if( $report_time == $heartbeat ) {
-
-		$tpl->newBlock("node");
-		$tpl->assign( "clustername", $clustername );
-		$tpl->assign("id", $jobid );
-		$tpl->assign("state", $jobattrs[status] );
-		$tpl->assign("user", $jobattrs[owner] );
-		$tpl->assign("queue", $jobattrs[queue] );
-		$tpl->assign("name", $jobattrs[name] );
-		$tpl->assign("req_cpu", $jobattrs[requested_time] );
-		$tpl->assign("req_memory", $jobattrs[requested_memory] );
-		$nodes = count( $jobattrs[nodes] );
-		$ppn = (int) $jobattrs[ppn] ? $jobattrs[ppn] : 1;
-		$cpus = $nodes * $ppn;
-		$tpl->assign("nodes", $nodes );
-		$tpl->assign("cpus", $cpus );
-		$start_time = (int) $jobattrs[start_timestamp];
-
-		if( $start_time ) {
-
-			$runningtime = makeTime( $report_time - $start_time );
-			$tpl->assign("started", makeDate( $start_time ) );
-			$tpl->assign("runningtime", $runningtime );
+
+function sortJobs( $jobs, $sortby, $sortorder ) {
+
+	$sorted = array();
+
+	$cmp = create_function( '$a, $b', 
+		"global \$sortby, \$sortorder;".
+
+		"if( \$a == \$b ) return 0;".
+
+		"if (\$sortorder==\"desc\")".
+			"return ( \$a < \$b ) ? 1 : -1;".
+		"else if (\$sortorder==\"asc\")".
+			"return ( \$a > \$b ) ? 1 : -1;" );
+
+        foreach( $jobs as $jobid => $jobattrs ) {
+
+                        $state = $jobattrs[status];
+                        $user = $jobattrs[owner];
+                        $queue = $jobattrs[queue];
+                        $name = $jobattrs[name];
+                        $req_cpu = $jobattrs[requested_time];
+                        $req_memory = $jobattrs[requested_memory];
+                        $nodes = count( $jobattrs[nodes] );
+                        $ppn = (int) $jobattrs[ppn] ? $jobattrs[ppn] : 1;
+                        $cpus = $nodes * $ppn;
+                        $start_time = (int) $jobattrs[start_timestamp];
+			$runningtime = $report_time - $start_time;
+
+			switch( $sortby ) {
+				case "id":
+					$sorted[$jobid] = $jobid;
+					break;
+
+				case "state":
+					$sorted[$jobid] = $state;
+					break;
+
+				case "user":
+					$sorted[$jobid] = $user;
+					break;
+
+				case "queue":
+					$sorted[$jobid] = $queue;
+					break;
+
+				case "name":
+					$sorted[$jobid] = $name;
+					break;
+
+				case "req_cpu":
+					$sorted[$jobid] = $req_cpu;
+					break;
+
+				case "req_mem":
+					$sorted[$jobid] = $req_memory;
+					break;
+
+				case "nodes":
+					$sorted[$jobid] = $nodes;
+					break;
+
+				case "cpus":
+					$sorted[$jobid] = $cpus;
+					break;
+
+				case "start":
+					$sorted[$jobid] = $start_time;
+					break;
+
+				case "runningtime":
+					$sorted[$jobid] = $runningtime;
+					break;
+
+				default:
+					break;
+
+			}
+        }
+
+	uasort( $sorted, $cmp );
+
+	return $sorted;
+}
+
+function makeOverview() {
+
+	global $jobs, $nodes, $heartbeat, $clustername, $tpl;
+	global $sortorder, $sortby;
+
+	$tpl->assign("sortorder", $sortorder );
+	$tpl->assign("sortby", $sortby );
+
+
+	$sorted_jobs = sortJobs( $jobs, $sortby, $sortorder );
+
+	foreach( $sorted_jobs as $jobid => $sortdec ) {
+
+		$report_time = $jobs[$jobid][reported];
+
+		if( $report_time == $heartbeat ) {
+
+			$tpl->newBlock("node");
+			$tpl->assign( "clustername", $clustername );
+			$tpl->assign("id", $jobid );
+			$tpl->assign("state", $jobs[$jobid][status] );
+			$tpl->assign("user", $jobs[$jobid][owner] );
+			$tpl->assign("queue", $jobs[$jobid][queue] );
+			$tpl->assign("name", $jobs[$jobid][name] );
+			$tpl->assign("req_cpu", $jobs[$jobid][requested_time] );
+			$tpl->assign("req_memory", $jobs[$jobid][requested_memory] );
+			$nodes = count( $jobs[$jobid][nodes] );
+			$ppn = (int) $jobs[$jobid][ppn] ? $jobs[$jobid][ppn] : 1;
+			$cpus = $nodes * $ppn;
+			$tpl->assign("nodes", $nodes );
+			$tpl->assign("cpus", $cpus );
+			$start_time = (int) $jobs[$jobid][start_timestamp];
+
+			if( $start_time ) {
+
+				$runningtime = makeTime( $report_time - $start_time );
+				$tpl->assign("started", makeDate( $start_time ) );
+				$tpl->assign("runningtime", $runningtime );
+			}
 		}
 	}
 }
-
-$tpl->printToScreen();
-
 ?>
Index: trunk/web/addons/toga/templates/header.tpl
===================================================================
--- trunk/web/addons/toga/templates/header.tpl	(revision 116)
+++ trunk/web/addons/toga/templates/header.tpl	(revision 117)
@@ -45,4 +45,5 @@
 </TR>
 </TABLE> 
+</FORM>
 
 <FONT SIZE="+1">
Index: trunk/web/addons/toga/templates/index.tpl
===================================================================
--- trunk/web/addons/toga/templates/index.tpl	(revision 117)
+++ trunk/web/addons/toga/templates/index.tpl	(revision 117)
@@ -0,0 +1,9 @@
+<!-- TOGA SOB: <header> -->
+<!-- INCLUDE BLOCK : header -->
+<!-- TOGA EOB: </header> -->
+<!-- TOGA SOB: <main> -->
+<!-- INCLUDE BLOCK : main -->
+<!-- TOGA EOB: </main> -->
+<!-- TOGA SOB: <footer> -->
+<!-- INCLUDE BLOCK : footer -->
+<!-- TOGA EOB: </footer> -->
Index: trunk/web/addons/toga/templates/overview.tpl
===================================================================
--- trunk/web/addons/toga/templates/overview.tpl	(revision 117)
+++ trunk/web/addons/toga/templates/overview.tpl	(revision 117)
@@ -0,0 +1,76 @@
+<BR><BR>
+
+<CENTER>
+<TABLE>
+<TR>
+  <TD>
+    <IMG SRC="{clusterimage}"><BR>
+    reported: {heartbeat}
+  </TD>
+  <TD>
+    <IMG SRC="{pie}">
+  </TD>
+</TR>
+</TABLE>
+
+<BR><BR>
+
+<SCRIPT TYPE="text/javascript">
+	function setSort( sortbyval ) {
+
+		if( sortbyval != document.toga_form.sortby.value ) {
+
+			document.toga_form.sortby.value = sortbyval;
+			document.toga_form.sortorder.value = "desc";
+
+		} else {
+
+			if( document.toga_form.sortorder.value == "desc" )
+				document.toga_form.sortorder.value = "asc";
+			else if( document.toga_form.sortorder.value == "asc" )
+				document.toga_form.sortorder.value = "desc";
+		}
+
+		document.forms['toga_form'].submit();
+	}
+</SCRIPT>
+
+<FORM NAME="toga_form" ACTION="./" METHOD="GET">
+
+<INPUT TYPE="HIDDEN" NAME="sortby" VALUE="{sortby}">
+<INPUT TYPE="HIDDEN" NAME="sortorder" VALUE="{sortorder}">
+<INPUT TYPE="HIDDEN" NAME="c" VALUE="{clustername}">
+<INPUT TYPE="HIDDEN" NAME="jobid" VALUE="{jobid}">
+
+</FORM>
+
+<TABLE WIDTH="80%" CELLPADDING="8" CELLSPACING="0" BORDER=1>
+<TR>
+<TD><B><A HREF="#" onClick="setSort( 'id' )">Id</A></B></TD>
+<TD><B><A HREF="#" onClick="setSort( 'state' )">State</A></B></TD>
+<TD><B><A HREF="#" onClick="setSort( 'user' )">User</A></B></TD>
+<TD><B><A HREF="#" onClick="setSort( 'queue' )">Queue</A></B></TD>
+<TD><B><A HREF="#" onClick="setSort( 'name' )">Name</A></B></TD>
+<TD><B><A HREF="#" onClick="setSort( 'req_cpu' )">Requested CPU time</A></B></TD>
+<TD><B><A HREF="#" onClick="setSort( 'req_mem' )">Requested Memory</A></B></TD>
+<TD><B>Current <A HREF="#" onClick="setSort( 'nodes' )">Nodes</A>/<A HREF="#" onClick="setSort( 'cpus' )">Cpus</A></B></TD>
+<TD><B><A HREF="#" onClick="setSort( 'start' )">Started</A></B></TD>
+<TD><B><A HREF="#" onClick="setSort( 'runningtime' )">Runningtime</A></B></TD>
+</TR>
+
+<!-- START BLOCK : node -->
+  <TR>
+    <TD><A HREF="">{id}</A></TD>
+    <TD><A HREF="">{state}</A></TD>
+    <TD><A HREF="{togasorted}&user={user}">{user}</A></TD>
+    <TD><A HREF="{togasorted}&queue={queue}">{queue}</A></TD>
+    <TD>{name}</TD>
+    <TD>{req_cpu}</TD>
+    <TD>{req_memory}</TD>
+    <TD>{nodes}/{cpus}</TD>
+    <TD>{started}</TD>
+    <TD>{runningtime}</TD>
+  </TR>
+<!-- END BLOCK : node -->
+</TABLE>
+</CENTER>
