Index: review/server.inc
===================================================================
RCS file: /cvs/drupal/contributions/modules/project_issue_file_review/review/server.inc,v
retrieving revision 1.3
diff -u -r1.3 server.inc
--- review/server.inc	18 Oct 2009 23:36:48 -0000	1.3
+++ review/server.inc	28 Oct 2009 02:59:48 -0000
@@ -32,6 +32,14 @@
 
   public function detail(array $test, array $result);
 
+  /**
+   * Get the code title.
+   *
+   * @param integer $code Result code.
+   * @return string Title representing code.
+   */
+  public function code_title($code);
+
   public function load($result_id);
 
   public function record($result_id, array $data);
Index: server/views/pifr_server.views_default.inc
===================================================================
RCS file: /cvs/drupal/contributions/modules/project_issue_file_review/server/views/pifr_server.views_default.inc,v
retrieving revision 1.16
diff -u -r1.16 pifr_server.views_default.inc
--- server/views/pifr_server.views_default.inc	16 Oct 2009 20:38:47 -0000	1.16
+++ server/views/pifr_server.views_default.inc	28 Oct 2009 02:59:49 -0000
@@ -1286,10 +1286,49 @@
       'field' => 'test_id',
       'relationship' => 'none',
     ),
+    'client_id' => array(
+      'label' => 'client',
+      'required' => 0,
+      'id' => 'client_id',
+      'table' => 'pifr_log',
+      'field' => 'client_id',
+      'relationship' => 'none',
+    ),
   ));
   $handler->override_option('fields', array(
+    'client_id' => array(
+      'label' => 'Client ID',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'strip_tags' => 0,
+        'html' => 0,
+      ),
+      'set_precision' => FALSE,
+      'precision' => 0,
+      'decimal' => '.',
+      'separator' => ',',
+      'prefix' => '',
+      'suffix' => '',
+      'exclude' => 1,
+      'id' => 'client_id',
+      'table' => 'pifr_client',
+      'field' => 'client_id',
+      'relationship' => 'client_id',
+    ),
     'log_id' => array(
-      'label' => 'Log ID',
+      'label' => 'ID',
       'alter' => array(
         'alter_text' => 0,
         'text' => '',
@@ -1400,7 +1439,7 @@
       'field' => 'title',
       'relationship' => 'test_id',
     ),
-    'message' => array(
+    'code' => array(
       'label' => 'Message',
       'alter' => array(
         'alter_text' => 0,
@@ -1419,10 +1458,16 @@
         'strip_tags' => 0,
         'html' => 0,
       ),
+      'set_precision' => FALSE,
+      'precision' => 0,
+      'decimal' => '.',
+      'separator' => ',',
+      'prefix' => '',
+      'suffix' => '',
       'exclude' => 0,
-      'id' => 'message',
+      'id' => 'code',
       'table' => 'pifr_log',
-      'field' => 'message',
+      'field' => 'code',
       'relationship' => 'none',
     ),
     'timestamp' => array(
@@ -1465,14 +1510,6 @@
       'relationship' => 'none',
     ),
   ));
-  $handler->override_option('arguments', array(
-    'test_id' => array(
-      'id' => 'test_id',
-      'table' => 'pifr_test',
-      'field' => 'test_id',
-      'relationship' => 'test_id',
-    ),
-  ));
   $handler->override_option('access', array(
     'type' => 'none',
   ));
@@ -1520,8 +1557,42 @@
   ));
   $handler = $view->new_display('page', 'Event log (recent)', 'page_2');
   $handler->override_option('fields', array(
+    'client_id' => array(
+      'label' => 'Client ID',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'strip_tags' => 0,
+        'html' => 0,
+      ),
+      'set_precision' => FALSE,
+      'precision' => 0,
+      'decimal' => '.',
+      'separator' => ',',
+      'prefix' => '',
+      'suffix' => '',
+      'exclude' => 1,
+      'id' => 'client_id',
+      'table' => 'pifr_client',
+      'field' => 'client_id',
+      'relationship' => 'client_id',
+      'override' => array(
+        'button' => 'Use default',
+      ),
+    ),
     'log_id' => array(
-      'label' => 'Log ID',
+      'label' => 'ID',
       'alter' => array(
         'alter_text' => 0,
         'text' => '',
@@ -1550,6 +1621,9 @@
       'table' => 'pifr_log',
       'field' => 'log_id',
       'relationship' => 'none',
+      'override' => array(
+        'button' => 'Use default',
+      ),
     ),
     'test_id' => array(
       'label' => 'Test ID',
@@ -1638,7 +1712,7 @@
         'button' => 'Use default',
       ),
     ),
-    'message' => array(
+    'code' => array(
       'label' => 'Message',
       'alter' => array(
         'alter_text' => 0,
@@ -1657,10 +1731,19 @@
         'strip_tags' => 0,
         'html' => 0,
       ),
+      'set_precision' => FALSE,
+      'precision' => 0,
+      'decimal' => '.',
+      'separator' => ',',
+      'prefix' => '',
+      'suffix' => '',
       'exclude' => 0,
-      'id' => 'message',
+      'id' => 'code',
       'table' => 'pifr_log',
-      'field' => 'message',
+      'field' => 'code',
+      'override' => array(
+        'button' => 'Use default',
+      ),
       'relationship' => 'none',
     ),
     'timestamp' => array(
@@ -1713,8 +1796,70 @@
   ));
   $handler = $view->new_display('page', 'Event log (single)', 'page_3');
   $handler->override_option('fields', array(
+    'client_id' => array(
+      'label' => 'Client ID',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'strip_tags' => 0,
+        'html' => 0,
+      ),
+      'set_precision' => FALSE,
+      'precision' => 0,
+      'decimal' => '.',
+      'separator' => ',',
+      'prefix' => '',
+      'suffix' => '',
+      'exclude' => 1,
+      'id' => 'client_id',
+      'table' => 'pifr_client',
+      'field' => 'client_id',
+      'relationship' => 'client_id',
+      'override' => array(
+        'button' => 'Use default',
+      ),
+    ),
+    'title' => array(
+      'label' => 'Title',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'strip_tags' => 0,
+        'html' => 0,
+      ),
+      'exclude' => 1,
+      'id' => 'title',
+      'table' => 'pifr_test',
+      'field' => 'title',
+      'relationship' => 'test_id',
+      'override' => array(
+        'button' => 'Use default',
+      ),
+    ),
     'log_id' => array(
-      'label' => 'Log ID',
+      'label' => 'ID',
       'alter' => array(
         'alter_text' => 0,
         'text' => '',
@@ -1743,8 +1888,11 @@
       'table' => 'pifr_log',
       'field' => 'log_id',
       'relationship' => 'none',
+      'override' => array(
+        'button' => 'Use default',
+      ),
     ),
-    'message' => array(
+    'code' => array(
       'label' => 'Message',
       'alter' => array(
         'alter_text' => 0,
@@ -1763,10 +1911,19 @@
         'strip_tags' => 0,
         'html' => 0,
       ),
+      'set_precision' => FALSE,
+      'precision' => 0,
+      'decimal' => '.',
+      'separator' => ',',
+      'prefix' => '',
+      'suffix' => '',
       'exclude' => 0,
-      'id' => 'message',
+      'id' => 'code',
       'table' => 'pifr_log',
-      'field' => 'message',
+      'field' => 'code',
+      'override' => array(
+        'button' => 'Use default',
+      ),
       'relationship' => 'none',
     ),
     'timestamp' => array(
@@ -1822,6 +1979,10 @@
       'validate_user_argument_type' => 'uid',
       'validate_user_roles' => array(
         '2' => 0,
+        '6' => 0,
+        '3' => 0,
+        '5' => 0,
+        '4' => 0,
       ),
       'override' => array(
         'button' => 'Use default',
@@ -1831,9 +1992,8 @@
       'default_argument_fixed' => '',
       'default_argument_php' => '',
       'validate_argument_node_type' => array(
-        'project_project' => 0,
-        'project_release' => 0,
-        'project_issue' => 0,
+        'forum' => 0,
+        'book' => 0,
         'page' => 0,
         'story' => 0,
       ),
@@ -1841,7 +2001,6 @@
       'validate_argument_nid_type' => 'nid',
       'validate_argument_vocabulary' => array(
         '1' => 0,
-        '2' => 0,
       ),
       'validate_argument_type' => 'tid',
       'validate_argument_transform' => 0,
@@ -1862,7 +2021,7 @@
     'type' => 'none',
     'title' => '',
     'description' => '',
-    'weight' => 0,
+    'weight' => '0',
     'name' => 'navigation',
   ));
   $handler->override_option('tab_options', array(
@@ -1873,8 +2032,42 @@
   ));
   $handler = $view->new_display('page', 'Event log (single, recent)', 'page_4');
   $handler->override_option('fields', array(
+    'client_id' => array(
+      'label' => 'Client ID',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'strip_tags' => 0,
+        'html' => 0,
+      ),
+      'set_precision' => FALSE,
+      'precision' => 0,
+      'decimal' => '.',
+      'separator' => ',',
+      'prefix' => '',
+      'suffix' => '',
+      'exclude' => 1,
+      'id' => 'client_id',
+      'table' => 'pifr_client',
+      'field' => 'client_id',
+      'relationship' => 'client_id',
+      'override' => array(
+        'button' => 'Use default',
+      ),
+    ),
     'log_id' => array(
-      'label' => 'Log ID',
+      'label' => 'ID',
       'alter' => array(
         'alter_text' => 0,
         'text' => '',
@@ -1903,8 +2096,11 @@
       'table' => 'pifr_log',
       'field' => 'log_id',
       'relationship' => 'none',
+      'override' => array(
+        'button' => 'Use default',
+      ),
     ),
-    'message' => array(
+    'code' => array(
       'label' => 'Message',
       'alter' => array(
         'alter_text' => 0,
@@ -1923,10 +2119,19 @@
         'strip_tags' => 0,
         'html' => 0,
       ),
+      'set_precision' => FALSE,
+      'precision' => 0,
+      'decimal' => '.',
+      'separator' => ',',
+      'prefix' => '',
+      'suffix' => '',
       'exclude' => 0,
-      'id' => 'message',
+      'id' => 'code',
       'table' => 'pifr_log',
-      'field' => 'message',
+      'field' => 'code',
+      'override' => array(
+        'button' => 'Use default',
+      ),
       'relationship' => 'none',
     ),
     'timestamp' => array(
Index: server/views/pifr_server.views.inc
===================================================================
RCS file: /cvs/drupal/contributions/modules/project_issue_file_review/server/views/pifr_server.views.inc,v
retrieving revision 1.16
diff -u -r1.16 pifr_server.views.inc
--- server/views/pifr_server.views.inc	16 Oct 2009 03:18:58 -0000	1.16
+++ server/views/pifr_server.views.inc	28 Oct 2009 02:59:49 -0000
@@ -470,6 +470,11 @@
   );
 
   $data['pifr_log']['table']['join'] = array(
+    'pifr_client' => array(
+      'left_field' => 'client_id',
+      'field' => 'client_id',
+      'type' => 'INNER',
+    ),
     'pifr_test' => array(
       'left_field' => 'test_id',
       'field' => 'test_id',
@@ -503,6 +508,32 @@
     ),
   );
 
+  $data['pifr_log']['client_id'] = array(
+    'title' => t('Client'),
+    'help' => t('Reference to client.'),
+    'relationship' => array(
+      'base' => 'pifr_client',
+      'field' => 'client_id',
+      'handler' => 'views_handler_relationship',
+      'label' => t('client'),
+    ),
+  );
+
+  $data['pifr_log']['code'] = array(
+    'title' => t('Code'),
+    'help' => t('Event code.'),
+    'field' => array(
+      'handler' => 'views_handler_field_pifr_log_code',
+      'click sortable' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_numeric',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+  );
+
   $data['pifr_log']['timestamp'] = array(
     'title' => t('Timestamp'),
     'help' => t('Date/time when log entry occured.'),
@@ -518,17 +549,6 @@
     ),
   );
 
-  $data['pifr_log']['message'] = array(
-    'title' => t('Message'),
-    'help' => t('The log message.'),
-    'field' => array(
-      'handler' => 'views_handler_field',
-    ),
-    'filter' => array(
-      'handler' => 'views_handler_filter_string',
-    ),
-  );
-
   // ----------------------------------------------------------------
   // pifr_project table -- basic table information.
 
@@ -833,6 +853,9 @@
       'views_handler_field_pifr_client_operations_user' => array(
         'parent' => 'views_handler_field',
       ),
+      'views_handler_field_pifr_log_code' => array(
+        'parent' => 'views_handler_field',
+      ),
       'views_handler_field_pifr_test_type' => array(
         'parent' => 'views_handler_field',
       ),
Index: server/pifr_server.log.inc
===================================================================
RCS file: /cvs/drupal/contributions/modules/project_issue_file_review/server/pifr_server.log.inc,v
retrieving revision 1.6
diff -u -r1.6 pifr_server.log.inc
--- server/pifr_server.log.inc	15 Oct 2009 22:32:46 -0000	1.6
+++ server/pifr_server.log.inc	28 Oct 2009 02:59:49 -0000
@@ -8,15 +8,46 @@
  * Copyright 2008-2009 by Jimmy Berry ("boombatower", http://drupal.org/user/214218)
  */
 
+/*
+ * Log event codes.
+ */
+define('PIFR_SERVER_LOG_CONFIRMATION_START', 1);
+define('PIFR_SERVER_LOG_CONFIRMATION_PASS', 2);
+define('PIFR_SERVER_LOG_CONFIRMATION_FAIL', 3);
+
+define('PIFR_SERVER_LOG_TEST_REQUEST', 4);
+define('PIFR_SERVER_LOG_TEST_REQUEST_MANAGER', 5);
+define('PIFR_SERVER_LOG_TEST_REQUEST_IGNORE', 6);
+
+define('PIFR_SERVER_LOG_CLIENT_REQUEST', 7);
+define('PIFR_SERVER_LOG_CLIENT_RESET', 8);
+define('PIFR_SERVER_LOG_CLIENT_RESULT', 9);
+define('PIFR_SERVER_LOG_CLIENT_RETRIEVE', 10);
+
 /**
  * Log an event that occured to a test.
  *
  * @param interger $test_id Test ID.
- * @param string $message Message describing event.
+ * @param interger $client_id Client ID.
+ * @param integer $code Event code, PIFR_SERVER_LOG_*.
+ * @return array Update log event information.
  */
-function pifr_server_log_event($test_id, $message) {
-  db_query("INSERT INTO {pifr_log} (test_id, timestamp, message)
-            VALUES (%d, %d, '%s')", $test_id, time(), $message);
+function pifr_server_log($test_id, $client_id, $code) {
+  // Check for an invalid event code.
+  if ($code < 1 || $code > 10) {
+    trigger_error('Invalid log event code.', E_USER_ERROR);
+  }
+
+  // Save event to log.
+  $log = array(
+    'test_id' => $test_id,
+    'client_id' => $client_id,
+    'code' => $code,
+    'timestamp' => time(),
+  );
+  drupal_write_record('pifr_log', $log);
+
+  return $log;
 }
 
 /**
@@ -27,3 +58,37 @@
 function pifr_server_log_delete($test_id) {
   db_query('DELETE FROM {pifr_log} WHERE test_id = %d', $test_id);
 }
+
+/**
+ * Get the event message from the code.
+ *
+ * @param integer $code Event code.
+ * @param integer $client_id (Optional) Client ID.
+ * @return string Representation of the event code.
+ */
+function pifr_server_log_code($code, $client_id = 0) {
+  switch ($code) {
+    case PIFR_SERVER_LOG_CONFIRMATION_START:
+      return t('Client confirmation process started.');
+    case PIFR_SERVER_LOG_CONFIRMATION_PASS:
+      return t('Passed confirmation tests.');
+    case PIFR_SERVER_LOG_CONFIRMATION_FAIL:
+      return t('Failed confirmation tests.');
+    case PIFR_SERVER_LOG_TEST_REQUEST:
+      return t('Test request received.');
+    case PIFR_SERVER_LOG_TEST_REQUEST_MANAGER:
+      return t('Re-test requested by manager.');
+    case PIFR_SERVER_LOG_TEST_REQUEST_IGNORE:
+      return t('Re-test request ignored because test is already queued.');
+    case PIFR_SERVER_LOG_CLIENT_REQUEST:
+      return t('Requested by test client #@client_id.', array('@client_id' => $client_id));
+    case PIFR_SERVER_LOG_CLIENT_RESET:
+      return t('Test reset by client request.');
+    case PIFR_SERVER_LOG_CLIENT_RESULT:
+      return t('Result received from test client #@client_id.', array('@client_id' => $client_id));
+    case PIFR_SERVER_LOG_CLIENT_RETRIEVE:
+      return t('Result retrieved by project client.');
+    default:
+      return t('Unknown');
+  }
+}
Index: server/pifr_server.review.inc
===================================================================
RCS file: /cvs/drupal/contributions/modules/project_issue_file_review/server/pifr_server.review.inc,v
retrieving revision 1.3
diff -u -r1.3 pifr_server.review.inc
--- server/pifr_server.review.inc	18 Oct 2009 23:36:48 -0000	1.3
+++ server/pifr_server.review.inc	28 Oct 2009 02:59:49 -0000
@@ -70,6 +70,12 @@
   return $plugin->detail($test, $result);
 }
 
+function pifr_server_review_code_title($environment_id, $code) {
+  $plugin = pifr_server_review_plugin_load_environment($environment_id);
+
+  return $plugin->code_title($code);
+}
+
 function pifr_server_review_load(array $result) {
   $plugin = pifr_server_review_plugin_load_environment($result['environment_id']);
 
Index: server/pifr_server.client.inc
===================================================================
RCS file: /cvs/drupal/contributions/modules/project_issue_file_review/server/pifr_server.client.inc,v
retrieving revision 1.43
diff -u -r1.43 pifr_server.client.inc
--- server/pifr_server.client.inc	18 Oct 2009 23:36:48 -0000	1.43
+++ server/pifr_server.client.inc	28 Oct 2009 02:59:49 -0000
@@ -104,6 +104,21 @@
 }
 
 /**
+ * Determine the last time a client was active.
+ *
+ * @param array $client Client information.
+ * @return integer Timestamp when client was last active, or FALSE.
+ */
+function pifr_server_client_get_last_active(array $client) {
+  $result = db_query('SELECT timestamp
+                      FROM {pifr_log}
+                      WHERE client_id = %d
+                      ORDER BY timestamp DESC
+                      LIMIT 1', $client['client_id']);
+  return db_result($result);
+}
+
+/**
  * Load client by key and type (client must be enabled or testing).
  *
  * @param string $client_key Client key.
@@ -181,7 +196,7 @@
   pifr_server_client_confirmation_status_clear($client);
 
   // Log event.
-  pifr_server_log_event($test['test_id'], t('Client confirmation process started.'));
+  pifr_server_log($test['test_id'], $client['client_id'], PIFR_SERVER_LOG_CONFIRMATION_START);
 }
 
 /**
@@ -333,7 +348,7 @@
   $client['status'] = PIFR_SERVER_CLIENT_STATUS_ENABLED;
   pifr_server_client_save($client);
 
-  pifr_server_log_event($client['test_id'], t('Passed confirmation tests.'));
+  pifr_server_log($client['test_id'], $client['client_id'], PIFR_SERVER_LOG_CONFIRMATION_PASS);
 }
 
 /**
@@ -345,7 +360,7 @@
   $client['status'] = PIFR_SERVER_CLIENT_STATUS_FAIL;
   pifr_server_client_save($client);
 
-  pifr_server_log_event($client['test_id'], t('Failed confirmation tests.'));
+  pifr_server_log($client['test_id'], $client['client_id'], PIFR_SERVER_LOG_CONFIRMATION_FAIL);
 }
 
 /**
@@ -403,6 +418,27 @@
 }
 
 /**
+ * Render the environments a client can review.
+ *
+ * @param array $client Client information.
+ * @return string HTML output.
+ */
+function pifr_server_client_environment_render(array $client) {
+  $environments = array();
+  foreach ($client['environment'] as $environment_id => $enabled) {
+    if ($enabled) {
+      $environment = pifr_server_environment_get($environment_id);
+      $environments[] = $environment['title'];
+    }
+  }
+
+  if ($environments) {
+    return count($environments) > 1 ? theme('item_list', $environments) : $environments[0];
+  }
+  return '<em>' . t('None') . '</em>';
+}
+
+/**
  * Get the client type from the code.
  *
  * @param integer $type Client type code.
@@ -460,22 +496,7 @@
   public function getInfoTable() {
     $rows = array();
 
-    $environments = array();
-    foreach ($this->client['environment'] as $environment_id => $enabled) {
-      if ($enabled) {
-        $environment = pifr_server_environment_get($environment_id);
-        $environments[] = $environment['title'];
-      }
-    }
-
-    $rows['type'] = array(t('Type'), pifr_server_client_type($this->client['type']));
-    if ($environments) {
-      $environment = count($environments) > 1 ? theme('item_list', $environments) : $environments[0];
-    }
-    else {
-      $environment = '<em>' . t('None') . '</em>';
-    }
-    $rows['environment'] = array(t('Environment'), $environment);
+    $rows['environment'] = array(t('Environment'), pifr_server_client_environment_render($this->client));
     $rows['status'] = array(t('Status'), pifr_server_client_status($this->client['status']));
 
     return $this->formatTable($rows);
Index: server/pifr_server.module
===================================================================
RCS file: /cvs/drupal/contributions/modules/project_issue_file_review/server/pifr_server.module,v
retrieving revision 1.48
diff -u -r1.48 pifr_server.module
--- server/pifr_server.module	19 Oct 2009 00:59:06 -0000	1.48
+++ server/pifr_server.module	28 Oct 2009 02:59:49 -0000
@@ -134,6 +134,12 @@
   );
 }
 
+/**
+ * Format date.
+ *
+ * @param integer $timestamp Timestamp to format.
+ * @return string Formated date or "<em>Never</em>".
+ */
 function pifr_server_format_date($timestamp) {
   if ($timestamp) {
     return format_date($timestamp);
Index: server/pifr_server.page.inc
===================================================================
RCS file: /cvs/drupal/contributions/modules/project_issue_file_review/server/pifr_server.page.inc,v
retrieving revision 1.9
diff -u -r1.9 pifr_server.page.inc
--- server/pifr_server.page.inc	25 Sep 2009 00:49:24 -0000	1.9
+++ server/pifr_server.page.inc	28 Oct 2009 02:59:49 -0000
@@ -7,13 +7,19 @@
  * Copyright 2008-2009 by Jimmy Berry ("boombatower", http://drupal.org/user/214218)
  */
 
+define('PIFR_SERVER_CLIENT_THRESHOLD_ACTIVE', 60 * 60 * 4);
+define('PIFR_SERVER_CLIENT_THRESHOLD_IDLE', 60 * 60 * 24);
+
 /**
  * View the status of testing.
  *
  * @return string HTML output.
  */
 function pifr_server_page_status() {
+  module_load_include('statistic.inc', 'pifr_server');
+
   drupal_add_css(drupal_get_path('module', 'pifr') . '/pifr.css');
+  drupal_add_css(drupal_get_path('module', 'pifr_server') . '/pifr_server.css');
 
   $form = array();
 
@@ -21,16 +27,36 @@
     '#type' => 'fieldset',
     '#title' => t('General'),
     '#weight' => -10,
-    '#value' => t('Testing is %status. Please see home page for details.',
-                  array('%status' => (PIFR_ACTIVE ? 'enabled': 'disabled'))),
+  );
+  $form['general']['status'] = array(
+    '#type' => 'markup',
+    '#value' => t('<b>Status</b>: %status', array('%status' => (PIFR_ACTIVE ? 'enabled': 'disabled'))),
+    '#weight' => -10,
   );
 
-  $form['statistics'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Statistics'),
+  // Generate a set of graphs for the tabset.
+  $form['general']['graphs'] = array(
+    '#type' => 'tabset',
     '#weight' => -9,
-    '#value' => pifr_server_page_status_statistics(),
+    '#prefix' => '<div id="pifr-graphs">',
+    '#suffix' => '</div>',
   );
+  $i = -10;
+  foreach (array('queue', 'capacity', 'usage') as $graph) {
+    $function = 'pifr_server_page_status_graph_' . $graph;
+    $form['general']['graphs'][$graph] = array(
+      '#type' => 'tabpage',
+      '#title' => t(ucfirst($graph)),
+      '#content' => $function(),
+      '#weight' => $i++,
+    );
+  }
+
+  // If queue is empty then default to the capacity graph.
+  if (!$form['general']['graphs']['queue']['#content']) {
+    $form['general']['graphs']['queue']['#content'] = '<em>' . t('Queue is empty.') . '</em>';
+    $form['general']['graphs']['capacity']['#selected'] = TRUE;
+  }
 
   $form['project_clients'] = array(
     '#type' => 'fieldset',
@@ -50,81 +76,94 @@
     '#weight' => -7,
   );
 
+  drupal_alter('pifr_server_status_view', $form);
+
   return drupal_render($form);
 }
 
-function pifr_server_page_status_statistics() {
-  // Queue.
-  $queue = array(
-    '#chart_id' => 'status_queue',
-    '#title' => t('Queue'),
+/**
+ * Generate a graph of the queue state.
+ *
+ * @return string HTML representing graph.
+ */
+function pifr_server_page_status_graph_queue() {
+  // Initialize graph.
+  $graph = array(
+    '#chart_id' => 'pifr_queue',
     '#type' => CHART_TYPE_PIE_3D,
     '#size' => chart_size(350, 150),
     '#data' => array(),
     '#labels' => array(),
   );
 
-  $result = db_query('SELECT COUNT(test_id) AS count, status
-                      FROM {pifr_test}
-                      GROUP BY status
-                      ORDER BY count');
+  // Determine the number of tests that are active.
+  $active_count = pifr_server_statistic_active_count();
+  $graph['#data']['active'] = $active_count;
+  $graph['#labels']['active'] = t('Active') . ': ' . $active_count;
+
+  // Determine the number of queued tests.
+  $queue_count = pifr_server_statistic_queue_count();
+  $graph['#data']['queue'] = $queue_count;
+  $graph['#labels']['queue'] = pifr_server_test_status(PIFR_SERVER_TEST_STATUS_QUEUED) . ': ' . $queue_count;
 
-  while ($type = db_fetch_array($result)) {
-    $queue['#data'][$type['status']] = $type['count'];
-    $queue['#labels'][$type['status']] = pifr_server_test_status($type['status']) . ': ' . $type['count'];
+  if (!$graph['#data']['active'] && !$graph['#data']['queue']) {
+    return FALSE;
   }
 
-  $out = chart_render($queue);
-
-  // Capacity.
-  $active = 0;
-  $total = 0;
-
-  $clients = pifr_server_client_get_type(PIFR_SERVER_CLIENT_TYPE_TEST);
-  foreach ($clients as $client) {
-    if ($client['status'] == PIFR_SERVER_CLIENT_STATUS_DISABLED) {
-      continue;
-    }
-
-    $deadtime = time() - $client['last_active'];
-    if ($deadtime < PIFR_SERVER_CLIENT_TEST_INTERVAL * 60 * 60) {
-      $active++;
-    }
-    $total++;
-  }
+  return chart_render($graph);
+}
 
-  $capacity = array(
-    '#chart_id' => 'capacity',
-    '#title' => t('Capacity'),
+/**
+ * Generate a graph of the test network capacity.
+ *
+ * @return string HTML representing graph.
+ */
+function pifr_server_page_status_graph_capacity() {
+  $enabled_count = pifr_server_statistic_enabled_count();
+  $total_count = count(pifr_server_client_get_type(PIFR_SERVER_CLIENT_TYPE_TEST));
+
+  $graph = array(
+    '#chart_id' => 'pifr_capacity',
+    '#title' => t('Test clients enabled: @enabled of @total.',
+      array('@enabled' => $enabled_count, '@total' => $total_count)),
     '#type' => CHART_TYPE_GMETER,
     '#size' => chart_size(300, 150),
-    '#data' => array($total ? $active / $total * 100 : 0),
+    '#data' => array($total_count ? $enabled_count / $total_count * 100 : 0),
   );
-  $out .= chart_render($capacity);
-
-  // Usage. (TODO PIFR_SERVER_TEST_STATUS_SENT has been removed)
-  $sent = isset($queue['#data'][PIFR_SERVER_TEST_STATUS_SENT]) ? $queue['#data'][PIFR_SERVER_TEST_STATUS_SENT] : 0;
+  return chart_render($graph);
+}
 
-  $usage = array(
-    '#chart_id' => 'usage',
-    '#title' => t('Usage'),
+/**
+ * Generate a graph of the test network usage.
+ *
+ * @return string HTML representing graph.
+ */
+function pifr_server_page_status_graph_usage() {
+  $active_count = pifr_server_statistic_active_count();
+  $enabled_count = pifr_server_statistic_enabled_count();
+
+  $graph = array(
+    '#chart_id' => 'pifr_usage',
+    '#title' => t('Test clients in use: @active of @enabled.',
+      array('@active' => $active_count, '@enabled' => $enabled_count)),
     '#type' => CHART_TYPE_GMETER,
     '#size' => chart_size(300, 150),
-    '#data' => array($actve ? $sent / $active * 100 : 0),
+    '#data' => array($enabled_count ? $active_count / $enabled_count * 100 : 0),
     '#data_colors' => array('00FF00', 'FFFF00', 'FF8040', 'FF0000'),
   );
-  $out .= chart_render($usage);
-
-  return $out;
+  return chart_render($graph);
 }
 
+/**
+ * Generate a list of clients.
+ *
+ * @param integer $client_type Client type, PIFR_SERVER_CLIENT_TYPE_*.
+ * @return string HTML output.
+ */
 function pifr_server_page_status_client_list($client_type) {
   $clients = pifr_server_client_get_type($client_type);
 
-  $header = array(t('Client'), t('Environment'), t('Status'), t('Last active'), t('Manager'));
-  if ($client_type == PIFR_SERVER_CLIENT_TYPE_PROJECT) {
-    unset($header[1]);
-  }
+  $header = array(t('Client'), t('Environment(s)'), t('Status'), t('Last active'), t('Idle'), t('Manager'));
   $rows = array();
   foreach ($clients as $client) {
     if ($client['status'] == PIFR_SERVER_CLIENT_STATUS_DISABLED) {
@@ -132,78 +171,166 @@
     }
 
     $row = array();
-
     $row[] = $client['client_id'];
 
-    if ($client_type == PIFR_SERVER_CLIENT_TYPE_TEST) {
-      $row[] = pifr_server_client_environment($client['environment_id']);
+    // Project clients do not related to an environment.
+    if ($client['type'] == PIFR_SERVER_CLIENT_TYPE_TEST) {
+      $row[] = pifr_server_client_environment_render($client);
     }
 
-    $row[] = pifr_server_client_status($client['status']);
-    $row[] = pifr_server_format_date($client['last_active']);
+    // Determine the last time the client was active.
+    $last_active = pifr_server_client_get_last_active($client);
+
+    // Determine the amount of time the server has been idle.
+    $idletime = time() - $last_active;
+
+    $row[] = l(pifr_server_client_status($client['status']), 'pifr/test/' . $client['test_id']);
+    $row[] = pifr_server_format_date($last_active);
+    $row[] = $last_active ? format_interval($idletime) : '--';
     $row[] = theme('username', user_load($client['uid']));
 
-    $deadtime = time() - $client['last_active'];
-    if ($deadtime < 60 * 60 * 2) {
+    // Determine the class to color the row with based on the idle time.
+    if ($idletime <= PIFR_SERVER_CLIENT_THRESHOLD_ACTIVE) {
       $class = 'pifr-pass';
     }
-    elseif ($deadtime > 60 * 60 * 2 && $deadtime < 60 * 60 * 24) {
+    elseif ($idletime > PIFR_SERVER_CLIENT_THRESHOLD_ACTIVE && $idletime <= PIFR_SERVER_CLIENT_THRESHOLD_IDLE) {
       $class = 'pifr-exception';
     }
     else {
       $class = 'pifr-fail';
     }
 
-    $rows[] = array('class' => $class, 'data' => $row);
+    $rows[] = array(
+      'class' => $class,
+      'data' => $row
+    );
+  }
+
+  // Project clients do not related to an environment.
+  if ($client_type == PIFR_SERVER_CLIENT_TYPE_PROJECT) {
+    unset($header[1]);
+  }
+
+  // If rows then display table, otherwise empty message.
+  if ($rows) {
+    return theme('table', $header, $rows);
   }
-  return theme('table', $header, $rows);
+  return '<em>' . t('No clients to display.') . '</em>';
 }
 
+/**
+ * View statistics.
+ *
+ * @return string HTML output.
+ */
 function pifr_server_page_statistics() {
-  $out = '';
+  module_load_include('statistic.inc', 'pifr_server');
 
-  // Test result breakdown graph.
-  $results = db_query('SELECT code, COUNT(code) AS count
-                       FROM {pifr_result}
-                       WHERE test_id NOT IN (
-                         SELECT test_id
-                         FROM {pifr_client}
-                       )
-                       GROUP BY code
-                       ORDER BY count');
+  drupal_add_css(drupal_get_path('module', 'pifr_server') . '/pifr_server.css');
+
+  $form = array();
+
+  $form['general'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('General'),
+    '#weight' => -10,
+  );
+
+  // Generate a table of general statistics.
+  $general = pifr_server_statistic_general();
+  $header = array(t('Key'), t('Value'));
+  $rows = array(
+    array(t('Number of tests reviewed'), number_format($general['test_count'])),
+    array(t('Number of reviews performed'), number_format($general['review_count'])),
+    array(t('Average number of times a test is reviewd'), number_format($general['review_average'])),
+  );
+  $form['general']['table'] = array(
+    '#type' => 'markup',
+    '#value' => theme('table', $header, $rows),
+    '#weight' => -10,
+  );
+
+  // Genate result breakdown summary graph and one for each environment.
+  $form['general']['results'] = array(
+    '#type' => 'tabset',
+    '#weight' => -9,
+    '#prefix' => '<div id="pifr-graphs">',
+    '#suffix' => '</div>',
+  );
+  $form['general']['results'][] = array(
+    '#type' => 'tabpage',
+    '#title' => t('Summary'),
+    '#content' => pifr_server_page_statistics_breakdown_graph(pifr_server_statistic_breakdown()),
+  );
 
+  // Cycle through each environment and create a result breakdown graph.
+  $environments = pifr_server_environment_get_all();
+  foreach ($environments as $environment) {
+    $breakdown = pifr_server_statistic_breakdown($environment['environment_id']);
+
+    $form['general']['results'][$environment['environment_id']] = array(
+      '#type' => 'tabpage',
+      '#title' => $environment['title'],
+      '#content' => pifr_server_page_statistics_breakdown_graph($breakdown, $environment['environment_id']),
+    );
+  }
+
+  drupal_alter('pifr_server_statistics_view', $form);
+
+  return drupal_render($form);
+}
+
+/**
+ * Generate a breakdown graph.
+ *
+ * @param array $breakdown Breakdown information.
+ * @param integer $environment_id (Optional) Environment ID.
+ * @return string HTML output.
+ */
+function pifr_server_page_statistics_breakdown_graph(array $breakdown, $environment_id = 0) {
+  // Initialize chart information.
   $chart = array(
-    '#chart_id' => 'result_breakdown',
-    '#title' => t('Test result breakdown'),
+    '#chart_id' => 'pifr_server_result_breakdown_' . $environment_id,
+    '#title' => t('Result breakdown'),
     '#type' => CHART_TYPE_PIE_3D,
-    '#size' => chart_size(600, 200)
+    '#size' => chart_size(600, 200),
+    '#data' => array(),
+    '#labels' => array(),
   );
 
-  $chart['#data'] = array();
-  $chart['#labels'] = array();
-  while ($result = db_fetch_object($results)) {
-    $chart['#data'][] = $result->count;
-    $chart['#labels'][] = pifr_server_result_get_summary_message_minimal($result->code);
-  }
-
-  $out .= chart_render($chart);
-
-  // Numerical test statistics.
-  $test_count = db_result(db_query('SELECT COUNT(test_id)
-                                    FROM {pifr_test}
-                                    WHERE test_count > 0'));
-  $suite_runs = db_result(db_query('SELECT SUM(test_count)
-                                    FROM {pifr_test}'));
-  $assertions = db_result(db_query('SELECT MAX(pass + fail + exception)
-                                    FROM {pifr_result}'));
+  // If graphing an individual environment then graph data only needs to be
+  // added for that environment, otherwise cycle through all the environments
+  // combine the data.
+  if ($environment_id) {
+    pifr_server_page_statistics_breakdown_graph_data($chart['#data'], $chart['#labels'], $breakdown, $environment_id);
+  }
+  else {
+    foreach ($breakdown as $environment_id => $data) {
+      pifr_server_page_statistics_breakdown_graph_data($chart['#data'], $chart['#labels'], $data, $environment_id);
+    }
+  }
 
-  $header = array(t('Key'), t('Value'));
-  $rows = array();
-  $rows[] = array(t('Test count'), $test_count);
-  $rows[] = array(t('Test suite runs'), $suite_runs);
-  $rows[] = array(t('Maximum assertion count'), $assertions);
+  // Sort data so that it appears cleanly in graph.
+  asort($chart['#data']);
 
-  $out .= theme('table', $header, $rows, array('style' => 'width: auto'));
+  return chart_render($chart);
+}
 
-  return $out;
+/**
+ * Generate breakdown graph data and labels.
+ *
+ * @param array $data Reference to graph data.
+ * @param array $labels Reference to graph labels.
+ * @param array $breakdown Breakdown information.
+ * @param integer $environment_id (Optional) Environment ID.
+ */
+function pifr_server_page_statistics_breakdown_graph_data(array &$data, array &$labels, array $breakdown, $environment_id) {
+  foreach ($breakdown as $code => $count) {
+    // Use a key to ensure that data and labels match up after being sorted.
+    $key = $environment_id . ':' . $code;
+
+    // Add data and label representing code to chart.
+    $data[$key] = $count;
+    $labels[$key] = pifr_server_review_code_title($environment_id, $code);
+  }
 }
Index: server/pifr_server.xmlrpc.inc
===================================================================
RCS file: /cvs/drupal/contributions/modules/project_issue_file_review/server/pifr_server.xmlrpc.inc,v
retrieving revision 1.34
diff -u -r1.34 pifr_server.xmlrpc.inc
--- server/pifr_server.xmlrpc.inc	18 Oct 2009 23:36:48 -0000	1.34
+++ server/pifr_server.xmlrpc.inc	28 Oct 2009 02:59:49 -0000
@@ -83,10 +83,10 @@
     $projects = pifr_server_xmlrpc_project_save($batch['projects'], $client['client_id']);
 
     // Store branch data and retrieve completed branch information.
-    $branches = pifr_server_xmlrpc_branch_save($batch['branches'], $projects);
+    $branches = pifr_server_xmlrpc_branch_save($batch['branches'], $projects, $client);
 
     // Store branch data and retrieve completed file information.
-    $files = pifr_server_xmlrpc_file_save($batch['files'], $branches);
+    $files = pifr_server_xmlrpc_file_save($batch['files'], $branches, $client);
 
     // Postpone tests if branch is currently failing.
     foreach ($branches as $branch) {
@@ -144,9 +144,10 @@
  *
  * @param array $branches Branches to save.
  * @param array $projects Projects that branches relate to.
+ * @param array $client Client information.
  * @return array Saved branches.
  */
-function pifr_server_xmlrpc_branch_save(array $branches, array $projects) {
+function pifr_server_xmlrpc_branch_save(array $branches, array $projects, array $client) {
   $saved = array();
   foreach ($branches as $branch) {
     if (!isset($projects[$branch['project_identifier']])) {
@@ -164,7 +165,7 @@
     // If branch is to be tested then update test record.
     if ($branch['test']) {
       $test = pifr_server_test_get($saved[$branch['client_identifier']]['test_id']);
-      pifr_server_xmlrpc_test_queue($test);
+      pifr_server_xmlrpc_test_queue($test, $client);
     }
   }
   return $saved;
@@ -175,9 +176,10 @@
  *
  * @param array $files Files to save.
  * @param array $branches Branches that files relate to.
+ * @param array $client Client information.
  * @return array Saved files.
  */
-function pifr_server_xmlrpc_file_save(array $files, array $branches) {
+function pifr_server_xmlrpc_file_save(array $files, array $branches, array $client) {
   $saved = array();
   foreach ($files as $file) {
     if (!isset($branches[$file['branch_identifier']])) {
@@ -197,7 +199,7 @@
 
     // Update test record.
     $test = pifr_server_test_get($saved[$file['client_identifier']]['test_id']);
-    pifr_server_xmlrpc_test_queue($test);
+    pifr_server_xmlrpc_test_queue($test, $client);
   }
   return $saved;
 }
@@ -209,16 +211,16 @@
  * be ignored and an appropriate log message will be made.
  *
  * @param array $test Test information.
+ * @param array $client Client information.
  */
-function pifr_server_xmlrpc_test_queue(array $test) {
+function pifr_server_xmlrpc_test_queue(array $test, array $client) {
   if ($test['status'] == PIFR_SERVER_TEST_STATUS_QUEUED) {
-    pifr_server_log_event($test['test_id'], t('Re-test request ignored because test is already queued.'));
+    pifr_server_log($test['test_id'], $client['client_id'], PIFR_SERVER_LOG_TEST_REQUEST_IGNORE);
   }
   else {
     pifr_server_test_queue($test);
 
-    pifr_server_log_event($test['test_id'], t('@action request received.',
-                          array('@action' => $test['test_count'] == 0 ? t('Test') : t('Re-test'))));
+    pifr_server_log($test['test_id'], $client['client_id'], PIFR_SERVER_LOG_TEST_REQUEST);
   }
 }
 
@@ -411,7 +413,7 @@
         'pass' => !$result,
         'message' => pifr_server_result_summary_message($result),
       );
-      pifr_server_log_event($test['test_id'], t('Result retrieved by project client.'));
+      pifr_server_log($test['test_id'], $client['client_id'], PIFR_SERVER_LOG_CLIENT_RETRIEVE);
       $count++;
     }
 
Index: server/pifr_server.install
===================================================================
RCS file: /cvs/drupal/contributions/modules/project_issue_file_review/server/pifr_server.install,v
retrieving revision 1.37
diff -u -r1.37 pifr_server.install
--- server/pifr_server.install	10 Oct 2009 21:39:04 -0000	1.37
+++ server/pifr_server.install	28 Oct 2009 02:59:49 -0000
@@ -326,22 +326,28 @@
         'type' => 'int',
         'not null' => FALSE,
       ),
+      'client_id' => array(
+        'description' => t('Reference to client (if any) that was involved in the event.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'code' => array(
+        'description' => t('Event code, PIFR_SERVER_LOG_*.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
       'timestamp' => array(
         'description' => t('Timestamp when the event occured.'),
         'type' => 'int',
         'unsigned' => FALSE,
         'not null' => FALSE,
       ),
-      'message' => array(
-        'description' => t('Message related to event.'),
-        'type' => 'varchar',
-        'not null' => TRUE,
-        'length' => 255,
-        'default' => '',
-      ),
     ),
     'indexes' => array(
       'test_id' => array('test_id'),
+      'client_id' => array('client_id'),
     ),
     'primary key' => array('log_id'),
   );
Index: server/pifr_server.test.inc
===================================================================
RCS file: /cvs/drupal/contributions/modules/project_issue_file_review/server/pifr_server.test.inc,v
retrieving revision 1.52
diff -u -r1.52 pifr_server.test.inc
--- server/pifr_server.test.inc	27 Oct 2009 01:36:58 -0000	1.52
+++ server/pifr_server.test.inc	28 Oct 2009 02:59:49 -0000
@@ -71,7 +71,7 @@
   else if ($client['status'] == PIFR_SERVER_CLIENT_STATUS_ENABLED) {
     // If the client currently has a test out, reset the test.
     if ($test = pifr_server_test_get_client($client)) {
-      pifr_server_test_reset($test);
+      pifr_server_test_reset($test, $client);
     }
 
     // Return the next eligible branch or file test.
@@ -254,20 +254,20 @@
   pifr_server_test_save($test);
 
   // Log the event.
-  pifr_server_log_event($test['test_id'], t('Requested by test client #@client_id.',
-                                            array('@client_id' => $client['client_id'])));
+  pifr_server_log($test['test_id'], $client['client_id'], PIFR_SERVER_LOG_CLIENT_REQUEST);
 }
 
 /**
  * Perform test reset event operations.
  *
  * @param array $test Test information.
+ * @param array $client Client information.
  */
-function pifr_server_test_reset(array $test) {
+function pifr_server_test_reset(array $test, array $client) {
   pifr_server_test_queue($test);
 
   // Log the event.
-  pifr_server_log_event($test['test_id'], t('Test reset by client request.'));
+  pifr_server_log($test['test_id'], $client['client_id'], PIFR_SERVER_LOG_CLIENT_RESET);
 }
 
 /**
@@ -303,8 +303,7 @@
   $result = pifr_server_result_save($result);
 
   // Log the test result event.
-  pifr_server_log_event($test['test_id'], t('Result received from test client #@client_id.',
-                                            array('@client_id' => $client['client_id'])));
+  pifr_server_log($test['test_id'], $client['client_id'], PIFR_SERVER_LOG_CLIENT_RESULT);
 
   // If client is undergoing testing then allow the results to be checked based
   // on the client confirmation testing stage. If testing is incomplete then
@@ -576,7 +575,7 @@
     }
     else {
       pifr_server_test_queue($test);
-      pifr_server_log_event($test['test_id'], 'Re-test requested by manager.');
+      pifr_server_log($test['test_id'], 0, PIFR_SERVER_LOG_TEST_REQUEST_MANAGER);
 
       drupal_set_message(t('Removed result and queued %title.', array('%title' => $test['title'])));
     }
Index: server/pifr_server.css
===================================================================
RCS file: /cvs/drupal/contributions/modules/project_issue_file_review/server/pifr_server.css,v
retrieving revision 1.3
diff -u -r1.3 pifr_server.css
--- server/pifr_server.css	25 Sep 2009 06:07:44 -0000	1.3
+++ server/pifr_server.css	28 Oct 2009 02:59:49 -0000
@@ -55,3 +55,9 @@
 .pifr-assertion-header.odd:hover, .pifr-assertion-header.even:hover {
 	background-color: white;
 }
+
+/* Status page
+ **************/
+#pifr-graphs div.ui-tabs-panel {
+  text-align: center;
+}
Index: review/simpletest/pifr_simpletest.server.inc
===================================================================
RCS file: /cvs/drupal/contributions/modules/project_issue_file_review/review/simpletest/pifr_simpletest.server.inc,v
retrieving revision 1.4
diff -u -r1.4 pifr_simpletest.server.inc
--- review/simpletest/pifr_simpletest.server.inc	18 Oct 2009 23:36:48 -0000	1.4
+++ review/simpletest/pifr_simpletest.server.inc	28 Oct 2009 02:59:49 -0000
@@ -355,4 +355,31 @@
         return 'Unknown';
     }
   }
+
+  public function code_title($code) {
+     switch ($code) {
+      case PIFR_SERVER_TEST_RESULT_SETUP:
+        return t('setup environment');
+      case PIFR_SERVER_TEST_RESULT_FETCH:
+        return t('invalid file URL');
+      case PIFR_SERVER_TEST_RESULT_CVS:
+        return t('invalid repository information');
+      case PIFR_SERVER_TEST_RESULT_PATCH:
+        return t('invalid patch format');
+      case PIFR_SERVER_TEST_RESULT_APPLY:
+        return t('non-applicable patch');
+      case PIFR_SERVER_TEST_RESULT_SYNTAX:
+        return t('invalid PHP syntax');
+      case PIFR_SERVER_TEST_RESULT_INSTALL:
+        return t('Drupal installation failure');
+      case PIFR_SERVER_TEST_RESULT_TEST:
+        return t('test run failure');
+      case PIFR_SERVER_TEST_RESULT_FAIL:
+        return t('failing test');
+      case PIFR_SERVER_TEST_RESULT_PASS:
+        return t('all tests passing');
+      default:
+        return 'Unknown';
+    }
+  }
 }
Index: server/pifr_server.statistic.inc
===================================================================
RCS file: server/pifr_server.statistic.inc
diff -N server/pifr_server.statistic.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ server/pifr_server.statistic.inc	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,124 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Provide statistic functions.
+ *
+ * Copyright 2008-2009 by Jimmy Berry ("boombatower", http://drupal.org/user/214218)
+ */
+
+/**
+ * Determine the number of active tests.
+ *
+ * @return integer Number of active tests.
+ */
+function pifr_server_statistic_active_count() {
+  static $active_count;
+
+  if (!isset($active_count)) {
+    $result = db_query('SELECT COUNT(test_id)
+                        FROM (
+                          SELECT s.test_id
+                          FROM {pifr_environment_status} s
+                          JOIN {pifr_test} t
+                            ON s.test_id = t.test_id
+                          WHERE t.type != %d
+                          GROUP BY test_id
+                        ) x', PIFR_SERVER_TEST_TYPE_CLIENT);
+    $active_count = db_result($result);
+  }
+  return $active_count;
+}
+
+/**
+ * Determine the number of queued tests.
+ *
+ * @return integer Number of queued tests.
+ */
+function pifr_server_statistic_queue_count() {
+  static $queue_count;
+
+  if (!isset($queue_count)) {
+    $result = db_query('SELECT COUNT(test_id)
+                        FROM {pifr_test}
+                        WHERE type != %d
+                        AND status = %d', PIFR_SERVER_TEST_TYPE_CLIENT, PIFR_SERVER_TEST_STATUS_QUEUED);
+    $queue_count = db_result($result);
+  }
+  return $queue_count;
+}
+
+/**
+ * Determine the number of enabled test clients.
+ *
+ * @return integer Number of enabled test clients.
+ */
+function pifr_server_statistic_enabled_count() {
+  static $enabled_count;
+
+  if (!isset($enabled_count)) {
+    $clients = pifr_server_client_get_type(PIFR_SERVER_CLIENT_TYPE_TEST);
+    $enabled_count = 0;
+    foreach ($clients as $client) {
+      if ($client['status'] == PIFR_SERVER_CLIENT_STATUS_ENABLED) {
+        $enabled_count++;
+      }
+    }
+  }
+  return $enabled_count;
+}
+
+/**
+ * Generate a number of general statistics.
+ *
+ * @return array Associative array of general statistics with the following
+ *   keys: test_count, review_count, review_average.
+ */
+function pifr_server_statistic_general() {
+  $general = array(
+    'test_count' => 'SELECT COUNT(test_id) FROM {pifr_test} WHERE test_count > 0 AND type != %d',
+    'review_count' => 'SELECT SUM(test_count) FROM {pifr_test} WHERE type != %d',
+    'review_average' => 'SELECT AVG(test_count) FROM {pifr_test} WHERE type != %d',
+  );
+
+  // Execute each query to determine the value of the statistic.
+  foreach ($general as $key => $query) {
+    $general[$key] = db_result(db_query($query, PIFR_SERVER_TEST_TYPE_CLIENT));
+  }
+  return $general;
+}
+
+/**
+ * Determine the result breakdown.
+ *
+ * @param integer $environment_id (Optional) Environment ID.
+ * @return array If an environment is specified reakdown information in the
+ *   form $code => $count, otherwise wrapped by an associative array of
+ *   environemnt IDs.
+ */
+function pifr_server_statistic_breakdown($environment_id = NULL) {
+  $sql = 'SELECT r.environment_id, r.code, COUNT(r.result_id) AS count
+          FROM {pifr_result} r
+          JOIN {pifr_test} t
+            ON r.test_id = t.test_id
+          WHERE t.type != %d
+          ' . ($environment_id ? 'AND r.environment_id = %d' : '') . '
+          GROUP BY r.environment_id, r.code
+          ORDER BY count';
+  $results = db_query($sql, PIFR_SERVER_TEST_TYPE_CLIENT, $environment_id);
+
+  $breakdown = array();
+  while ($result = db_fetch_array($results)) {
+    if (!isset($breakdown[$result['environment_id']])) {
+      $breakdown[$result['environment_id']] = array();
+    }
+
+    $breakdown[$result['environment_id']][$result['code']] = $result['count'];
+  }
+
+  if ($environment_id) {
+    return $breakdown[$environment_id];
+  }
+  return $breakdown;
+}
Index: server/views/handlers/views_handler_field_pifr_log_code.inc
===================================================================
RCS file: server/views/handlers/views_handler_field_pifr_log_code.inc
diff -N server/views/handlers/views_handler_field_pifr_log_code.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ server/views/handlers/views_handler_field_pifr_log_code.inc	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,10 @@
+<?php
+// $Id: views_handler_field_pifr_client_environment.inc,v 1.2 2009/07/18 05:20:43 boombatower Exp $
+/**
+ * Field handler to present client environment as string.
+ */
+class views_handler_field_pifr_log_code extends views_handler_field {
+  function render($values) {
+    return pifr_server_log_code($values->{$this->field_alias}, $values->pifr_client_pifr_log_client_id);
+  }
+}
