<?

##########################################################################
# Viewable.php:  PHP file for the Simcal1 module.                        #
# Copyright (c) 2004 Daniel Dvorkin.                                     #
# Distributed under the Artistic License, WITHOUT "optional clause 8"    #
# (see http://www.opensource.org/licenses/artistic-license.php).         #
# All rights not granted in this license are reserved by the author.     #
##########################################################################

class DbEntityViewable
{

/* variables */

	//table variables
	var $Id = 0;
	var $Exp1 = 0.00;
	var $Exp2 = 0.00;
	var $Exp3 = 0.00;
	var $Variability = 0.00;
	var $UserAnnotation = "";
	
	//query variables
	var $Tablename = "DbEntities";
	
	//book-keeping variables
	var $IsDefault = TRUE;
	var $RelatedSet = FALSE;
	
/* constructor */

	function DbEntityViewable()
	{//PRECONDITION:  None.
	 //POSTCONDITION:  $this has been instantiated as an empty record.
	 
		$this->init_default_valued_record();
		
		return;
		
	}//end function DbEntityViewable

/* contructor-related functions */
	
	function init_record_from_query($dbRecord)
	{//PRECONDITION:  $dbRecord is a database return object (as generated
	 // by objq(), or iteration through the results of mobq()) drawn from
	 // a query to $this->Tablename.
	 //POSTCONDITION:  values from $dbRecord have been inserted into $this.
		
		$fields = get_object_vars($dbRecord);
		foreach ($fields as $key => $val) $this->$key = $val;
		$this->IsDefault = FALSE;
		
		return;
	
	}//end function init_record_from_query
	
	function init_default_valued_record()
	{//PRECONDITION:  None except that $this be instantiated, and that we
	 // are willing to wipe out all data currently in $this.
	 //POSTCONDITION:  all database-derived variables in $this have been
	 // set or reset to their default values.
	 
		$fields = get_class_vars(get_class($this));
		foreach($fields as $key => $val) $this->$key = $val;
		$this->IsDefault = TRUE;
			
		return;
	
	}//end function init_default_valued_record
	
/* display functions */

	function show_search()
	{//PRECONDITION:  The user has requested a gene or cluster search.
	 //POSTCONDITION:  The user has been instructed on how to perform a
	 // search and a search form has been displayed.
	 
		?>
		
		<p>Use the form below to search for genes or clusters.  The same
		options are available for both types of searches.</p>
		
		<p>Searching on "Cluster Characteristics" when searching for genes
		will return genes belonging to clusters with those characteristics,
		and searching on "Gene Characteristics" when searching for clusters
		will return clusters containing genes with those characteristics.
		"Expression Levels" searches always search for the type of record
		(gene or cluster) selected with the "Search For" buttons.</p>
		
		<p>Please note that if the search criteria are not fairly
		specific, the result set may be very large.</p>
		
		<?
		
		DbEntityViewable::show_search_form();
			  
		return;
	
	}//end function show_search

	function show_search_form()
	{//PRECONDITION:  The interface needs to show a search form.
	 //POSTCONDITION:  The actual search form has been displayed.
	 
		if($_REQUEST['action'] == "Gene Search" ||
		   $_REQUEST['action'] == "Gene Search Results")
		{
			$gene = TRUE;
			$cluster = FALSE;
		}
		elseif($_REQUEST['action'] == "Cluster Search" ||
			   $_REQUEST['action'] == "Cluster Search Results")
		{
			$gene = FALSE;
			$cluster = TRUE;
		}
	
		?>
		
		<form method = "get" action = "index.php">
		<table align = "center">
			<tr>
				<td class = "formheader">
					<b>Search For:</b>&nbsp;&nbsp;&nbsp;&nbsp;
				</td>
				<td colspan = "2" class = "formlabelleft">
					Genes
					<input type = "radio" name = "action"
						value = "Gene Search Results"
						<? if($gene) echo "checked=\"checked\""; ?>>
					&nbsp;&nbsp;&nbsp;
					Clusters
					<input type = "radio" name = "action"
						value = "Cluster Search Results"
						<? if($cluster) echo "checked=\"checked\""; ?>>
				</td>
			</tr>
			<tr>
				<td class = "formtopheader">
					Gene Characteristics
				</td>
				<td class = "formtopheader">
					Cluster Characteristics
				</td>
				<td class = "formtopheader">
					Expression Levels
				</td>
			</tr>
			<tr>
				<td>
					<? GeneViewable::show_search_table(); ?>
				</td>
				<td>
					<? ClusterViewable::show_search_table(); ?>
				</td>
				<td>
					<? DbEntityViewable::show_search_table(); ?>
				</td>
			</tr>
			<tr>
				<td colspan = "3" align = "right">
					<input type = "submit" value = "Get Search Results">
				</td>
			</tr>
		</table>
		</form>
				
		
		<?
			  
		return;
	
	}//end function show_search_form
	
	function show_search_table()
	{//PRECONDITION:  The interface has requested the display of the
	 // particular search form element relating to the attributes of
	 // $this.
	 //POSTCONDITION:  The search form element has been displayed.
	 //NOTE:  This is an odd function, in that it has a definition here in
	 // the parent class, but is also redefined, a la template functions,
	 // in the child classes.  In $this, it displays expression search
	 // fields.  Child class versions display information specific to
	 // those classes.
	 
	 
		?>
		
		<table>
			<tr>
				<th><!-- spacer cell --></th>
				<th class = "heavy">&le;</th>
				<th class = "heavy">&ge;</th>
			</tr>
			<tr>
				<td class = "formlabel">
					Exp. 0:30
				</td>
				<td>
					<input type = "text" size = "5" name = "Exp1le">
				</td>
				<td>
					<input type = "text" size = "5" name = "Exp1ge">
				</td>
			</tr>
			<tr>
				<td class = "formlabel">
					Exp. 2:00
				</td>
				<td>
					<input type = "text" size = "5" name = "Exp2le">
				</td>
				<td>
					<input type = "text" size = "5" name = "Exp2ge">
				</td>
			</tr>
			<tr>
				<td class = "formlabel">
					Exp. 8:30
				</td>
				<td>
					<input type = "text" size = "5" name = "Exp3le">
				</td>
				<td>
					<input type = "text" size = "5" name = "Exp3ge">
				</td>
			</tr>
			<tr>
				<td class = "formlabel">
					Variability
				</td>
				<td>
					<input type = "text" size = "5" name = "Varle">
				</td>
				<td>
					<input type = "text" size = "5" name = "Varge">
				</td>
			</tr>
		</table>
			
		<?
		
		return;
	
	}//end function show_search_table

	function show_search_results()
	{//PRECONDITION:  A search form has been filled out and submitted.
	 //POSTCONDITION:  All records matching the search request have been
	 // displayed in tabular form.
	 
		//data retrieval
		$records = mobq($this->query_string());
		$count = count($records);
		
		//inform user of results, if any
		$rname = $count == 1 ? "result" : "results";
		?>
		<p class = "center">Your search returned <? echo $count . " " . 
		$rname; ?>.  To search again, use the search form at the end
		of the page.</p>
		<?
		
		//display results
		$this->show_search_results_table($records);
		
		return;
	
	}//end function show_search_results
	
