lots of new features

cmurphy [2008-05-13 18:59:01]
lots of new features
Filename
retina/common/Logger.java
retina/common/OccurrenceMap.java
retina/db/CompilationErrorEventManager.java
retina/db/CompilationEventManager.java
retina/db/DatabaseConnector.java
retina/db/DatabaseManager.java
retina/db/LoginEventManager.java
retina/db/LoginEventServer.java
retina/db/SuggestionManager.java
retina/db/XMLLoader.java
retina/db/XmlServer.java
retina/ui/BrowsePane.java
retina/ui/DBTableModel.java
retina/ui/DateConverter.java
retina/ui/MainPane.java
retina/ui/UserInterfaceManager.java
diff --git a/retina/common/Logger.java b/retina/common/Logger.java
index de68e16..9e8d63c 100644
--- a/retina/common/Logger.java
+++ b/retina/common/Logger.java
@@ -48,6 +48,40 @@ public class Logger
 		log(errorLogFile, msg);
 	}

+	public static void logError(Event e, Exception ex)
+	{
+		if (errorLogFile == null)
+		{
+			// TODO: backup the original
+			try { errorLogFile = new PrintWriter(new File(ERROR_LOG)); }
+			catch (Exception ee) { }
+		}
+
+		String output = "Error on event " + e.toString() + ":\n";
+		output += ex.toString() + "\n";
+		StackTraceElement[] elements = ex.getStackTrace();
+		for (StackTraceElement element : elements)
+			output += element + "\n";
+		log(errorLogFile, output);
+	}
+
+
+	public static void logError(Exception ex)
+	{
+		if (errorLogFile == null)
+		{
+			// TODO: backup the original
+			try { errorLogFile = new PrintWriter(new File(ERROR_LOG)); }
+			catch (Exception ee) { }
+		}
+
+		String output = ex.toString() + "\n";
+		StackTraceElement[] elements = ex.getStackTrace();
+		for (StackTraceElement element : elements)
+			output += element + "\n";
+		log(errorLogFile, output);
+	}
+
 	public static void logWarning(String msg)
 	{
 		if (warningLogFile == null)
diff --git a/retina/common/OccurrenceMap.java b/retina/common/OccurrenceMap.java
index 1b8dc69..1025468 100644
--- a/retina/common/OccurrenceMap.java
+++ b/retina/common/OccurrenceMap.java
@@ -8,8 +8,90 @@ package retina.common;

 public class OccurrenceMap
 {
+	public OccurrenceMap(String[] k, int[] o)
+	{
+		keys = k;
+		occurrences = o;
+	}
+
+	public OccurrenceMap()
+	{
+
+	}
+
 	public String[] keys;
 	public int[] occurrences;

 	public int size() { return keys.length; }
+
+	/**
+	 * This method modifies the occurrence map by sorting the keys and their occurrences.
+	 */
+	public void sortKeys()
+	{
+		for (int i = 0; i < keys.length-1; i++)
+		{
+			String min = keys[i];
+			int minIndex = i;
+			for (int j = i+1; j < keys.length; j++)
+			{
+				if (keys[j].compareTo(min) < 0)
+				{
+					min = keys[j];
+					minIndex = j;
+				}
+			}
+			String temp = keys[i];
+			keys[i] = keys[minIndex];
+			keys[minIndex] = temp;
+
+			int tmp = occurrences[i];
+			occurrences[i] = occurrences[minIndex];
+			occurrences[minIndex] = tmp;
+		}
+	}
+
+	/**
+	 * This method modifies the occurrence map by sorting occurrence values and their keys.
+	 */
+	public void sortValues()
+	{
+		for (int i = 0; i < occurrences.length-1; i++)
+		{
+			int min = occurrences[i];
+			int minIndex = i;
+			for (int j = i+1; j < occurrences.length; j++)
+			{
+				if (occurrences[j] < min)
+				{
+					min = occurrences[j];
+					minIndex = j;
+				}
+			}
+			String temp = keys[i];
+			keys[i] = keys[minIndex];
+			keys[minIndex] = temp;
+
+			int tmp = occurrences[i];
+			occurrences[i] = occurrences[minIndex];
+			occurrences[minIndex] = tmp;
+		}
+	}
+
+
+
+
+	public static void main(String[] args)
+	{
+		String[] keys = { "C", "D", "B", "E", "A" };
+		int[] vals = { 5, 2, 1, 8, 0 };
+		OccurrenceMap map = new OccurrenceMap(keys, vals);
+
+		map.sortKeys();
+
+		for (int i = 0; i < map.size(); i++)
+		{
+			System.out.println(map.keys[i] + " " + map.occurrences[i]);
+		}
+	}
 }
diff --git a/retina/db/CompilationErrorEventManager.java b/retina/db/CompilationErrorEventManager.java
index aef1ced..d9b97d4 100644
--- a/retina/db/CompilationErrorEventManager.java
+++ b/retina/db/CompilationErrorEventManager.java
@@ -7,6 +7,8 @@ import java.util.ArrayList;

 import retina.common.CompilationErrorEvent;
 import retina.common.OccurrenceMap;
+import retina.ui.DateConverter;
+import retina.common.Logger;

 public class CompilationErrorEventManager extends CompilationEventManager
 {
@@ -50,6 +52,8 @@ public class CompilationErrorEventManager extends CompilationEventManager
 		catch(Exception error)
 		{
 			error.printStackTrace();
+			if (Logger.isLogError()) Logger.logError(e, error);
+			return false;
 		}
 		finally
 		{
@@ -113,6 +117,7 @@ public class CompilationErrorEventManager extends CompilationEventManager
 		catch(Exception e)
 		{
 			e.printStackTrace();
+			if (Logger.isLogError()) Logger.logError(e);
 		}
 		finally
 		{
@@ -156,6 +161,7 @@ public class CompilationErrorEventManager extends CompilationEventManager
 		catch(Exception e)
 		{
 			e.printStackTrace();
+			if (Logger.isLogError()) Logger.logError(e);
 		}
 		finally
 		{
@@ -164,7 +170,65 @@ public class CompilationErrorEventManager extends CompilationEventManager
 		return null;
 	}

-
+	/**
+	 * This method gets the number of total compilation errors for ALL students for the given assignment.
+	 */
+	public OccurrenceMap getTotalNumberOfCompilationErrors(String assignment)
+	{
+		try
+		{
+			con = getConnection();
+
+			if (con != null)
+			{
+				// create a Statement
+				Statement stmt = con.createStatement();
+
+				// now create the SQL query
+				String query = "SELECT student, count(*) FROM compilation_errors WHERE assignment = '" + assignment + "' GROUP BY student ORDER BY count(*) DESC";
+
+				// execute the query
+				ResultSet rs = stmt.executeQuery(query);
+				//System.out.println("Executed " + query);
+
+				ArrayList<String> ids = new ArrayList<String>();
+				ArrayList<Integer> occurrences = new ArrayList<Integer>();
+
+				// iterate through the ResultSet and populate the ArrayList
+				int count = 0;
+				while (rs.next())
+				{
+					ids.add(rs.getString(1));
+					occurrences.add(rs.getInt(2));
+
+					count++;
+				}
+
+				// now return the results
+				OccurrenceMap map = new OccurrenceMap();
+				map.keys = ids.toArray(new String[count]);
+				map.occurrences = new int[count];
+				for (int i = 0; i < count; i++)
+				{
+					map.occurrences[i] = occurrences.get(i).intValue();
+				}
+
+				return map;
+			}
+		}
+		catch(Exception e)
+		{
+			e.printStackTrace();
+			if (Logger.isLogError()) Logger.logError(e);
+		}
+		finally
+		{
+			closeConnection();
+		}
+		return null;
+	}
+
+
 	/**
 	 * This method gets the most common errors for ALL students for the given assignment.
 	 */
@@ -207,6 +271,7 @@ public class CompilationErrorEventManager extends CompilationEventManager
 		catch(Exception e)
 		{
 			e.printStackTrace();
+			if (Logger.isLogError()) Logger.logError(e);
 		}
 		finally
 		{
@@ -237,45 +302,52 @@ public class CompilationErrorEventManager extends CompilationEventManager
 				ResultSet rs = stmt.executeQuery(query);
 				//System.out.println("Executed " + query);

-				// we can't actually know the size of the ResultSet in advance
-				// so we can't create an array... yet
-				// use an ArrayList for now
-				// TODO: can we be certain that the ArrayList will keep everything in the right order?
-				ArrayList<String> times = new ArrayList<String>();
-				ArrayList<Integer> events = new ArrayList<Integer>();
-
-				// iterate through the ResultSet and populate the ArrayList
-				int count = 0;
-				while (rs.next())
-				{
-					String month = rs.getString(1);
-					String day = rs.getString(2);
-					String hour = rs.getString(3);
-					String date = month + "-" + day + " " + hour + ":00";
-					times.add(date);
-
-					int compile = rs.getInt(4);
-					events.add(compile);
-
-					count++;
-				}
+				return calculateTimes(rs);
+			}
+		}
+		catch(Exception e)
+		{
+			e.printStackTrace();
+			if (Logger.isLogError()) Logger.logError(e);
+		}
+		finally
+		{
+			closeConnection();
+		}
+		return null;
+
+	}
+
+	/**
+	 * For the specified assignment, this returns an OccurrenceMap that details how many compilation errors occurred
+	 * at different times of the day.
+	 */
+	public OccurrenceMap getCompilationErrorTimes(String assignment, String student)
+	{
+		try
+		{
+			con = getConnection();
+
+			if (con != null)
+			{
+				// create a Statement
+				Statement stmt = con.createStatement();

-				// now return the results
-				OccurrenceMap map = new OccurrenceMap();
-				map.keys = times.toArray(new String[count]);
-				map.occurrences = new int[count];
-				for (int i = 0; i < count; i++)
-				{
-					map.occurrences[i] = events.get(i).intValue();
-				}
+				// now create the SQL query
+				String query = "select datepart(mm, date), datepart(d, date), datepart(hh, date), count(*) from compilation_errors where assignment = '" + assignment + "' and student = '" + student + "' group by datepart(mm, date), datepart(d, date), datepart(hh, date)";

-				return map;
+				// execute the query
+				ResultSet rs = stmt.executeQuery(query);
+				//System.out.println("Executed " + query);

+				// just call the helper method
+				return calculateTimes(rs);
 			}
 		}
 		catch(Exception e)
 		{
 			e.printStackTrace();
+			if (Logger.isLogError()) Logger.logError(e);
 		}
 		finally
 		{
@@ -285,11 +357,130 @@ public class CompilationErrorEventManager extends CompilationEventManager

 	}

+
+	/*
+	 * This is a helper method that takes a ResultSet from a query used to get times when something happened,
+	 * and then it creates an occurrence map that matches the times (grouped by hour) to the number of occurrences.
+	 */
+	private OccurrenceMap calculateTimes(ResultSet rs) throws Exception
+	{
+
+		// we can't actually know the size of the ResultSet in advance
+		// so we can't create an array... yet
+		// use an ArrayList for now
+		// TODO: can we be certain that the ArrayList will keep everything in the right order?
+		ArrayList<String> times = new ArrayList<String>();
+		ArrayList<Integer> events = new ArrayList<Integer>();
+
+		// iterate through the ResultSet and populate the ArrayList
+		int count = 0; // count the number of values so we know how big to make the arrays in the OccurrenceMap
+
+		// these keep track of the last value, in case we need to fill in any blanks
+		String lastHour = null;
+		String lastDay = null;
+		String lastMonth = null;
+
+		while (rs.next())
+		{
+			String month = rs.getString(1);
+			String day = rs.getString(2);
+			String hour = rs.getString(3);
+
+			// in case they're null
+			if (lastHour == null) lastHour = hour;
+			if (lastDay == null) lastDay = day;
+			if (lastMonth == null) lastMonth = month;
+
+			int missingDays = 0;
+
+			int fillInCounter = 0;
+			// this part figures out if we need to fill in any empty times
+			if (Integer.parseInt(hour) - Integer.parseInt(lastHour) > 1 && day.equals(lastDay))
+			{
+				// in this part, there are some hours in which there were no errors
+
+				// figure out the number of spots to fill in
+				fillInCounter = Integer.parseInt(hour) - Integer.parseInt(lastHour) - 1;
+				// for each one, insert a time stamp
+				for (int i = 1; i <= fillInCounter; i++)
+				{
+					int tempHour = Integer.parseInt(lastHour) + i;
+					times.add(month + "-" + day + " " + tempHour + ":00");
+				}
+			}
+			else if (Integer.parseInt(hour) < Integer.parseInt(lastHour) || (Integer.parseInt(day) != Integer.parseInt(lastDay) && Integer.parseInt(hour) != 0))
+			{
+				// in this part, we notice that the current hour is less than the previous, so a day must have changed
+
+				// first, fill in for the rest of the previous day
+				fillInCounter = 23 - Integer.parseInt(lastHour);
+				for (int i = 1; i <= fillInCounter; i++)
+				{
+					int tempHour = Integer.parseInt(lastHour) + i;
+					times.add(lastMonth + "-" + lastDay + " " + tempHour + ":00");
+				}
+
+				// see if it's been more than one day
+				missingDays = Integer.parseInt(day) - Integer.parseInt(lastDay) - 1;
+				//System.out.println(missingDays);
+
+				// fill in any missing days
+				// TODO: this doesn't work across months
+				for (int i = 1; i <= missingDays; i++)
+				{
+					for (int j = 0; j < 24; j++)
+					{
+						times.add(lastMonth + "-" + (Integer.parseInt(lastDay)+i) + " " + j + ":00");
+						events.add(0);
+					}
+				}
+
+				// now we do it for the rest of the current day
+				for (int i = 0; i < Integer.parseInt(hour); i++)
+				{
+					times.add(month + "-" + day + " " + i + ":00");
+				}
+				fillInCounter += Integer.parseInt(hour);
+			}
+
+			// now put in the one we just read from the database
+			String date = month + "-" + day + " " + hour + ":00";
+			times.add(date);
+
+			// if we had any fillins, put zeroes in the events ArrayList
+			for (int i = 0; i < fillInCounter; i++)
+				events.add(0);
+
+			// now put in the one we just read from the database
+			int compile = rs.getInt(4);
+			events.add(compile);
+
+			// update the counter
+			count += fillInCounter + 1 + (missingDays * 24);
+
+			// update the values
+			lastHour = hour;
+			lastDay = day;
+			lastMonth = month;
+		}
+
+		// now return the results
+		OccurrenceMap map = new OccurrenceMap();
+		map.keys = times.toArray(new String[count]);
+		map.occurrences = new int[count];
+		for (int i = 0; i < count; i++)
+		{
+			map.occurrences[i] = events.get(i).intValue();
+		}
+
+		return map;
+
+	}

 	public static void main(String[] args)
 	{
 		CompilationErrorEventManager m = new CompilationErrorEventManager();
-		OccurrenceMap map = m.getCompilationErrorTimes("1");
+		OccurrenceMap map = m.getCompilationErrorTimes("4");
 		for (int i = 0; i < map.keys.length; i++)
 		{
 			System.out.println(map.keys[i] + " " + map.occurrences[i]);
diff --git a/retina/db/CompilationEventManager.java b/retina/db/CompilationEventManager.java
index 8e9d22c..1c2d9f7 100644
--- a/retina/db/CompilationEventManager.java
+++ b/retina/db/CompilationEventManager.java
@@ -5,7 +5,9 @@ import java.sql.Statement;
 import java.util.ArrayList;

 import retina.common.CompilationEvent;
+import retina.common.Logger;
 import retina.common.OccurrenceMap;
+import retina.ui.DateConverter;

 /**
  * This class holds all methods for getting info related to compilation events.
@@ -52,6 +54,8 @@ public class CompilationEventManager extends DatabaseManager
 		catch(Exception error)
 		{
 			error.printStackTrace();
+			if (Logger.isLogError()) Logger.logError(e, error);
+			return false;
 		}
 		finally
 		{
@@ -112,6 +116,7 @@ public class CompilationEventManager extends DatabaseManager
 		catch(Exception e)
 		{
 			e.printStackTrace();
+			if (Logger.isLogError()) Logger.logError(e);
 		}
 		finally
 		{
@@ -119,8 +124,82 @@ public class CompilationEventManager extends DatabaseManager
 		}
 		return null;
 	}
-

+	/**
+	 * This method calculates the working time for ALL students for the given assignment.
+	 */
+	public String[][] getWorkingTimes(String assignment)
+	{
+        DateConverter dc = new DateConverter();
+
+        // the array of students
+		String[] students = getStudents();
+
+		// the array of times... times[i][0] is the hours, times[i][1] is the minutes
+		long[][] times = new long[students.length][2];
+
+		// to keep track of the times in minutes, for comparison
+		long[] totalTimes = new long[students.length];
+
+
+		// get all the working times
+		for (int i = 0; i < students.length; i++)
+		{
+			// set the 2d "times" array
+			times[i] = dc.computeWorkTime(getCompilationEvents(students[i], assignment));
+			// set the total time
+			totalTimes[i] = times[i][0] * 60 + times[i][1];
+		}
+
+
+		// now sort by the total times, but remember to also move the student names and the hour/minute times around, too
+		// TODO: the names are not sorted when the values are the same
+
+		for (int i = 0; i < totalTimes.length; i++)
+		{
+			for (int j = totalTimes.length-1; j > i; j--)
+			{
+				if (totalTimes[j-1] < totalTimes[j])
+				{
+					// swap the values
+					String temp = students[j];
+					students[j] = students[j-1];
+					students[j-1] = temp;
+
+					long tmp = totalTimes[j];
+					totalTimes[j] = totalTimes[j-1];
+					totalTimes[j-1] = tmp;
+
+					long[] t = times[j];
+					times[j] = times[j-1];
+					times[j-1] = t;
+
+				}
+			}
+		}
+
+		/* at this point, the arrays are sorted based on what was in totalTimes */
+
+		// this is the array that holds the string representation of the working times
+		String[] workTimes = new String[students.length];
+
+		for (int i = 0; i < students.length; i++){
+			String result = "";
+			if(times[i][0] == 0){
+				result = "Less Than 1 Hour";
+			}
+			else{
+				result = "Approx. " + (int)times[i][0] + " hrs. and " + (int)times[i][1] + " mins.";
+			}
+			workTimes[i] = result;
+		}
+
+		// this is the return value... retValue[0][i] is the name of the student, retValue[1][i] is the corresponding working time
+		String[][] retValue = new String[2][students.length];
+		retValue[0] = students;
+		retValue[1] = workTimes;
+		return retValue;
+	}

 	/**
 	 * This method returns the total number of compilations for a user on an assignment.
@@ -153,6 +232,8 @@ public class CompilationEventManager extends DatabaseManager
 	}


+
+
 	/**
 	 * For the specified assignment, this returns an OccurrenceMap that details how many compilations occurred
 	 * at different times of the day.
@@ -183,19 +264,80 @@ public class CompilationEventManager extends DatabaseManager
 				ArrayList<Integer> events = new ArrayList<Integer>();

 				// iterate through the ResultSet and populate the ArrayList
-				int count = 0;
+				int count = 0; // count the number of values so we know how big to make the arrays in the OccurrenceMap
+
+				// these keep track of the last value, in case we need to fill in any blanks
+				String lastHour = null;
+				String lastDay = null;
+				String lastMonth = null;
+
 				while (rs.next())
 				{
 					String month = rs.getString(1);
 					String day = rs.getString(2);
 					String hour = rs.getString(3);
+
+					// in case they're null
+					if (lastHour == null) lastHour = hour;
+					if (lastDay == null) lastDay = day;
+					if (lastMonth == null) lastMonth = month;
+
+					int fillInCounter = 0;
+					// this part figures out if we need to fill in any empty times
+					if (Integer.parseInt(hour) - Integer.parseInt(lastHour) > 1)
+					{
+						// in this part, we're just assuming it's the same day
+						// but with some hours in which there were no errors
+
+						// figure out the number of spots to fill in
+						fillInCounter = Integer.parseInt(hour) - Integer.parseInt(lastHour) - 1;
+						// for each one, insert a time stamp
+						for (int i = 1; i <= fillInCounter; i++)
+						{
+							int tempHour = Integer.parseInt(lastHour) + i;
+							times.add(month + "-" + day + " " + tempHour + ":00");
+						}
+					}
+					else if (Integer.parseInt(hour) < Integer.parseInt(lastHour) || (Integer.parseInt(day) != Integer.parseInt(lastDay) && Integer.parseInt(hour) != 0))
+					{
+						// in this part, we notice that the current hour is less than the previous, so a day must have changed
+						// we assume it's only been one day
+
+						// first, fill in for the rest of the previous day
+						fillInCounter = 23 - Integer.parseInt(lastHour);
+						for (int i = 1; i <= fillInCounter; i++)
+						{
+							int tempHour = Integer.parseInt(lastHour) + i;
+							times.add(lastMonth + "-" + lastDay + " " + tempHour + ":00");
+						}
+
+						// now we do it for the rest of the current day
+						for (int i = 0; i < Integer.parseInt(hour); i++)
+						{
+							times.add(month + "-" + day + " " + i + ":00");
+						}
+						fillInCounter += Integer.parseInt(hour);
+					}
+
+					// now put in the one we just read from the database
 					String date = month + "-" + day + " " + hour + ":00";
 					times.add(date);

+					// if we had any fillins, put zeroes in the events ArrayList
+					for (int i = 0; i < fillInCounter; i++)
+						events.add(0);
+
+					// now put in the one we just read from the database
 					int compile = rs.getInt(4);
 					events.add(compile);

-					count++;
+					// update the counter
+					count += fillInCounter + 1;
+
+					// update the values
+					lastHour = hour;
+					lastDay = day;
+					lastMonth = month;
 				}

 				// now return the results
@@ -214,6 +356,7 @@ public class CompilationEventManager extends DatabaseManager
 		catch(Exception e)
 		{
 			e.printStackTrace();
+			if (Logger.isLogError()) Logger.logError(e);
 		}
 		finally
 		{
@@ -223,10 +366,145 @@ public class CompilationEventManager extends DatabaseManager

 	}

+
+	/**
+	 * For the specified assignment and a specified student id, this returns an OccurrenceMap that details how many compilations occurred
+	 * at different times of the day.
+	 */
+	public OccurrenceMap getCompilationTimes(String assignment, String student)
+	{
+		try
+		{
+			con = getConnection();
+
+			if (con != null)
+			{
+				// create a Statement
+				Statement stmt = con.createStatement();
+
+				// now create the SQL query
+				String query = "select datepart(mm, date), datepart(d, date), datepart(hh, date), count(*) from compilations where assignment = '" + assignment + "' and student = '" + student + "' group by datepart(mm, date), datepart(d, date), datepart(hh, compilations.date)";
+				// execute the query
+				ResultSet rs = stmt.executeQuery(query);
+				//System.out.println("Executed " + query);
+
+				// we can't actually know the size of the ResultSet in advance
+				// so we can't create an array... yet
+				// use an ArrayList for now
+				// TODO: can we be certain that the ArrayList will keep everything in the right order?
+				ArrayList<String> times = new ArrayList<String>();
+				ArrayList<Integer> events = new ArrayList<Integer>();
+
+				// iterate through the ResultSet and populate the ArrayList
+				int count = 0; // count the number of values so we know how big to make the arrays in the OccurrenceMap
+
+				// these keep track of the last value, in case we need to fill in any blanks
+				String lastHour = null;
+				String lastDay = null;
+				String lastMonth = null;
+
+				while (rs.next())
+				{
+					String month = rs.getString(1);
+					String day = rs.getString(2);
+					String hour = rs.getString(3);
+
+					// in case they're null
+					if (lastHour == null) lastHour = hour;
+					if (lastDay == null) lastDay = day;
+					if (lastMonth == null) lastMonth = month;
+
+					int fillInCounter = 0;
+					// this part figures out if we need to fill in any empty times
+					if (Integer.parseInt(hour) - Integer.parseInt(lastHour) > 1)
+					{
+						// in this part, we're just assuming it's the same day
+						// but with some hours in which there were no errors
+
+						// figure out the number of spots to fill in
+						fillInCounter = Integer.parseInt(hour) - Integer.parseInt(lastHour) - 1;
+						// for each one, insert a time stamp
+						for (int i = 1; i <= fillInCounter; i++)
+						{
+							int tempHour = Integer.parseInt(lastHour) + i;
+							times.add(month + "-" + day + " " + tempHour + ":00");
+						}
+					}
+					else if (Integer.parseInt(hour) < Integer.parseInt(lastHour) || (Integer.parseInt(day) != Integer.parseInt(lastDay) && Integer.parseInt(hour) != 0))
+					{
+						// in this part, we notice that the current hour is less than the previous, so a day must have changed
+						// we assume it's only been one day
+
+						// first, fill in for the rest of the previous day
+						fillInCounter = 23 - Integer.parseInt(lastHour);
+						for (int i = 1; i <= fillInCounter; i++)
+						{
+							int tempHour = Integer.parseInt(lastHour) + i;
+							times.add(lastMonth + "-" + lastDay + " " + tempHour + ":00");
+						}
+
+						// now we do it for the rest of the current day
+						for (int i = 0; i < Integer.parseInt(hour); i++)
+						{
+							times.add(month + "-" + day + " " + i + ":00");
+						}
+						fillInCounter += Integer.parseInt(hour);
+					}
+
+					// now put in the one we just read from the database
+					String date = month + "-" + day + " " + hour + ":00";
+					times.add(date);
+
+					// if we had any fillins, put zeroes in the events ArrayList
+					for (int i = 0; i < fillInCounter; i++)
+						events.add(0);
+
+					// now put in the one we just read from the database
+					int compile = rs.getInt(4);
+					events.add(compile);
+
+					// update the counter
+					count += fillInCounter + 1;
+
+					// update the values
+					lastHour = hour;
+					lastDay = day;
+					lastMonth = month;
+				}
+
+				// now return the results
+				OccurrenceMap map = new OccurrenceMap();
+				map.keys = times.toArray(new String[count]);
+				map.occurrences = new int[count];
+				for (int i = 0; i < count; i++)
+				{
+					map.occurrences[i] = events.get(i).intValue();
+				}
+
+				return map;
+
+			}
+		}
+		catch(Exception e)
+		{
+			e.printStackTrace();
+			if (Logger.isLogError()) Logger.logError(e);
+		}
+		finally
+		{
+			closeConnection();
+		}
+		return null;
+
+	}
+
+
+
+
 	public static void main(String[] args)
 	{
 		CompilationEventManager m = new CompilationEventManager();
-		OccurrenceMap map = m.getCompilationTimes("1");
+		OccurrenceMap map = m.getCompilationTimes("4");
 		for (int i = 0; i < map.keys.length; i++)
 		{
 			System.out.println(map.keys[i] + " " + map.occurrences[i]);
diff --git a/retina/db/DatabaseConnector.java b/retina/db/DatabaseConnector.java
index 6bd31c6..44e6bf3 100644
--- a/retina/db/DatabaseConnector.java
+++ b/retina/db/DatabaseConnector.java
@@ -1,13 +1,13 @@
-package retina.db;

/**
 * This class has all the base functionality for managing a database connection, like
 * connecting and closing it.
 */
+package retina.db;

import retina.common.Logger;

/**
 * This class has all the base functionality for managing a database connection, like
 * connecting and closing it.
 */
 public class DatabaseConnector
 {
 	protected java.sql.Connection  con = null;
     
	private final String url = "jdbc:sqlserver://";
	private final String serverName= "vesey.cs.columbia.edu";
	private final String portNumber = "1433";
	private final String databaseName= "Retina";
	private final String userName = "student";
	private final String password = "password";
	private final String driver = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
     // Constructor
    public DatabaseConnector(){}
 
    /* This method just creates the connection string based on all the properties. */
     private String getConnectionUrl()
    {
    	// return url+serverName+":"+portNumber+";databaseName="+databaseName+";selectMethod="+selectMethod+";";
    	return url+serverName+":"+portNumber+";user="+userName+";password="+password+";databaseName="+databaseName;
    }
-
    /* Create the database connection */
    protected java.sql.Connection getConnection()
    {
    	try
    	{
    		Class.forName(driver);
    		con = java.sql.DriverManager.getConnection(getConnectionUrl(),userName,password);
            //if(con!=null) System.out.println("Connection Successful!");
    	}
    	catch (Exception e)
    	{
    		System.out.println("Error Trace in getConnection() : " + e.getMessage());
    		e.printStackTrace();
    	}
        return con;
    }
+
    /* Create the database connection */
    protected java.sql.Connection getConnection()
    {
    	try
    	{
    		Class.forName(driver);
    		con = java.sql.DriverManager.getConnection(getConnectionUrl(),userName,password);
            //if(con!=null) System.out.println("Connection Successful!");
    	}
    	catch (Exception e)
    	{
    		System.out.println("Error Trace in getConnection() : " + e.getMessage());
    		e.printStackTrace();
			if (Logger.isLogError()) Logger.logError(e);
    	}
        return con;
    }

-    /* Close the connection to the database. */
    protected void closeConnection()
    {
    	try
    	{
    		if (con != null) con.close();
        }	
    	catch (Exception e)
    	{
    		// if an error occurs, well, what can you do?
    	}
    	finally
    	{
    		con = null;
    	}
    }
+    /* Close the connection to the database. */
    protected void closeConnection()
    {
    	try
    	{
    		if (con != null) con.close();
        }	
    	catch (Exception e)
    	{
			if (Logger.isLogError()) Logger.logError(e);
    	}
    	finally
    	{
    		con = null;
    	}
    }
 
    /* Test method to display the driver properties and database details */
    public void displayDbProperties()
    {
    	java.sql.DatabaseMetaData dm = null;
    	java.sql.ResultSet rs = null;
    	try{
    		con= this.getConnection();
    		if(con!=null){
    			dm = con.getMetaData();
    			System.out.println("Driver Information");
    			System.out.println("\tDriver Name: "+ dm.getDriverName());
    			System.out.println("\tDriver Version: "+ dm.getDriverVersion ());
    			System.out.println("\nDatabase Information ");
    			System.out.println("\tDatabase Name: "+ dm.getDatabaseProductName());
    			System.out.println("\tDatabase Version: "+ dm.getDatabaseProductVersion());
    			System.out.println("Avalilable Catalogs ");
    			rs = dm.getCatalogs();
    			while(rs.next()){
    				System.out.println("\tcatalog: "+ rs.getString(1));
    			}	
    			rs.close();
    			rs = null;
    			closeConnection();
    		}else System.out.println("Error: No active Connection");
    	}catch(Exception e){
    		e.printStackTrace();
    	}
    	dm=null;
    }
 	public static void main(String[] args)
 	{
diff --git a/retina/db/DatabaseManager.java b/retina/db/DatabaseManager.java
index f4be0af..195b0dd 100644
--- a/retina/db/DatabaseManager.java
+++ b/retina/db/DatabaseManager.java
@@ -10,6 +10,8 @@ package retina.db;
 import java.sql.*;
 import java.util.ArrayList;

+import retina.common.Logger;
+

 public class DatabaseManager extends DatabaseConnector
 {
	// Constructor
	public DatabaseManager(){}
@@ -35,7 +37,8 @@ public class DatabaseManager extends DatabaseConnector

 				return true;
             }
            else System.out.println("Error: No active Connection");
-        }
        catch(Exception e)
        {
			e.printStackTrace();
		}
+        }
        catch(Exception e)
        {
			e.printStackTrace();
			if (Logger.isLogError()) Logger.logError(e);
+		}
 		finally
 		{
 			closeConnection();
@@ -88,6 +91,7 @@ public class DatabaseManager extends DatabaseConnector
         catch(Exception e)
         {
 			e.printStackTrace();
+			if (Logger.isLogError()) Logger.logError(e);
 		}
 		finally
 		{
@@ -141,6 +145,7 @@ public class DatabaseManager extends DatabaseConnector
 		catch(Exception e)
 		{
 			e.printStackTrace();
+			if (Logger.isLogError()) Logger.logError(e);
 		}
 		finally
 		{
@@ -179,6 +184,7 @@ public class DatabaseManager extends DatabaseConnector
 		catch(Exception e)
 		{
 			e.printStackTrace();
+			if (Logger.isLogError()) Logger.logError(e);
 		}
 		finally
 		{
@@ -231,6 +237,7 @@ public class DatabaseManager extends DatabaseConnector
 		catch(Exception e)
 		{
 			e.printStackTrace();
+			if (Logger.isLogError()) Logger.logError(e);
 		}
 		finally
 		{
@@ -239,5 +246,10 @@ public class DatabaseManager extends DatabaseConnector
 		return null;
 	}

-
+	public static void main(String[] args)
+	{
+		DatabaseManager m = new DatabaseManager();
+		m.insertStudent("foo", "bar");
+
+	}
 }
\ No newline at end of file
diff --git a/retina/db/LoginEventManager.java b/retina/db/LoginEventManager.java
index 1abf0cb..a679199 100644
--- a/retina/db/LoginEventManager.java
+++ b/retina/db/LoginEventManager.java
@@ -6,6 +6,8 @@ package retina.db;
 import java.sql.*;
 import java.util.ArrayList;

+import retina.common.Logger;
+

 public class LoginEventManager extends DatabaseManager
 {
	// Constructor
	public LoginEventManager(){}
@@ -29,7 +31,8 @@ public class LoginEventManager extends DatabaseManager

 				return true;
             }
            else System.out.println("Error: No active Connection");
-        }
        catch(Exception e)
        {
			e.printStackTrace();
		}
+        }
        catch(Exception e)
        {
			e.printStackTrace();
			if (Logger.isLogError()) Logger.logError(e);
+		}
 		finally
 		{
 			closeConnection();
diff --git a/retina/db/LoginEventServer.java b/retina/db/LoginEventServer.java
index e12d29b..3c71212 100644
--- a/retina/db/LoginEventServer.java
+++ b/retina/db/LoginEventServer.java
@@ -10,6 +10,7 @@ import java.io.*;
 import java.net.*;
 import java.util.Scanner;

+import retina.common.Logger;
 import retina.im.MessageSender;


@@ -120,6 +121,7 @@ public class LoginEventServer extends Thread
     		catch (Exception e)
     		{
     			e.printStackTrace();
+    			if (Logger.isLogError()) Logger.logError(e);
     		}
     		finally
     		{
diff --git a/retina/db/SuggestionManager.java b/retina/db/SuggestionManager.java
index 423d68f..ab6e458 100644
--- a/retina/db/SuggestionManager.java
+++ b/retina/db/SuggestionManager.java
@@ -1,5 +1,7 @@
 package retina.db;
 import java.sql.*;
+
+import retina.common.Logger;
 import retina.common.Student;

 /***********************************************************************************
@@ -51,6 +53,7 @@ public class SuggestionManager extends DatabaseManager
         catch(Exception e)
         {
 			e.printStackTrace();
+			if (Logger.isLogError()) Logger.logError(e);
 		}
 		finally
 		{
diff --git a/retina/db/XMLLoader.java b/retina/db/XMLLoader.java
index 8d60480..99d7677 100644
--- a/retina/db/XMLLoader.java
+++ b/retina/db/XMLLoader.java
@@ -3,6 +3,8 @@ package retina.db;
 /**
  * This class contains methods for reading an XML file from disk, creating the necessary Events,
  * and then using the DatabaseManager to insert those into the database.
+ *
+ * This class is NOT threadsafe; each thread should have its own instance.
  */

 import java.io.IOException;
@@ -20,20 +22,33 @@ import org.w3c.dom.NodeList;
 import org.xml.sax.SAXException;

 import retina.common.CompilationErrorEvent;
+import retina.common.RuntimeErrorEvent;
 import retina.common.CompilationEvent;
+import retina.common.Event;
 import retina.common.Logger;
 import retina.im.MessageSender;

 public class XMLLoader {

+	private static final String ASSIGNMENT = "4";
+
 	// the Document object
 	private Document dom;

 	// the set of objects that need to be inserted into the database
-	private ArrayList<CompilationErrorEvent> events;
+	private ArrayList<Event> events;

 	// used for sending messages
 	private MessageSender sender;
+
+	// for database stuff
+	private CompilationErrorEventManager compilationManager = new CompilationErrorEventManager();
+	private RuntimeErrorEventManager runtimeManager = new RuntimeErrorEventManager();
+
+	// to indicate the type of events being loaded
+	private int type = 0;
+	private static final int COMPILATION_ERROR = 1;
+	private static final int RUNTIME_ERROR = 2;

 	public XMLLoader()
 	{
@@ -53,7 +68,7 @@ public class XMLLoader {
 	public void readAndLoad(String file) {

 		// reset the list of events
-		events = new ArrayList<CompilationErrorEvent>();
+		events = new ArrayList<Event>();

 		//parse the xml file and get the dom object
 		parseXmlFile(file);
@@ -61,13 +76,24 @@ public class XMLLoader {
 		//get each element and create objects
 		parseDocument();

-		// now write all the compilation error events to the database
-		CompilationErrorEventManager mgr = new CompilationErrorEventManager();
-		for (CompilationErrorEvent event : events)
+		if (type == COMPILATION_ERROR)
+		{
+			// now write all the compilation error events to the database
+			for (Event event : events)
+			{
+				compilationManager.insertCompilationErrorEvent((CompilationErrorEvent)event);
+			}
+		}
+		else if (type == RUNTIME_ERROR)
 		{
-			mgr.insertCompilationErrorEvent(event);
-			//System.out.println("Inserted " + event);
+			// and then the runtime errors
+			for (Event event : events)
+			{
+				boolean success = runtimeManager.insertRuntimeErrorEvent((RuntimeErrorEvent)event);
+				if (success && Logger.isLogInfo()) Logger.logInfo("Inserted " + event);
+			}
 		}
+

 		// now send a message to the student - temporarily disabled!
 		/*
@@ -124,16 +150,21 @@ public class XMLLoader {

 		//get a nodelist of <metric> elements
 		NodeList nl = docEle.getElementsByTagName("metric");
-		if(nl != null && nl.getLength() > 0) {
+		if (nl != null && nl.getLength() > 0)
+		{
+			// first figure out what type it is
+			Element e = (Element)nl.item(0);
+			String metricType = e.getAttribute("name");
+			if (metricType.equals("compilation_errors")) type = COMPILATION_ERROR;
+			else if (metricType.equals("runtime_errors")) type = RUNTIME_ERROR;
+
 			for(int i = 0 ; i < nl.getLength();i++) {
-
 				//get the element
 				Element el = (Element)nl.item(i);
 				// create the objects and put them in the "events" ArrayList
 				createObjects(el);
 			}
 		}
-
 	}


@@ -196,7 +227,7 @@ public class XMLLoader {
 		}

 		// TODO: how do we get the assignment?
-		if (assignment == null) assignment = "3";
+		if (assignment == null) assignment = ASSIGNMENT;

 		// tracks the number of errors made
 		int errors = 0;
@@ -218,18 +249,27 @@ public class XMLLoader {
 				//System.out.println("error: " + error.trim());
 				//System.out.println("message: " + message.trim());

-				CompilationErrorEvent errComp = new CompilationErrorEvent(user, assignment, timeFormat, error, message, file, line);
-				events.add(errComp);
+				// figure out what type of event it is before putting it in the array list
+				Event event = null;
+				if (type == COMPILATION_ERROR)
+					event = new CompilationErrorEvent(user, assignment, timeFormat, error, message, file, line);
+				else if (type == RUNTIME_ERROR)
+					event = new RuntimeErrorEvent(user, assignment, timeFormat, error, message, file, line);
+				events.add(event);

 				errors++;
 			}

 		}

-		// now record the fact that a compilation occurred
-		CompilationEvent ce = new CompilationEvent(user, assignment, timeFormat, errors);
-		new CompilationEventManager().insertCompilationEvent(ce);
-		if (Logger.isLogInfo()) Logger.logInfo("Inserted " + ce);
+		// if it's a compilation event, we need to record that
+		if (type == COMPILATION_ERROR)
+		{
+			// now record the fact that a compilation occurred
+			CompilationEvent ce = new CompilationEvent(user, assignment, timeFormat, errors);
+			boolean success = compilationManager.insertCompilationEvent(ce);
+			if (success && Logger.isLogInfo()) Logger.logInfo("Inserted " + ce);
+		}

 	}

@@ -264,7 +304,7 @@ public class XMLLoader {
 	{

 		// this is for reading one file at a time
-		String filename = "..\\inbox\\_mja2128-PrimeNumber.java-02-12-02-03-00.xml";
+		String filename = "..\\test.xml";
 		/*
 		if (args.length == 0)
 		{
diff --git a/retina/db/XmlServer.java b/retina/db/XmlServer.java
index b66a226..87f33ac 100644
--- a/retina/db/XmlServer.java
+++ b/retina/db/XmlServer.java
@@ -19,9 +19,6 @@ public class XmlServer extends Thread
     // the server
     private ServerSocket server;

-    // the tool for writing to the database
-    private XMLLoader loader;
-
     // used for sending messages
     private MessageSender sender;

@@ -49,14 +46,12 @@ public class XmlServer extends Thread
     public XmlServer(int port)
     {
     	sender = new MessageSender();
-    	loader = new XMLLoader(sender);
     	init(port);
     }

     public XmlServer(int port, MessageSender ms)
     {
     	sender = ms;
-    	loader = new XMLLoader(sender);
     	init(port);
     }

@@ -71,6 +66,7 @@ public class XmlServer extends Thread
 		{
 		    System.out.println("Cannot create XmlServer!");
 		    e.printStackTrace();
+			if (Logger.isLogError()) Logger.logError(e);
 		}
     }

@@ -95,6 +91,7 @@ public class XmlServer extends Thread
     		catch (Exception e)
     		{
     			e.printStackTrace();
+    			if (Logger.isLogError()) Logger.logError(e);
     		}
     	}
     }
@@ -105,7 +102,11 @@ public class XmlServer extends Thread
     class Handler extends Thread
     {
     	Socket socket = null;
-
+
+    	// the tool for writing to the database
+    	// each thread should have its own because the XMLLoader is not threadsafe
+        XMLLoader loader = new XMLLoader(sender);
+
     	Handler(Socket s)
     	{
     		socket = s;
@@ -170,7 +171,7 @@ public class XmlServer extends Thread
     		catch (Exception e)
     		{
     			e.printStackTrace();
-    			if (Logger.isLogError()) Logger.logError("Error loading " + fileName + ": " + e.toString());
+    			if (Logger.isLogError()) Logger.logError(e);
     		}
     		finally
     		{
diff --git a/retina/ui/BrowsePane.java b/retina/ui/BrowsePane.java
index 4aa8de6..0fa2e64 100644
--- a/retina/ui/BrowsePane.java
+++ b/retina/ui/BrowsePane.java
@@ -611,6 +611,7 @@ public class BrowsePane extends javax.swing.JPanel {
                 new BrowsePane(new UserInterfaceManager()).setVisible(true);
             }
         });
+
     }

 }
diff --git a/retina/ui/DBTableModel.java b/retina/ui/DBTableModel.java
index 99d9928..33aa318 100644
--- a/retina/ui/DBTableModel.java
+++ b/retina/ui/DBTableModel.java
@@ -7,6 +7,7 @@ package retina.ui;
 import javax.swing.table.AbstractTableModel;

 import retina.common.CompilationErrorEvent;
+import retina.common.RuntimeErrorEvent;
 import retina.common.Event;

 public class DBTableModel extends AbstractTableModel
@@ -61,6 +62,20 @@ public class DBTableModel extends AbstractTableModel

         }
        }
+        else if (e instanceof RuntimeErrorEvent[]){
+        	RuntimeErrorEvent[] ce = (RuntimeErrorEvent[])e;
+            data = new Object[ce.length][COLUMN_MAX];
+            for(row = 0; row < ce.length; row++){
+                data[row][col++] = ce[row].getError();
+                data[row][col++] = ce[row].getMessage();
+                data[row][col++] = ce[row].getTime();
+                data[row][col++] = ce[row].getFile();
+                data[row][col++] = ce[row].getLine();
+                // data[row][col++] = ce[row].getUser();
+                col = 0;
+
+            }
+           }
        else if (e == null){
             data = new Object[1][COLUMN_MAX];
             data[0][col++] = "";
diff --git a/retina/ui/DateConverter.java b/retina/ui/DateConverter.java
index 9f5668b..96514f9 100644
--- a/retina/ui/DateConverter.java
+++ b/retina/ui/DateConverter.java
@@ -1,6 +1,8 @@
 package retina.ui;

 import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import java.text.*;

 import retina.common.CompilationEvent;
@@ -10,21 +12,55 @@ public class DateConverter {
 	private final int timeCap = 3600;		 //units = "seconds"
 	private long workTime = 0;
 	private DateFormat formatter;
+	private Pattern datePattern1, datePattern2;
+	private String dateRegex1, dateRegex2;

+	public DateConverter(){
+		dateRegex1 = "\\d{1,2}-\\d{1,2}\\s\\d{1,2}:\\d{1,2}";
+		dateRegex2 = "\\d{4}-\\d{1,2}-\\d{1,2}\\s\\d{1,2}:\\d{1,2}:\\d{1,2}\\.\\d";
+
+		datePattern1 = Pattern.compile(dateRegex1); //2-8 18:00
+		datePattern2 = Pattern.compile(dateRegex2); //2008-02-08 12:51:23.0
+
+
+	}
 	public int dateToInt(String date){
-		StringTokenizer st = new StringTokenizer(date, "\\d-\\d \\d:\\d");
-	    String newdate = "";
-	    while(st.hasMoreTokens()){
-	        String temp = st.nextToken();
-	       if(temp.length() < 2){
-	        	temp = "0" + temp;
-	        }
-	        newdate += temp;
+		Matcher m1 = datePattern1.matcher(date);
+		Matcher m2 = datePattern2.matcher(date);
+
+		if(m1.matches()){
+			StringTokenizer st = new StringTokenizer(date, "\\d-\\d \\d:\\d");
+			String newdate = "";
+			while(st.hasMoreTokens()){
+				String temp = st.nextToken();
+				if(temp.length() < 2){
+					temp = "0" + temp;
+				}
+				newdate += temp;


-	    }
-
-	    return Integer.parseInt(newdate);
+				}
+			return Integer.parseInt(newdate);
+		}
+		else if(m2.matches()){
+				StringTokenizer st = new StringTokenizer(date, "\\d-\\d-\\d \\d:\\d:\\d");
+				String newdate = "";
+				while(st.hasMoreTokens()){
+					String temp = st.nextToken();
+					if(!temp.matches("\\d{4}")){
+						if(temp.length() < 2){
+							temp = "0" + temp;
+						}
+						newdate += temp;
+					}
+				}
+				newdate = newdate.substring(0, 10);
+				return Integer.parseInt(newdate);
+
+		}
+		else{
+			return 0;
+		}

 	}

diff --git a/retina/ui/MainPane.java b/retina/ui/MainPane.java
index 9b0c89b..ab0f8d8 100644
--- a/retina/ui/MainPane.java
+++ b/retina/ui/MainPane.java
@@ -10,13 +10,13 @@ import java.awt.event.*;

 public class MainPane extends javax.swing.JPanel {

-  private javax.swing.JLabel assignmentDescriptionLabel;
+  private javax.swing.JLabel classDescriptionLabel;
   private javax.swing.JLabel studentDescriptionLabel;
   private javax.swing.JLabel browseDescriptionLabel;
-  private javax.swing.JLabel errorDescriptionLabel;
-  private javax.swing.JRadioButton buttonAStat;
+  private javax.swing.JLabel runDescriptionLabel;
+  private javax.swing.JRadioButton buttonCStat;
   private javax.swing.JRadioButton buttonBrowse;
-  private javax.swing.JRadioButton buttonEStat;
+  private javax.swing.JRadioButton buttonRStat;
   private javax.swing.ButtonGroup buttonGroup;
   private javax.swing.JRadioButton buttonSStat;
   private javax.swing.JLayeredPane centerPane;
@@ -25,7 +25,7 @@ public class MainPane extends javax.swing.JPanel {
   private javax.swing.JLayeredPane optionsPane;
   private javax.swing.JLabel projectLabel;
   private javax.swing.JLabel titleLabel;
-  private String browseString = "browse", astatString = "astat", estatString = "estat", sstatString = "sstat";
+  private String browseString = "browse", cstatString = "cstat", rstatString = "rstat", sstatString = "sstat";
   private ActionListener buttonListener;
   private UserInterfaceManager uimanager;
   private String selectedButton;
@@ -51,19 +51,19 @@ public class MainPane extends javax.swing.JPanel {

         buttonBrowse = new javax.swing.JRadioButton();

-        buttonEStat = new javax.swing.JRadioButton();
+        buttonRStat = new javax.swing.JRadioButton();

-        buttonAStat = new javax.swing.JRadioButton();
+        buttonCStat = new javax.swing.JRadioButton();

         buttonSStat = new javax.swing.JRadioButton();

         browseDescriptionLabel = new javax.swing.JLabel();

-        assignmentDescriptionLabel = new javax.swing.JLabel();
+        classDescriptionLabel = new javax.swing.JLabel();

         studentDescriptionLabel = new javax.swing.JLabel();

-        errorDescriptionLabel = new javax.swing.JLabel();
+        runDescriptionLabel = new javax.swing.JLabel();

         goButton = new javax.swing.JButton();

@@ -85,14 +85,14 @@ public class MainPane extends javax.swing.JPanel {
         optionsPane = new javax.swing.JLayeredPane();
         buttonGroup = new javax.swing.ButtonGroup();
         buttonBrowse = new javax.swing.JRadioButton();
-        buttonEStat = new javax.swing.JRadioButton();
-        buttonAStat = new javax.swing.JRadioButton();
+        buttonRStat = new javax.swing.JRadioButton();
+        buttonCStat = new javax.swing.JRadioButton();
         buttonSStat = new javax.swing.JRadioButton();
         titleLabel = new javax.swing.JLabel();
         browseDescriptionLabel = new javax.swing.JLabel();
-        assignmentDescriptionLabel = new javax.swing.JLabel();
+        classDescriptionLabel = new javax.swing.JLabel();
         studentDescriptionLabel = new javax.swing.JLabel();
-        errorDescriptionLabel = new javax.swing.JLabel();
+        runDescriptionLabel = new javax.swing.JLabel();
         goButton = new javax.swing.JButton();
         classLabel = new javax.swing.JLabel();
         projectLabel = new javax.swing.JLabel();
@@ -132,23 +132,23 @@ public class MainPane extends javax.swing.JPanel {
         optionsPane.add(buttonBrowse, javax.swing.JLayeredPane.DEFAULT_LAYER);
         buttonBrowse.getAccessibleContext().setAccessibleParent(optionsPane);

-        buttonEStat.setFont(new java.awt.Font("Tahoma", 1, 18));
-        buttonEStat.setText("Error Stats");
-        buttonEStat.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
-        buttonEStat.setContentAreaFilled(false);
-        buttonEStat.setMargin(new java.awt.Insets(0, 0, 0, 0));
-        buttonEStat.setBounds(450, 30, 200, 40);
-        buttonEStat.setActionCommand(estatString);
-        optionsPane.add(buttonEStat, javax.swing.JLayeredPane.DEFAULT_LAYER);
+        buttonRStat.setFont(new java.awt.Font("Tahoma", 1, 18));
+        buttonRStat.setText("Runtime Stats");
+        buttonRStat.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
+        buttonRStat.setContentAreaFilled(false);
+        buttonRStat.setMargin(new java.awt.Insets(0, 0, 0, 0));
+        buttonRStat.setBounds(450, 30, 200, 40);
+        buttonRStat.setActionCommand(rstatString);
+        optionsPane.add(buttonRStat, javax.swing.JLayeredPane.DEFAULT_LAYER);

-        buttonAStat.setFont(new java.awt.Font("Verdana", 1, 18));
-        buttonAStat.setText("Assignment Stats");
-        buttonAStat.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
-        buttonAStat.setContentAreaFilled(false);
-        buttonAStat.setMargin(new java.awt.Insets(0, 0, 0, 0));
-        buttonAStat.setBounds(20, 150, 200, 40);
-        buttonAStat.setActionCommand(astatString);
-        optionsPane.add(buttonAStat, javax.swing.JLayeredPane.DEFAULT_LAYER);
+        buttonCStat.setFont(new java.awt.Font("Verdana", 1, 18));
+        buttonCStat.setText("Class Stats");
+        buttonCStat.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
+        buttonCStat.setContentAreaFilled(false);
+        buttonCStat.setMargin(new java.awt.Insets(0, 0, 0, 0));
+        buttonCStat.setBounds(20, 150, 200, 40);
+        buttonCStat.setActionCommand(cstatString);
+        optionsPane.add(buttonCStat, javax.swing.JLayeredPane.DEFAULT_LAYER);

         buttonSStat.setFont(new java.awt.Font("Verdana", 1, 18));
         buttonSStat.setText("Student Stats");
@@ -166,12 +166,12 @@ public class MainPane extends javax.swing.JPanel {
         browseDescriptionLabel.setBounds(20, 70, 370, 70);
         optionsPane.add(browseDescriptionLabel, javax.swing.JLayeredPane.DEFAULT_LAYER);

-        assignmentDescriptionLabel.setFont(new java.awt.Font("Verdana", 2, 12));
-        assignmentDescriptionLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
-        assignmentDescriptionLabel.setText("View statistics on each assignment");
-        assignmentDescriptionLabel.setVerticalAlignment(javax.swing.SwingConstants.TOP);
-        assignmentDescriptionLabel.setBounds(20, 190, 370, 70);
-        optionsPane.add(assignmentDescriptionLabel, javax.swing.JLayeredPane.DEFAULT_LAYER);
+        classDescriptionLabel.setFont(new java.awt.Font("Verdana", 2, 12));
+        classDescriptionLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
+        classDescriptionLabel.setText("View graphs and tables for the entire class");
+        classDescriptionLabel.setVerticalAlignment(javax.swing.SwingConstants.TOP);
+        classDescriptionLabel.setBounds(20, 190, 370, 70);
+        optionsPane.add(classDescriptionLabel, javax.swing.JLayeredPane.DEFAULT_LAYER);

         studentDescriptionLabel.setFont(new java.awt.Font("Verdana", 2, 12));
         studentDescriptionLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
@@ -180,12 +180,12 @@ public class MainPane extends javax.swing.JPanel {
         studentDescriptionLabel.setBounds(450, 190, 370, 70);
         optionsPane.add(studentDescriptionLabel, javax.swing.JLayeredPane.DEFAULT_LAYER);

-        errorDescriptionLabel.setFont(new java.awt.Font("Verdana", 2, 12));
-        errorDescriptionLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
-        errorDescriptionLabel.setText("View statistics on specific errors");
-        errorDescriptionLabel.setVerticalAlignment(javax.swing.SwingConstants.TOP);
-        errorDescriptionLabel.setBounds(450, 70, 370, 70);
-        optionsPane.add(errorDescriptionLabel, javax.swing.JLayeredPane.DEFAULT_LAYER);
+        runDescriptionLabel.setFont(new java.awt.Font("Verdana", 2, 12));
+        runDescriptionLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
+        runDescriptionLabel.setText("View data on runtime errors");
+        runDescriptionLabel.setVerticalAlignment(javax.swing.SwingConstants.TOP);
+        runDescriptionLabel.setBounds(450, 70, 370, 70);
+        optionsPane.add(runDescriptionLabel, javax.swing.JLayeredPane.DEFAULT_LAYER);

         optionsPane.setBounds(155, 220, 700, 270);
         centerPane.add(optionsPane, javax.swing.JLayeredPane.DEFAULT_LAYER);
@@ -202,8 +202,8 @@ public class MainPane extends javax.swing.JPanel {
         centerPane.add(classLabel, javax.swing.JLayeredPane.DEFAULT_LAYER);

         buttonGroup.add(buttonBrowse);
-        buttonGroup.add(buttonAStat);
-        buttonGroup.add(buttonEStat);
+        buttonGroup.add(buttonCStat);
+        buttonGroup.add(buttonRStat);
         buttonGroup.add(buttonSStat);

         javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
@@ -226,8 +226,8 @@ public class MainPane extends javax.swing.JPanel {
         };

         buttonBrowse.addActionListener(buttonListener);
-        buttonAStat.addActionListener(buttonListener);
-        buttonEStat.addActionListener(buttonListener);
+        buttonCStat.addActionListener(buttonListener);
+        buttonRStat.addActionListener(buttonListener);
         buttonSStat.addActionListener(buttonListener);

         goButton.addActionListener(new ActionListener()
@@ -262,18 +262,18 @@ public class MainPane extends javax.swing.JPanel {
              uimanager.showBrowsePane();

         }
-        else if (selectedButton.equals(estatString)){
-
+        else if (selectedButton.equals(rstatString)){
+        	uimanager.showRuntimePane();

         }
-        else if (selectedButton.equals(astatString)){
-        	uimanager.showAssignPane();
+        else if (selectedButton.equals(cstatString)){
+        	uimanager.showClassPane();


         }
        else if (selectedButton.equals(sstatString)){
-
-
+    	   uimanager.showStudentPane();
+
         }

     }
diff --git a/retina/ui/UserInterfaceManager.java b/retina/ui/UserInterfaceManager.java
index 0b9d539..98db5e8 100644
--- a/retina/ui/UserInterfaceManager.java
+++ b/retina/ui/UserInterfaceManager.java
@@ -1,13 +1,13 @@
 package retina.ui;

/**
 * This class contains some helper methods for dealing with UI stuff
 */

-import javax.swing.*;
-public class UserInterfaceManager extends JFrame
{
    private MainPane mainpane; 
    private BrowsePane browsepane;
    private AssignmentPane assignpane;

    public UserInterfaceManager() {
        initComponents(); 
        showMainPane();
    }
+import javax.swing.*;
+public class UserInterfaceManager extends JFrame
{
    private MainPane mainpane; 
    private BrowsePane browsepane;
    private StudentPane studentpane;
    private ClassPane classpane; 
    private RuntimePane runpane; 

    public UserInterfaceManager() {
        initComponents(); 
        showMainPane();
    }

-    private void initComponents(){
        setSize(1010, 740);
        setLocation(10, 10);
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setBounds(new java.awt.Rectangle(120, 10, 1010, 740 ));
        setVisible(true);
        setResizable(true);
        setTitle("RetinaServer Viewer");

        mainpane = new MainPane(this); 
        add(mainpane);

        browsepane = new BrowsePane(this);
        add(browsepane);
        
        assignpane = new AssignmentPane(this);
        add(assignpane);
    }
-    public void showAssignPane(){
    	browsepane.setVisible(false);
    	mainpane.setVisible(false);
    	assignpane.setVisible(true);
    	validate();
    }
-    public void showMainPane(){
        browsepane.setVisible(false);
        assignpane.setVisible(false);
        mainpane.setVisible(true);
        validate(); 
    }
+    private void initComponents(){
        setSize(1010, 740);
        setLocation(10, 10);
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setBounds(new java.awt.Rectangle(120, 10, 1010, 740 ));
        setVisible(true);
        setResizable(true);
        setTitle("RetinaServer Viewer");

        mainpane = new MainPane(this); 
        add(mainpane);

        browsepane = new BrowsePane(this);
        add(browsepane);
        
        studentpane = new StudentPane(this);
        add(studentpane);
        
        classpane = new ClassPane(this);
        add(classpane);
        
        runpane = new RuntimePane(this);
        add(runpane);
    }


    public void showClassPane(){
    	browsepane.setVisible(false);
    	mainpane.setVisible(false);
    	studentpane.setVisible(false);
    	runpane.setVisible(false);
    	classpane.setVisible(true);
    	validate();
    }
+    public void showStudentPane(){
    	browsepane.setVisible(false);
    	mainpane.setVisible(false);
    	classpane.setVisible(false);
        runpane.setVisible(false);
    	studentpane.setVisible(true);
    	validate();
    }
+    public void showMainPane(){
        browsepane.setVisible(false);
        studentpane.setVisible(false);
        classpane.setVisible(false);
        runpane.setVisible(false);
        mainpane.setVisible(true);
        validate(); 
    }
    
    public void showRuntimePane(){
    	mainpane.setVisible(false);
    	browsepane.setVisible(false);
    	studentpane.setVisible(false);
    	classpane.setVisible(false);
    	runpane.setVisible(true);
    	validate(); 
    }

-    public void showBrowsePane(){
        mainpane.setVisible(false);
        assignpane.setVisible(false);
        browsepane.setVisible(true);
        validate(); 
    }
+    public void showBrowsePane(){
        mainpane.setVisible(false);
        studentpane.setVisible(false);
        classpane.setVisible(true);
        browsepane.setVisible(true);
        validate(); 
    }

     public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new UserInterfaceManager(); 
            }
        });
    }