	function show_search_results_table($records)
	{//PRECONDITION:  $records is an array of DbEntity child class
	 // objects returned by a search.
	 //POSTCONDITION:  $records has been displayed in tabular form.
	 	
		$count = count($records);
		
		if($count > 0)
		{
			echo "<table border = \"1\" align = \"center\">";
			$this->show_table_header();
			$classname = get_class($this);
			$Entity = new $classname();
			foreach($records as $record)
			{
				$Entity->init_record_from_query($record);
				$Entity->show_row();
			}
			echo "</table>";
		}
		
		return;
	
	}//end function show_search_results_table
	
	function show_self()
	{//PRECONDITION:  The user has requested to view $this, a specific
	 // and uniquely identified record of a DbEntity child class.
	 //POSTCONDITION:  $this has been displayed.
	 
		?>
		
		<form method = "get" action = "index.php">
		<input type = "hidden" name = "action"
			value = "<? echo $_REQUEST['action']; ?>">
		
		<p class = "pageheader"><? echo $this->title_string(); ?></p>
		
		<table align = "center" cellpadding = "10">
			<tr>
				<td class = "formtopheader">
					Characteristics
				</td>
				<td rowspan = "4">
					<? $this->show_graphics(); ?>
				</td>
			</tr>
			<tr>
				<td>
					<? $this->show_characteristics(); ?>
				</td>
			</tr>
			<tr>
				<td class = "formtopheader">
					Annotations
				</td>
			</tr>
			<tr>
				<td>
					<? $this->show_annotations(); ?>
				</td>
			</tr>
			<tr>
				<? if($_REQUEST['showRelated']): ?>
				<td colspan = "2">
						<p class = "formtopnoundl"><u>Related Genes and
						Clusters</u> &darr;</p>
						<? $this->show_related(); ?>
				</td>
				<? else: ?>
				<td colspan = "2">
					<a href = "<? echo $this->my_href(); ?>&showRelated=1">
					<p class = "pagefooter">Show Related Genes and Clusters
					</p></a>
				</td>
				<? endif; ?>
			</tr>
		</table>
		
		</form>
				
		<?
			  
		return;
	
	}//end function show_self
	
	function show_plot($relateds = NULL)
	{//PRECONDITION:  The interface has requested a plot of the expression
	 // values of $this.  If set, $relateds must be an array of related
	 // DbEntity child class objects (e.g., neigbor genes, child clusters,
	 // etc.) whose expression values are to be shown on the same plot.
	 //POSTCONDITION:  The requested plot has been displayed.  Measured
	 // values of $this are shown as dots of one color, interpolated
	 // values of $this are shown as lines of another color, and a third
	 // color is used to show line plots of expression values of all
	 // records in $relateds.
	 
		//find largest possible absolute value of expressions, pad it a bit
		$explim = max(rowq("select max(abs(Exp1)), 
								   max(abs(Exp2)), 
								   max(abs(Exp3)) 
							from Genes")) + 0.25;
	
		//mandatory parameters for plot_from_arrays
		$name = $this->plot_title();
		$path = "graphics";
		$xlabel = "Time Point";
		$ylabel = "Expression";
		$xvals = array(0, 1, 2, 3);
		$yvals = array(0, $this->Exp1, $this->Exp2, $this->Exp3);
		
		//title and style parameters for plot_from_arrays
		$title = "Measured";
		$interpolate = TRUE;
		$interptitle = "Interpolated";
		$scale = .75;
		
		//general plotting information  parameters for plot_from_arrays
		$max = array_limit($yvals); //calculation, not passed
		$lim = sqrt($max * $explim); //calculation, not passed
		$xyranges = array(-.1, 3.1, -$lim, $lim);
		$pointsize = 1.5;
		$xtics = "0, 1, 3";
		$ytics = "";
		
		//extra data parameters for plot_from_arrays
		if(is_array($relateds))
		{
			$optxs = array();
			$optys = array();
			foreach($relateds as $rel)
			{
				array_push($optxs, array(0, 1, 2, 3));
				array_push($optys, 
					array(0, $rel->Exp1, $rel->Exp2, $rel->Exp3));
			}
			$max = max($max, array_limit_2d($optys));
				//calculation, not passed
			$lim = sqrt($max * $explim); //calculation, not passed
			$xyranges = array(-.1, 3.1, -$lim, $lim);
			$optinterp = TRUE;
			$opttitle = "Related";
		}
		else
			$optxs = $optys = $optinterp = $opttitle = NULL;
						
		plot_from_arrays
			($name, $path, $xlabel, $ylabel, $xvals, $yvals,
			 $title, $interpolate, $interptitle, $scale,
			 $xyranges, $pointsize, $xtics, $ytics,
			 $optxs, $optys, $optinterp, $opttitle);
	
		return;
		
	}//end function show_plot
	
/* other functions */

	function query_string()
	{//PRECONDITION:  $_REQUEST is properly formatted as the result of
	 // a search form submission, with key-value pairs relating to
	 // attributes of the DbEntity child class record(s) to be retrieved.
	 // This function can also be used to sort previously retrieved
	 // records, which is the information contained in 
	 // $_REQUEST['OldRequest'] if that variable is set.
	 //POSTCONDITION:  A MySQL query string to find these records, sorted
	 // as desired if applicable, has been returned.
	 
		//get any old request information
		if(strlen($_REQUEST['OldRequest']))
			$_REQUEST = array_merge
				(formvalue_unpack($_REQUEST['OldRequest']), $_REQUEST);
	
		//determine which table we're in for table abbrevation ("tab")
		if($this->Tablename == "Genes") $tab = "G";
		elseif($this->Tablename == "Clusters") $tab = "C";
		
		//start off our query string
		$query = "select distinct $tab.* 
				  from	 Genes G, Clusters C, ClusterGenes CG
				  where	 G.Id = CG.GeneId and
				  		 C.Id = CG.ClusterId and
				  		 C.Rank = CG.Rank";
			//NOTE:  we can get away with this "where" because under the
			//current algorithm, all genes will be members of a cluster.
			//If we ever go to an algorithm that allows singletons, we
			//will have to check for the existence of gene and cluster
			//information separately before linking them together in the
			//search string.  This would probably require a dummy "where"
			//clause along the lines of "where 1=1 ".
		
		//set general gene characteristic information
		$fieldsInfo = mobq("describe Genes");
		foreach ($fieldsInfo as $fieldInfo)
		{
			$fieldName = $fieldInfo->Field;
			$fieldValue = $_REQUEST['Gene'][$fieldName];
			
			if(strlen($fieldValue))
			{//we have something to add to the search
			
				$query .= " and G.$fieldName";
				
				if(strcasecmp($fieldInfo->Type, "text"))
					$query .= " = \"$fieldValue\"";
				else
				{//text field, so process appropriately
					
					$fieldValue = addslashes(stripslashes($fieldValue));
					$query .= " like \"%$fieldValue%\"";
				}
			}
		}
		
		//set general cluster characteristic information
		$fieldsInfo = mobq("describe Clusters");
		foreach ($fieldsInfo as $fieldInfo)
		{
			$fieldName = $fieldInfo->Field;
			$fieldValue = $_REQUEST['Cluster'][$fieldName];
			
			if(strlen($fieldValue))
			{//we have something to add to the search
			
				$query .= " and C.$fieldName";
				
				if(strcasecmp($fieldInfo->Type, "text"))
					$query .= " = \"$fieldValue\"";
				else
				{//text field, so process appropriately
					
					$fieldValue = addslashes(stripslashes($fieldValue));
					$query .= " like \"%$fieldValue%\"";
				}
			}
		}
		
		//set cluster rank information
		if(strlen($_REQUEST['Cluster']['RankEq']))
			$query .= " and C.Rank = " . $_REQUEST['Cluster']['RankEq'];
		if(strlen($_REQUEST['Cluster']['RankLe']))
			$query .= " and C.Rank <= " . $_REQUEST['Cluster']['RankLe'];
		if(strlen($_REQUEST['Cluster']['RankGe']))
			$query .= " and C.Rank >= " . $_REQUEST['Cluster']['RankGe'];
		
		//set expression information
		if(strlen($_REQUEST['Exp1le']))
			$query .= " and $tab.Exp1 <= " . $_REQUEST['Exp1le'];
		if(strlen($_REQUEST['Exp1ge']))
			$query .= " and $tab.Exp1 >= " . $_REQUEST['Exp1ge'];
		if(strlen($_REQUEST['Exp2le']))
			$query .= " and $tab.Exp2 <= " . $_REQUEST['Exp2le'];
		if(strlen($_REQUEST['Exp2ge']))
			$query .= " and $tab.Exp2 >= " . $_REQUEST['Exp2ge'];
		if(strlen($_REQUEST['Exp3le']))
			$query .= " and $tab.Exp3 <= " . $_REQUEST['Exp3le'];
		if(strlen($_REQUEST['Exp3ge']))
			$query .= " and $tab.Exp3 >= " . $_REQUEST['Exp3ge'];
		if(strlen($_REQUEST['Varle']))
			$query .= " and $tab.Variability <= " . $_REQUEST['Varle'];
		if(strlen($_REQUEST['Varge']))
			$query .= " and $tab.Variability >= " . $_REQUEST['Varge'];
			
		//set ordering information
		$query .= " order by ";
		if(strlen($_REQUEST['OrderBy']))
		{
			if($_REQUEST['OrderBy'] == "Exp 0:30")
				$query .= "Exp1";
			elseif($_REQUEST['OrderBy'] == "Exp 2:00")
				$query .= "Exp2";
			elseif($_REQUEST['OrderBy'] == "Exp 8:30")
				$query .= "Exp3";
			else
				$query .= $_REQUEST['OrderBy'];
		}
		else
			$query .= "Id";
		
		return $query;
	
	}//end function query_string
	
	function do_handle_changes()
	{//PRECONDITION:  $_REQUEST is properly formatted to contain key-value
	 // pairs for any user-initiated changes to $this.  Currently, this is
	 // only user annotation -- others may be possible in the future.
	 //POSTCONDITION:  The changes have been saved in the database.
	 
		if(array_key_exists("UserAnnotation", $_REQUEST))
		{
			$this->UserAnnotation = stripslashes
				($_REQUEST['UserAnnotation']);
			
			$query = "update $this->Tablename
					  set    UserAnnotation = '" . 
							 addslashes($this->UserAnnotation) . "'
					  where  Id = $this->Id";
					  
			//NOTE:  this works because the minimum rank of any cluster 
			// (or any other ranked record, for that matter) is 1 under the
			// current algorithm.  If we ever go to something that allows 0
			// ranks, something more sophisticated -- i.e., checking to see
			// if Rank is defined as a variable in $this -- will be required.
			if($this->Rank)
				$query .= " and Rank = $this->Rank";
				
			setq($query);
		}
		
		return;
		
	}//end function do_handle_changes

/* display template functions */

	function show_general()
	{//TEMPLATE FUNCTION:  See child class definition if exists.
	 // Otherwise, no pre- or post-conditions apply.
	 //PRECONDITION:  The user has requested to see general information
	 // relating to records of the class of $this.
	 //POSTCONDITION:  Statistics about records of the class of $this, as
	 // a group, have been displayed and plotted.
	 		  
		return;
	
	}//end function show_general

	function show_table_header()
	{//TEMPLATE FUNCTION:  See child class definition if exists.
	 // Otherwise, no pre- or post-conditions apply.
	 //PRECONDITION:  The interface has requested a sortable header for
	 // the tabular display of found records.
	 //POSTCONDITION:  The header has been displayed as a table row.
	
		return;
	
	}//end function show_table_header

	function show_row()
	{//TEMPLATE FUNCTION:  See child class definition if exists.
	 // Otherwise, no pre- or post-conditions apply.
	 //PRECONDITION:  The interface has requested the display of some
	 // attributes of $this in a tabular display.
	 //POSTCONDITION:  The requested information has been displayed
	 // as a table row.
	
		return;
	
	}//end function show_row

	function show_characteristics()
	{//TEMPLATE FUNCTION:  See child class definition if exists.
	 // Otherwise, no pre- or post-conditions apply.
	 //PRECONDITION:  The interface has requested the display of general
	 // attributes of $this formatted for single-record display.
	 //POSTCONDITION:  The information has been displayed.
	
		return;
	
	}//end function show_characteristics

	function show_annotations()
	{//TEMPLATE FUNCTION:  See child class definition if exists.
	 // Otherwise, no pre- or post-conditions apply.
	 //PRECONDITION:  The interface has requested the display of
	 // annotation attributes of $this formatted for single-record
	 // display.
	 //POSTCONDITION:  The information has been displayed.  User
	 // annotation has been shown as an editable field.
	 
		return;
	
	}//end function show_annotations

	function show_graphics()
	{//TEMPLATE FUNCTION:  See child class definition if exists.
	 // Otherwise, no pre- or post-conditions apply.
	 //PRECONDITION:  The interface has requested the graphical display
	 // of expression attributes of $this, and possibly the expression
	 // values of related information.
	 //POSTCONDITION:  The information has been displayed, along with form
	 // elements allowing the user to choose whether or not to show
	 // related information on the plot, and what types of information
	 // to be shown.
	 
		return;
	
	}//end function show_graphics

	function show_related()
	{//TEMPLATE FUNCTION:  See child class definition if exists.
	 // Otherwise, no pre- or post-conditions apply.
	 //PRECONDITION:  The user has requested the display of related
	 // records (e.g., neighbor genes, child clusters, etc.) in a single-
	 // record display.
	 //POSTCONDITION:  The information has been displayed in tabular form.
	 
		return;
	
	}//end function show_related

	function show_as_related()
	{//TEMPLATE FUNCTION:  See child class definition if exists.
	 // Otherwise, no pre- or post-conditions apply.
	 //PRECONDITION:  The interface has requested that certain attributes
	 // of $this, as a related record of some other DbEntity child class
	 // record, be displayed.
	 //POSTCONDITION:  The requested information has been displayed in
	 // a table row.
	 
		return;
	
	}//end function show_as_related

/* other template functions */

	function title_string()
	{//TEMPLATE FUNCTION:  See child class definition if exists.
	 // Otherwise, no pre- or post-conditions apply.
	 //PRECONDITION:  $this is a properly instantiated, non-empty record.
	 //POSTCONDITION:  A string containing a short descriptive title for
	 // $this has been returned.
	 
		return;
	
	}//end function title_string

	function my_href()
	{//TEMPLATE FUNCTION:  See child class definition if exists.
	 // Otherwise, no pre- or post-conditions apply.
	 //PRECONDITION:  $this is a properly instantiated, non-empty record.
	 //POSTCONDITION:  A reference string suitable for insertion in an
	 // "<a href = ..." HTML element has been returned.
	 //NOTE:  this function does NOT format the entire HTML element, only
	 // returns the reference itself.
	 
		return;
	
	}//end function my_href

	function plot_title()
	{//TEMPLATE FUNCTION:  See child class definition if exists.
	 // Otherwise, no pre- or post-conditions apply.
	 //PRECONDITION:  $this is a properly instantiated, non-empty record.
	 //POSTCONDITION:  A string suitable for use as the name of a graphics
	 // file (currently in .png format) plotting attributes of $this (and
	 // possibly related records) has been returned.  File type extension
	 // is NOT included.
	 
		return;
	
	}//end function plot_title
	
	function set_related()
	{//TEMPLATE FUNCTION:  See child class definition if exists.
	 // Otherwise, no pre- or post-conditions apply.
	 //PRECONDITION:  Related records have been requested for view.
	 //POSTCONDITION:  Arrays of related objects have been filled in.
	 
		return;
		
	}//end function set_related

} /* END CLASS DbEntityViewable */

class GeneViewable extends DbEntityViewable
{

/* variables */

	//table variables
	var $Reliability = 0.00;
	var $AffyName = "";
	var $AffyAnnotation = "";

	//query variables
	var $Tablename = "Genes";
	
	//related object variables
	var $Clusters = NULL;
	var $Neighbors = NULL;
	var $Leaders = NULL;
	var $Followers = NULL;

/* contructor */

	function GeneViewable($Id = NULL)
	{//PRECONDITION:  If set, $Id must be the Id of a valid record in
	 // the Genes table.
	 //POSTCONDITION:  If $Id is set, $this has been instantiated with
	 // the information in the record identified by $Id.  Otherwise,
	 // a blank record has been instantiated.
	 
		if(is_numeric($Id))
		{
			$dbRecord = objq("select * 
							  from   $this->Tablename
							  where  Id = $Id");
			$this->init_record_from_query($dbRecord);
		}
		else
			$this->init_default_valued_record();
		
		return;
	
	}//end function GeneViewable
	
/* display functions */

/* other functions */
	
/* display template-derived functions */

	function show_general()
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
			
		$geneCount = valq("select count(*)
						   from   Genes");
						   
		$affyGenes = valq("select count(*)
						   from   Genes
						   where  AffyName like 'AFF%'");
						   
		$expGenes = $geneCount - $affyGenes;
		
		$avg_expressions = objq("select avg(Exp1) as avg_05,
										avg(Exp2) as avg_20,
										avg(Exp3) as avg_85
								  from   Genes");
							  
		$avg_hi_exp =  objq("select avg(Exp1) as avg_05,
									avg(Exp2) as avg_20,
									avg(Exp3) as avg_85
							 from   Genes
							 where  (Exp1 + Exp2 + Exp3) > 0");
							  
		$avg_low_exp = objq("select avg(Exp1) as avg_05,
									avg(Exp2) as avg_20,
									avg(Exp3) as avg_85
							 from   Genes
							 where  (Exp1 + Exp2 + Exp3) < 0");
							  
		$avg_vhi_exp =  objq("select avg(Exp1) as avg_05,
									 avg(Exp2) as avg_20,
									 avg(Exp3) as avg_85
							 from    Genes
							 where   Exp1 > 0 and
									 Exp2 > 0 and
									 Exp3 > 0");
							  
		$avg_vlow_exp = objq("select avg(Exp1) as avg_05,
									 avg(Exp2) as avg_20,
									 avg(Exp3) as avg_85
							 from   Genes
							 where  Exp1 < 0 and
									Exp2 < 0 and
									Exp3 < 0");
	
		
							
		?>
		
		<p>Some facts about the genes:</p>
		
		<table cellpadding = "0" cellspacing = "0"><tr>
			
			<td>
	
				<ul>
				
					<li><u><? echo $geneCount; ?></u> genes
					used.</li>
				
					<li><u><? echo $affyGenes; ?></u> genes
					identified by Affymetrix.</li>
				
					<li><u><? echo $expGenes; ?></u> experimental
					genes.</li>
					
					<li>Average expression levels for all genes:
					<br /><u><? echo number_format
						($avg_expressions->avg_05, 3); ?></u>
						at time point 0:30
					<br /><u><? echo number_format
						($avg_expressions->avg_20, 3); ?></u>
						at time point 2:00
					<br /><u><? echo number_format
						($avg_expressions->avg_85, 3); ?></u>
						at time point 8:30</li>
					
					<li>Average expression levels for generally
					upregulated genes:
					<br /><u><? echo number_format
						($avg_hi_exp->avg_05, 3); ?></u>
						at time point 0:30
					<br /><u><? echo number_format
						($avg_hi_exp->avg_20, 3); ?></u>
						at time point 2:00
					<br /><u><? echo number_format
						($avg_hi_exp->avg_85, 3); ?></u>
						at time point 8:30</li>
					
					<li>Average expression levels for generally
					downregulated genes:
					<br /><u><? echo number_format
						($avg_low_exp->avg_05, 3); ?></u>
						at time point 0:30
					<br /><u><? echo number_format
						($avg_low_exp->avg_20, 3); ?></u>
						at time point 2:00
					<br /><u><? echo number_format
						($avg_low_exp->avg_85, 3); ?></u>
						at time point 8:30</li>
					
					<li>Average expression levels for consistently
					upregulated genes:
					<br /><u><? echo number_format
						($avg_vhi_exp->avg_05, 3); ?></u>
						at time point 0:30
					<br /><u><? echo number_format
						($avg_vhi_exp->avg_20, 3); ?></u>
						at time point 2:00
					<br /><u><? echo number_format
						($avg_vhi_exp->avg_85, 3); ?></u>
						at time point 8:30</li>
					
					<li>Average expression levels for consistently
					downregulated genes:
					<br /><u><? echo number_format
						($avg_vlow_exp->avg_05, 3); ?></u>
						at time point 0:30
					<br /><u><? echo number_format
						($avg_vlow_exp->avg_20, 3); ?></u>
						at time point 2:00
					<br /><u><? echo number_format
						($avg_vlow_exp->avg_85, 3); ?></u>
						at time point 8:30</li>
				
				</ul>
			
			</td>
			<td>
			
				<?
		
				//show graphics of genes given numerically above
				echo "<p class = \"caption\">";
				
				//mandatory parameters for plot_from_arrays
				$name = "gene_averages";
				$path = "graphics";
				$xlabel = "Time Point";
				$ylabel = "Expression";
				$xvals = array(0, 1, 2, 3);
				$yvals = array
				(
					0,
					$avg_expressions->avg_05,
					$avg_expressions->avg_20,
					$avg_expressions->avg_85
				);
				
				//title and style parameters for plot_from_arrays
				$title = "All Genes Measured";
				$interpolate = TRUE;
				$interptitle = "All Genes Interpolated";
				$scale = 0.75;
				
				//general plotting information  parameters for plot_from_arrays
				$xyranges = array(-.1, 3.1, -$lim, $lim);
				$pointsize = 1.5;
				$xtics = "0, 1, 3";
				$ytics = "";
				
				//extra data parameters for plot_from_arrays
				$optxs = array
				(
					array(0, 1, 2, 3),
					array(0, 1, 2, 3),
					array(0, 1, 2, 3),
					array(0, 1, 2, 3),
				);
				$optys = array
				(
					array
					(
						0,
						$avg_hi_exp->avg_05,
						$avg_hi_exp->avg_20,
						$avg_hi_exp->avg_85
					),
					array
					(
						0,
						$avg_low_exp->avg_05,
						$avg_low_exp->avg_20,
						$avg_low_exp->avg_85
					),
					array
					(
						0,
						$avg_vhi_exp->avg_05,
						$avg_vhi_exp->avg_20,
						$avg_vhi_exp->avg_85
					),
					array
					(
						0,
						$avg_vlow_exp->avg_05,
						$avg_vlow_exp->avg_20,
						$avg_vlow_exp->avg_85
					)
				);
				$xyranges = array(-.1, 3.1, -1, 1);
				$optinterp = TRUE;
				$opttitle = "High, Low, Etc.";
								
				plot_from_arrays
					($name, $path, $xlabel, $ylabel, $xvals, $yvals,
					 $title, $interpolate, $interptitle, $scale,
					 $xyranges, $pointsize, $xtics, $ytics,
					 $optxs, $optys, $optinterp, $opttitle);
					 
				echo "<br />Average gene expression levels.</p>";
				
				?>
				
			</td>
			
		</tr></table>
		
		<?
			  
		return;
	
	}//end function show_general
	
	function show_table_header()
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
	
		unset($_REQUEST['OldRequest']);
		$OldRequest = formvalue_pack($_REQUEST);
		
		?>		
		<form method = "get" action = "index.php">
		<input type = "hidden" name = "action"
			value = "<? echo $_REQUEST['action']; ?>">
		<tr>
			<td>
				<input type = "submit" name = "OrderBy" 
					value = "Id">
			</td>
			<td>
				<input type = "submit" name = "OrderBy"
					value = "AffyName">
			</td>
			<td>
				<input type = "submit" name = "OrderBy" 
					value = "Exp 0:30">
			</td>
			<td>
				<input type = "submit" name = "OrderBy" 
					value = "Exp 2:00">
			</td>
			<td>
				<input type = "submit" name = "OrderBy" 
					value = "Exp 8:30">
			</td>
			<td>
				<input type = "submit" name = "OrderBy" 
					value = "Variability">
			</td>
			<td>
				<input type = "submit" name = "OrderBy" 
					value = "Reliability">
			</td>
		</tr>
		<input type = "hidden" name = "OldRequest" 
			value = "<? echo $OldRequest; ?>">
		</form>
		
		<?
		
		return;
	
	}//end function show_table_header
	
	function show_row()
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
	
		?>
		
		<tr>
			<td>
				<a href = "<? echo $this->my_href(); ?>">
				<? echo $this->Id; ?></a>
			</td>
			<td>
				<a href = "<? echo $this->my_href(); ?>">
				<? echo $this->AffyName; ?></a>
			</td>
			<td>
				<? echo number_format
						($this->Exp1, 3); ?>
			</td>
			<td>
				<? echo number_format
						($this->Exp2, 3); ?>
			</td>
			<td>
				<? echo number_format
						($this->Exp3, 3); ?>
			</td>
			<td>
				<? echo number_format
						($this->Variability, 3); ?>
			</td>
			<td>
				<? echo number_format
						($this->Reliability * 100.0, 3); ?>
			</td>
		</tr>
		
		<?
		
		return;
	
	}//end function show_row

	function show_search_table()
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
	
		?>
		
		<table>
			<tr>
				<td class = "formlabel">
					ID #
				</td>
				<td>
					<input type = "text" size = "5" name = "Gene[Id]">
				</td>
			</tr>
			<tr>
				<td class = "formlabel">
					Affy Name
				</td>
				<td>
					<input type = "text" size = "15" 
						name = "Gene[AffyName]">
				</td>
			</tr>
			<tr>
				<td class = "formlabel">
					Affy Annotation
				</td>
				<td>
					<input type = "text" size = "15" 
						name = "Gene[AffyAnnotation]">
				</td>
			</tr>
			<tr>
				<td class = "formlabel">
					User Annotation
				</td>
				<td>
					<input type = "text" size = "15" 
						name = "Gene[UserAnnotation]">
				</td>
			</tr>
		</table>
		
		<?
		
		return;
	
	}//end function show_search_table
	
	function show_characteristics()
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
	
		$fields = array
		(
			"Exp1" => "Exp 0:30",
			"Exp2" => "Exp 2:00",
			"Exp3" => "Exp 8:30",
			"Variability" => "Variability",
			"Reliability" => "Reliability"
		);
		
		?>
		
		<input type = "hidden" name = "Id"
			value = "<? echo $this->Id; ?>">
		<table align = "center">
		
		<?
		
		foreach($fields as $key => $display)
		{
			$value = is_numeric($this->$key) ? 
				number_format($this->$key, 3, ".", "") : $this->$key;
			
			?>
			<tr>
				<td class = "formlabel"><? echo $display; ?>:</td>
				<td class = "formvalue"><? echo $value; ?></td>
			</tr>
			<?
		}
		
		?>
		
		</table>
		
		<?
	
		return;
	
	}//end function show_characteristics

	function show_annotations()
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
			
		?>
		
		<form method = "get" target = "_self">
		<input type = "hidden" name = "Id"
			value = "<? echo $this->Id; ?>">
		<table border = "0">
			<tr>
				<td class = "formlabel">Affy:</td>
				<td class = "formvalue">
					<? echo html_format($this->AffyAnnotation); ?>
				</td>
			</tr>
			<tr>
				<td class = "formlabel">User:</td>
				</td>
				<td><textarea cols = "38" rows = "10" name = "UserAnnotation"
					><? echo $this->UserAnnotation; ?></textarea>
				</td>
			</tr>
			<tr>
				<td>
					<!-- spacer cell -->
				</td>
				<td align = "center">
					<input type = "submit" name = "subaction"
						value = "Save Changes">
					</nobr>
			</tr>
		</table>
		</form>
		
		<?
		
		return;
	
	}//end function show_annotations

	function show_graphics()
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
	
		switch($_REQUEST['subaction'])
		{
			case "Clusters":
			
				$this->set_related();
				$this->show_plot($this->Clusters);
				$_REQUEST['showRelated'] = 1;
			
				?>
				<p class = "caption">Expression levels for this gene and
				its associated clusters.</p>
				<?
				
			break;
			
			case "Neighbors":
			
				$this->set_related();
				$this->show_plot($this->Neighbors);
				$_REQUEST['showRelated'] = 1;
			
				?>
				<p class = "caption">Expression levels for this gene and
				its nearest neighbors.</p>
				<?
				
			break;
			
			case "Leaders":
			
				$this->set_related();
				$this->show_plot($this->Leaders);
				$_REQUEST['showRelated'] = 1;
			
				?>
				<p class = "caption">Expression levels for this gene and
				its leaders.</p>
				<?
				
			break;
			
			case "Followers":
			
				$this->set_related();
				$this->show_plot($this->Followers);
				$_REQUEST['showRelated'] = 1;
			
				?>
				<p class = "caption">Expression levels for this gene and
				its followers.</p>
				<?
				
			break;
		
			case "Single Gene":
			default:
			
				$this->show_plot();
			
				?>
				<p class = "caption">Expression levels for only this gene.
				</p>
				<?
				
			break;
		}
		
		?>
		
		<table align = "center">
			<tr>
				<td class = "formlabel">
					Plots:
				</td>
				<td>
					<input type = "submit" name = "subaction" 
						value = "Single Gene" />
				</td>
				<td>
					<input type = "submit" name = "subaction" 
						value = "Clusters" />
				</td>
				<td>
					<input type = "submit" name = "subaction" 
						value = "Neighbors" />
				</td>
				<td>
					<input type = "submit" name = "subaction" 
						value = "Leaders" />
				</td>
				<td>
					<input type = "submit" name = "subaction" 
						value = "Followers" />
				</td>
			</tr>
		</table>
		
		<?
			  
		return;
	
	}//end function show_graphics
	
	function show_related()
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
	
		$this->set_related();
						   
		$Gene = new GeneViewable();
		$Cluster = new ClusterViewable();
		
		?>
		
		<table align = "center" cellpadding = "10">
			<tr>
				<td>
					<p class = "toplabel">Clusters</p>
					<? $Cluster->show_as_related($this->Clusters) ?>
				</td>
				<td>
					<p class = "toplabel">Leaders</p>
					<? $Gene->show_as_related($this->Leaders) ?>
				</td>
			</tr>
			<tr>
				<td>
					<p class = "toplabel">Neighbors</p>
					<? $Gene->show_as_related($this->Neighbors) ?>
				</td>
				<td>
					<p class = "toplabel">Followers</p>
					<? $Gene->show_as_related($this->Followers) ?>
				</td>
			</tr>
		</table>
		
		<?
						  
		return;
	
	}//end function show_related
	
	function show_as_related($Genes)
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
	
		if(count($Genes))
		{
			?>
			
			<table border = "1">
			
				<tr>
					<th>
						Id
					</th>
					<th>
						Name
					</th>
					<th>
						Rank
					</th>
					<th>
						Exp 0:30
					</th>
					<th>
						Exp 2:00
					</th>
					<th>
						Exp 8:30
					</th>
				</tr>
			
			<?
				
			foreach($Genes as $Gene)
			{
				$href = $this->my_href($Gene);
				
				?>
				
				<tr class = "formvalue">
					<td>
						<a href = "<? echo $href; ?>">
						<? echo $Gene->Id; ?></a>
					</td>
					<td>
						<a href = "<? echo $href; ?>">
						<? echo $Gene->AffyName; ?></a>
					</td>
					<td><? echo $Gene->Rank; ?></td>
					<td><? echo number_format($Gene->Exp1, 3); ?></td>
					<td><? echo number_format($Gene->Exp2, 3); ?></td>
					<td><? echo number_format($Gene->Exp3, 3); ?></td>
				</tr>
				
				<?
			}
			
			?>
				
			</table>
			
			<?
			
		}
		
		return;
	
	}//end function show_as_related
	
/* other template-derived functions */

	function title_string()
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
	
		return $this->IsDefault ? $_REQUEST['action'] :
			"Gene Id $this->Id, Affy Name \"$this->AffyName\"";
	
	}//end function title_string
	
	function my_href($Gene = NULL)
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
	
		return is_object($Gene) ?
			"index.php?action=Gene&Id=$Gene->Id" :
			"index.php?action=Gene&Id=$this->Id";
	
	}//end function my_href

	function plot_title()
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
	
		$retn = "Gene.Id." . $this->Id;
		if(strlen($_REQUEST['subaction']))
			$retn .= 
				"." . preg_replace("/ /", "_", $_REQUEST['subaction']);
		
		return $retn;
	
	}//end function plot_title
	
	function set_related()
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
	
		if(!$this->RelatedSet)
		{
			$this->Clusters = mobq("select distinct C.*
								    from   Clusters C, ClusterGenes G
								    where  G.GeneId = $this->Id and 
										   C.Id = G.ClusterId and
										   C.Rank = G.Rank
									order  by C.Rank");
							   
			$this->Neighbors = mobq("select distinct G.*, N.Rank 
								     from   Genes G, GeneNeighbors N
								     where  N.GeneId = $this->Id and 
										    G.Id = N.NeighborGeneId
									 order  by N.Rank");
							   
			$this->Leaders = mobq("select distinct G.*, S.Rank 
								   from   Genes G, GeneSuccessions S
								   where  S.FollowerGeneId = $this->Id and 
										  G.Id = S.LeaderGeneId
								   order  by S.Rank, G.Id");
							   
			$this->Followers = mobq("select distinct G.*, S.Rank 
								     from   Genes G, GeneSuccessions S
								     where  S.LeaderGeneId = $this->Id and 
										    G.Id = S.FollowerGeneId
									 order  by S.Rank, G.Id");
		}
		
		return;
		
	}//end function set_related

} /* END CLASS GeneViewable */

class ClusterViewable extends DbEntityViewable
{

/* variables */

	//table variables
	var $Rank = 0;
	var $Members = 0;
	var $Reliability = 0.00;
	var $ParentId = 0;

	//query variables
	var $Tablename = "Clusters";
	
	//related object variables
	var $Genes = NULL;
	var $Leaders = NULL;
	var $Followers = NULL;
	var $Children = NULL;

/* contructor */

	function ClusterViewable($Id = NULL, $Rank = NULL)
	{//PRECONDITION:  If set, $Id and $Rank must be the Id and Rank of a
	 // valid record in the Clusters table.
	 //POSTCONDITION:  If $Id and $Rank are set, $this has been
	 // instantiated with the information in the record identified by $Id
	 // and $Rank.  Otherwise, a blank record has been instantiated.
		if(is_numeric($Id) && is_numeric($Rank))
		{
			$dbRecord = objq("select * 
							  from   $this->Tablename
							  where  Id = $Id and
							  		 Rank = $Rank");
			$this->init_record_from_query($dbRecord);
		}
		else
			$this->init_default_valued_record();
		
		return;
	
	}//end function ClusterViewable

/* display functions */

/* other functions */

/* display template-derived functions */

	function show_general()
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
	
		$clusterGrowths = mobq("select Rank,
									   count(*) as ct,
									   min(Members) as minsize, 
									   avg(Members) as avgsize,
									   max(Members) as maxsize,
									   std(Members) as sizestd
								from   Clusters 
								group  by Rank 
								order  by Rank");
								
		
		$counts = array();
		$minsizes = array();
		$avgsizes = array();
		$maxsizes = array();
		foreach ($clusterGrowths as $cRow)
		{
			array_push($counts, $cRow->ct);
			array_push($minsizes, $cRow->minsize);
			array_push($avgsizes, $cRow->avgsize);
			array_push($maxsizes, $cRow->maxsize);
		}
							
		?>
		
		<p class = "centered">Cluster agglomeration stopped at rank 
		<? echo $GLOBALS['maxRank']; ?>.  Cluster growth proceeded
		as follows:</p>
		
		</ul>
		
		<table border = "1" align = "center" >
			<tr>
				<th>
					Rank
				</th>
				<th>
					# of Clusters
				</th>
				<th>
					Min. Cluster Size
				</th>
				<th>
					Avg. Cluster Size
				</th>
				<th>
					Max. Cluster Size
				</th>
				<th>
					Cluster Size Std. Dev.
				</th>
			</tr>
			<? foreach ($clusterGrowths as $cRow): ?>
			<tr>
				<td>
					<? echo $cRow->Rank; ?>
				</td>
				<td>
					<? echo $cRow->ct; ?>
				</td>
				<td>
					<? echo $cRow->minsize; ?>
				</td>
				<td>
					<? echo number_format($cRow->avgsize, 2, ".", ""); ?>
				</td>
				<td>
					<? echo $cRow->maxsize; ?>
				</td>
				<td>
					<? echo number_format($cRow->sizestd, 2, ".", ""); ?>
				</td>
			</tr>
			<? endforeach; ?>
		</table>
		
		<?
		
		//show graphics
		$ranks = array(1, 2, 3, 4);
		$xtics = "1, 1, 4";
		$scale = 0.4;
		$ctranges = array(min($ranks) - 0.5, max($ranks) + 0.5,
						  min($counts) - 300, max($counts) + 300);
		$msranges = array(min($ranks) - 0.5, max($ranks) + 0.5,
						  min($minsizes) - 300, max($minsizes) + 300);
		$asranges = array(min($ranks) - 0.5, max($ranks) + 0.5,
						  min($avgsizes) - 300, max($avgsizes) + 300);
		$xsranges = array(min($ranks) - 0.5, max($ranks) + 0.5,
						  min($maxsizes) - 300, max($maxsizes) + 300);
		$_REQUEST['smooth'] = "unique";
						  
		?>
						  
		<table align = "center" cellpadding = "10">
			<tr>
				<td>
					<? plot_from_arrays
						("ClusterCounts", "graphics", "Rank", "Clusters",
						$ranks, $counts, "", TRUE, "",
						$scale, $ctranges, 1.5, $xtics); ?>
				</td>
				<td>
					<? plot_from_arrays
						("Minsizes", "graphics", "Rank", "Min. Cl. Size",
						$ranks, $minsizes, "", TRUE, "",
						$scale, $msranges, 1.5, $xtics); ?>
				</td>
			</tr>
			<tr>
				<td>
					<? plot_from_arrays
						("Avgsizes", "graphics", "Rank", "Avg. Cl. Size",
						$ranks, $avgsizes, "", TRUE, "",
						$scale, $asranges, 1.5, $xtics); ?>
				</td>
				<td>
					<? plot_from_arrays
						("Maxsizes", "graphics", "Rank", "Max. Cl. Size",
						$ranks, $maxsizes, "", TRUE, "",
						$scale, $xsranges, 1.5, $xtics); ?>
			</tr>
		</table>
		
		<?
		
		return;
	
	}//end function show_general
	
	function show_table_header()
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
	
		unset($_REQUEST['OldRequest']);
		$OldRequest = formvalue_pack($_REQUEST);
		
		?>		
		<form method = "get" action = "index.php">
		<input type = "hidden" name = "action"
			value = "<? echo $_REQUEST['action']; ?>">
		<tr>
			<td>
				<input type = "submit" name = "OrderBy" 
					value = "Id">
			</td>
			<td>
				<input type = "submit" name = "OrderBy"
					value = "Rank">
			</td>
			<td>
				<input type = "submit" name = "OrderBy"
					value = "Members">
			</td>
			<td>
				<input type = "submit" name = "OrderBy" 
					value = "Exp 0:30">
			</td>
			<td>
				<input type = "submit" name = "OrderBy" 
					value = "Exp 2:00">
			</td>
			<td>
				<input type = "submit" name = "OrderBy" 
					value = "Exp 8:30">
			</td>
			<td>
				<input type = "submit" name = "OrderBy" 
					value = "Variability">
			</td>
			<td>
				<input type = "submit" name = "OrderBy" 
					value = "Reliability">
			</td>
		</tr>
		<input type = "hidden" name = "OldRequest" 
			value = "<? echo $OldRequest; ?>">
		</form>
		
		<?
		
		return;
	
	}//end function show_table_header
	
	function show_row()
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
	
		?>
		
		<tr>
			<td>
				<a href = "<? echo $this->my_href(); ?>">
				<? echo $this->Id; ?></a>
			</td>
			<td>
				<a href = "<? echo $this->my_href(); ?>">
				<? echo $this->Rank; ?></a>
			</td>
			<td>
				<? echo $this->Members; ?>
			</td>
			<td>
				<? echo number_format
						($this->Exp1, 3); ?>
			</td>
			<td>
				<? echo number_format
						($this->Exp2, 3); ?>
			</td>
			<td>
				<? echo number_format
						($this->Exp3, 3); ?>
			</td>
			<td>
				<? echo number_format
						($this->Variability, 3); ?>
			</td>
			<td>
				<? echo number_format
						($this->Reliability * 100.0, 3); ?>
			</td>
		</tr>
		
		<?
		
		return;
	
	}//end function show_row

	function show_search_table()
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
	
		$maxRank = valq("select max(Rank) from Clusters");
	
		?>
		
		<table>
			<tr>
				<td class = "formlabel">
					ID #
				</td>
				<td>
					<input type = "text" size = "5" 
						name = "Cluster[Id]">
				</td>
			</tr>
			<tr>
				<td class = "formlabel">
					Rank =
				</td>
				<td>
					<select name = "Cluster[RankEq]">
					<option value = "">(Any)</option>
					<?
						for($i = 1; $i <= $maxRank; $i++)
							echo "<option value = $i>$i</option>";
					?>
				</td>
			</tr>
			<tr>
				<td class = "formlabel">
					Rank &le;
				</td>
				<td>
					<select name = "Cluster[RankLe]">
					<option value = "">(Any)</option>
					<?
						for($i = 1; $i <= $maxRank; $i++)
							echo "<option value = $i>$i</option>";
					?>
				</td>
			</tr>
			<tr>
				<td class = "formlabel">
					Rank &ge;
				</td>
				<td>
					<select name = "Cluster[RankGe]">
					<option value = "">(Any)</option>
					<?
						for($i = 1; $i <= $maxRank; $i++)
							echo "<option value = $i>$i</option>";
					?>
				</td>
			</tr>
			<tr>
				<td class = "formlabel">
					User Annotation
				</td>
				<td>
					<input type = "text" size = "15" 
						name = "Cluster[UserAnnotation]">
				</td>
			</tr>
		</table>
					
		
		<?
		
		return;
	
	}//end function show_search_table
	
	function show_characteristics()
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
	
		$maxRank = valq("select max(Rank) from Clusters");
		if($this->Rank < $maxRank)
		{
			$pId = $this->ParentId;
			$pRank = $this->Rank + 1;	
			$Parent = new ClusterViewable($pId, $pRank);
			$pHref = $Parent->my_href();
			$pString = 
				"<a href = \"$pHref\">Cluster Id $pId, Rank $pRank</a>";
			unset($Parent);
		}
		else
			$pString = "N/A";
	
		$fields = array
		(
			"Exp1" => "Exp 0:30",
			"Exp2" => "Exp 2:00",
			"Exp3" => "Exp 8:30",
			"Variability" => "Variability",
			"Reliability" => "Reliability",
			"Members" => "Members"
		);
		
		?>
		
		<input type = "hidden" name = "Id"
			value = "<? echo $this->Id; ?>">
		<table align = "center">
		
		<?
		
		foreach($fields as $key => $display)
		{
			$value = is_numeric($this->$key) && $key != "Members" ?
				number_format($this->$key, 3, ".", "") : $this->$key;
			
			?>
			<tr>
				<td class = "formlabel"><? echo $display; ?>:</td>
				<td class = "formvalue"><? echo $value; ?></td>
			</tr>
			<?
		}
		
		?>
			<tr>
				<td class = "formlabel">Parent:</td>
				<td class = "formvalue"><? echo $pString; ?></td>
			</tr>
		
		</table>
		
		<?
	
		return;
	
	}//end function show_characteristics
	
	function show_annotations()
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
			
		?>
		
		<form method = "get" target = "_self">
		<input type = "hidden" name = "Id"
			value = "<? echo $this->Id; ?>">
		<input type = "hidden" name = "Rank"
			value = "<? echo $this->Rank; ?>">
		<table border = "0">
			<tr>
				<td class = "formlabel">User:</td>
				</td>
				<td><textarea cols = "40" rows = "12" name = "UserAnnotation"
					><? echo $this->UserAnnotation; ?></textarea>
				</td>
			</tr>
			<tr>
				<td>
					<!-- spacer cell -->
				</td>
				<td align = "center">
					<input type = "submit" name = "subaction"
						value = "Save Changes">
					</nobr>
			</tr>
		</table>
		</form>
		
		<?
		
		return;
	
	}//end function show_annotations
	
	function show_graphics()
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
	
		switch($_REQUEST['subaction'])
		{
			case "Genes":
			
				$this->set_related();
				$this->show_plot($this->Genes);
				$_REQUEST['showRelated'] = 1;
			
				?>
				<p class = "caption">Expression levels for this cluster and
				its associated genes.</p>
				<?
				
			break;
			
			case "Leaders":
			
				$this->set_related();
				$this->show_plot($this->Leaders);
				$_REQUEST['showRelated'] = 1;
			
				?>
				<p class = "caption">Expression levels for this cluster and
				its leaders.</p>
				<?
				
			break;
			
			case "Followers":
			
				$this->set_related();
				$this->show_plot($this->Followers);
				$_REQUEST['showRelated'] = 1;
			
				?>
				<p class = "caption">Expression levels for this cluster and
				its followers.</p>
				<?
				
			break;
			
			case "Children":
			
				$this->set_related();
				$this->show_plot($this->Children);
				$_REQUEST['showRelated'] = 1;
			
				?>
				<p class = "caption">Expression levels for this cluster and
				its children.</p>
				<?
				
			break;
		
			case "Single Cluster":
			default:
			
				$this->show_plot();
			
				?>
				<p class = "caption">Expression levels for only this cluster.
				</p>
				<?
				
			break;
		}
		
		?>
		
		<table align = "center">
			<tr>
				<td class = "formlabel">
					Plots:
				</td>
				<td>
					<input type = "submit" name = "subaction" 
						value = "Single Cluster" />
				</td>
				<td>
					<input type = "submit" name = "subaction" 
						value = "Genes" />
				</td>
				<td>
					<input type = "submit" name = "subaction" 
						value = "Leaders" />
				</td>
				<td>
					<input type = "submit" name = "subaction" 
						value = "Followers" />
				</td>
				<? //NOTE:  yet another thing to be changed if we ever decide
			   	   // to allow Rank 0 clusters ...
			   	   if($this->Rank > 1): ?>
				<td>
					<input type = "submit" name = "subaction" 
						value = "Children" />
				</td>
				<? endif; //see NOTE above
				?>
			</tr>
		</table>
		
		<?
			  
		return;
	
	}//end function show_graphics
	
	function show_related()
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
	
		$this->set_related();
						   
		$Gene = new GeneViewable();
		$Cluster = new ClusterViewable();
		
		?>
		
		<table align = "center" cellpadding = "10">
			<tr>
				<td rowspan = "3">
					<p class = "toplabel">Genes</p>
					<? $Gene->show_as_related($this->Genes); ?>
				</td>
				<td>
					<p class = "toplabel">Leaders</p>
					<? $Cluster->show_as_related($this->Leaders); ?>
				</td>
			</tr>
			<tr>
				<td>
					<p class = "toplabel">Followers</p>
					<? $Cluster->show_as_related($this->Followers); ?>
				</td>
			</tr>
			<? //NOTE:  yet another thing to be changed if we ever decide
			   // to allow Rank 0 clusters ...
			   if($this->Rank > 1): ?>
			<tr>
				<td>
					<p class = "toplabel">Children</p>
					<? $Cluster->show_as_related($this->Children); ?>
				</td>
			</tr>
			<? endif; //see NOTE above
			?>
		</table>
		
		<?
						  
		return;
	
	}//end function show_related
	
	function show_as_related($Clusters)
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
	
		if(count($Clusters))
		{
			?>
			
			<table border = "1">
			
				<tr>
					<th>
						Id
					</th>
					<th>
						Rank
					</th>
					<th>
						Members
					</th>
					<th>
						Exp 0:30
					</th>
					<th>
						Exp 2:00
					</th>
					<th>
						Exp 8:30
					</th>
				</tr>
			
			<?
				
			foreach($Clusters as $Cluster)
			{
				$href = $this->my_href($Cluster);
				
				?>
				
				<tr class = "formvalue">
					<td>
						<a href = "<? echo $href; ?>">
						<? echo $Cluster->Id; ?></a>
					</td>
					<td>
						<a href = "<? echo $href; ?>">
						<? echo $Cluster->Rank; ?></a>
					</td>
					<td><? echo $Cluster->Members; ?></td>
					<td><? echo number_format($Cluster->Exp1, 3); ?></td>
					<td><? echo number_format($Cluster->Exp2, 3); ?></td>
					<td><? echo number_format($Cluster->Exp3, 3); ?></td>
				</tr>
				
				<?
			}
			
			?>
				
			</table>
			
			<?
			
		}
		
		return;
	
	}//end function show_as_related
	
/* other template-derived functions */

	function title_string()
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
	
		return $this->IsDefault ? $_REQUEST['action'] :
			"Cluster Id $this->Id, Rank $this->Rank";
	
	}//end function title_string
	
	function my_href($Cluster = NULL)
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
	
		return is_object($Cluster) ?
			"index.php?action=Cluster&Id=$Cluster->Id&Rank=$Cluster->Rank"
			: "index.php?action=Cluster&Id=$this->Id&Rank=$this->Rank";
	
	}//end function my_href

	function plot_title()
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
	
		$retn = "Cluster.Id." . $this->Id . ".Rank." . $this->Rank; 
		if(strlen($_REQUEST['subaction']))
			$retn .= 
				"." . preg_replace("/ /", "_", $_REQUEST['subaction']);
		
		return $retn;
	
	}//end function plot_title
	
	function set_related()
	{//TEMPLATE-DERIVED FUNCTION:  see DbEntity function definition.
	
		if(!$this->RelatedSet)
		{
			$this->Genes = mobq("select distinct G.*, C.Rank
							     from   Genes G, ClusterGenes C
							     where  C.ClusterId = $this->Id and 
									    C.Rank = $this->Rank and
									    G.Id = C.GeneId
							     order  by G.Id");
							   
			$this->Leaders = mobq("select distinct C.*
							       from   Clusters C, ClusterSuccessions S
								   where  S.FollowerClusterId = $this->Id 
								   			and
										  S.Rank = $this->Rank and
										  C.Id = S.LeaderClusterId and
										  C.Rank = S.Rank
							 	   order  by C.Id");
							   
			$this->Followers = mobq("select distinct C.*
							 		 from   Clusters C, 
							 		 		ClusterSuccessions S
							 		 where  S.LeaderClusterId = $this->Id
							 		 			and
											S.Rank = $this->Rank and
											C.Id = S.FollowerClusterId and
											C.Rank = S.Rank
							 		 order  by C.Id");
							   
			//NOTE:  yet another thing to be changed if we ever decide to
			// allow Rank 0 clusters ...
			if($this->Rank > 1)
			{
				$cRank = $this->Rank - 1;
				$this->Children = mobq("select distinct C.*
								  		from   Clusters C
								  		where  C.ParentId = $this->Id and
										 	   C.Rank = $cRank
								  		order  by C.Id");
			}
		}
		
		return;
		
	}//end function set_related

} /* END CLASS ClusterViewable */

?>