[Piwik-svn] r410 - in trunk: libs/open-flash-chart misc modules modules/DataTable/Filter modules/LogStats modules/LogStats/Generator modules/SmartyPlugins modules/ViewDataTable modules/Visualization plugins/Actions plugins/Provider plugins/Referers plugins/UserCountry plugins/UserSettings plugins/VisitTime plugins/VisitorInterest

svnmaster at piwik.org svnmaster at piwik.org
Wed Mar 26 02:38:48 CET 2008


Author: matt
Date: 2008-03-26 02:38:45 +0100 (Wed, 26 Mar 2008)
New Revision: 410

Added:
   trunk/modules/LogStats/Generator/
   trunk/modules/LogStats/Generator/LogStats.php
   trunk/modules/LogStats/Generator/Visit.php
   trunk/modules/Visualization/Sparkline.php
Modified:
   trunk/libs/open-flash-chart/open-flash-chart.swf
   trunk/misc/api_example_marketing.php
   trunk/modules/Access.php
   trunk/modules/Common.php
   trunk/modules/Controller.php
   trunk/modules/DataTable/Filter/PatternRecursive.php
   trunk/modules/LogStats.php
   trunk/modules/LogStats/Generator.php
   trunk/modules/LogStats/Visit.php
   trunk/modules/SmartyPlugins/function.hiddenurl.php
   trunk/modules/SmartyPlugins/function.postEvent.php
   trunk/modules/SmartyPlugins/function.url.php
   trunk/modules/SmartyPlugins/modifier.sumtime.php
   trunk/modules/SmartyPlugins/modifier.translate.php
   trunk/modules/SmartyPlugins/modifier.urlRewriteAdminView.php
   trunk/modules/SmartyPlugins/modifier.urlRewriteBasicView.php
   trunk/modules/SmartyPlugins/modifier.urlRewriteWithParameters.php
   trunk/modules/ViewDataTable.php
   trunk/modules/ViewDataTable/Cloud.php
   trunk/modules/ViewDataTable/GenerateGraphData.php
   trunk/modules/ViewDataTable/Graph.php
   trunk/modules/ViewDataTable/Html.php
   trunk/modules/ViewDataTable/Sparkline.php
   trunk/modules/Visualization/Chart.php
   trunk/modules/Visualization/ChartEvolution.php
   trunk/modules/Visualization/ChartPie.php
   trunk/modules/Visualization/ChartVerticalBar.php
   trunk/modules/Visualization/Cloud.php
   trunk/modules/Visualization/OpenFlashChart.php
   trunk/plugins/Actions/Controller.php
   trunk/plugins/Provider/Controller.php
   trunk/plugins/Referers/Controller.php
   trunk/plugins/UserCountry/UserCountry.php
   trunk/plugins/UserSettings/Controller.php
   trunk/plugins/VisitTime/Controller.php
   trunk/plugins/VisitorInterest/Controller.php
Log:
- refs #33 work in progress soon finished
- updated OFC lib and added link to stats on EVOLUTION GRAPH
- changed api of Piwik_ViewDataTable::factory

Modified: trunk/libs/open-flash-chart/open-flash-chart.swf
===================================================================
(Binary files differ)

Modified: trunk/misc/api_example_marketing.php
===================================================================
--- trunk/misc/api_example_marketing.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/misc/api_example_marketing.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -3,6 +3,7 @@
 </p><p>This report is generated in order to see how <a href='http://piwik.org'>Piwik.org</a> visitors are interested in Piwik, which we determine by the ratio of visitors that look the <a href='http://piwik.org/demo'>online demo</a>.</p>
 <?php
 $visitsDemo = file_get_contents('http://piwik.org/demo/?module=API&method=Actions.getActions&idSite=1&period=day&date=previous7&format=php&filter_column=label&filter_pattern=demo');
+//$visitsDemo = file_get_contents('http://piwik.org/demo/?module=API&method=Actions.getActions&idSite=1&period=day&date=previous7&format=php&filter_column=label&filter_pattern=demo');
 $visitsAll = file_get_contents('http://piwik.org/demo/?module=API&method=VisitsSummary.getUniqueVisitors&idSite=1&period=day&date=previous7&format=php');
 
 $visitsDemo = unserialize($visitsDemo);

Modified: trunk/modules/Access.php
===================================================================
--- trunk/modules/Access.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/Access.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -11,6 +11,7 @@
  */
 
 require_once 'SitesManager/API.php';
+
 /**
  * Class to handle User Access.
  * In Piwik there are mainly 4 access levels
@@ -30,8 +31,6 @@
  * There is only one Super User ; he has ADMIN access to all the websites
  * and he only can change the main configuration settings.
  *
- * TODO This class should be in the Login plugin
- * This class should instead be an interface to be implemented by a Login plugin for other types of authentication (ldpa,openid,etc.)
  * @package Piwik
  */
 

Modified: trunk/modules/Common.php
===================================================================
--- trunk/modules/Common.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/Common.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -239,7 +239,6 @@
 	}
 
 	/**
-	 * get the visitor os
 	 *
 	 * @param string $userAgent
 	 * @param array $osList
@@ -263,7 +262,6 @@
 	}
 
 	/**
-	 * get visitor browser
 	 *
 	 * @param string $userAgent
 	 * @return array array(  'name' 			=> '',

Modified: trunk/modules/Controller.php
===================================================================
--- trunk/modules/Controller.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/Controller.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -52,7 +52,7 @@
 	protected function getLastUnitGraph($currentModuleName, $currentControllerAction, $apiMethod)
 	{
 		require_once "ViewDataTable/Graph.php";
-		$view = Piwik_ViewDataTable::factory(null, 'graphEvolution');
+		$view = Piwik_ViewDataTable::factory('graphEvolution');
 		$view->init( $currentModuleName, $currentControllerAction, $apiMethod );
 		
 		// if the date is not yet a nicely formatted date range ie. YYYY-MM-DD,YYYY-MM-DD we build it

Modified: trunk/modules/DataTable/Filter/PatternRecursive.php
===================================================================
--- trunk/modules/DataTable/Filter/PatternRecursive.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/DataTable/Filter/PatternRecursive.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -41,7 +41,7 @@
 			$table = $this->table;
 		}
 		$rows = $table->getRows();
-						
+		
 		foreach($rows as $key => $row)
 		{
 			// A row is deleted if

Added: trunk/modules/LogStats/Generator/LogStats.php
===================================================================
--- trunk/modules/LogStats/Generator/LogStats.php	                        (rev 0)
+++ trunk/modules/LogStats/Generator/LogStats.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -0,0 +1,53 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ * 
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id: Generator.php 404 2008-03-23 01:09:59Z matt $
+ * 
+ * @package Piwik_LogStats
+ */
+
+
+/**
+ * Fake Piwik_LogStats that:
+ * - overwrite the sendHeader method so that no headers are sent.
+ * - doesn't print the 1pixel transparent GIF at the end of the visit process
+ * - overwrite the logstat_visit object to use so we use our own logstats_visit @see Piwik_LogStats_Generator_Visit
+ * 
+ * @package Piwik_LogStats
+ * @subpackage Piwik_LogStats_Generator
+ */
+class Piwik_LogStats_Generator_LogStats extends Piwik_LogStats
+{
+	/**
+	 * Does nothing instead of sending headers
+	 *
+	 * @return void
+	 */
+	protected function sendHeader($header)
+	{
+	//	header($header);
+	}
+	
+	/**
+	 * Does nothing instead of displaying a 1x1 transparent pixel GIF
+	 *
+	 * @return void
+	 */
+	protected function endProcess()
+	{
+	}
+	
+	/**
+	 * Returns our 'generator home made' Piwik_LogStats_Generator_Visit object.
+	 *
+	 * @return Piwik_LogStats_Generator_Visit
+	 */
+	protected function getNewVisitObject()
+	{
+		return new Piwik_LogStats_Generator_Visit($this->db);
+	}
+	
+}
\ No newline at end of file

Added: trunk/modules/LogStats/Generator/Visit.php
===================================================================
--- trunk/modules/LogStats/Generator/Visit.php	                        (rev 0)
+++ trunk/modules/LogStats/Generator/Visit.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -0,0 +1,51 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ * 
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id: Generator.php 404 2008-03-23 01:09:59Z matt $
+ * 
+ * @package Piwik_LogStats
+ */
+
+
+/**
+ * Fake Piwik_LogStats_Visit class that overwrite all the Time related method to be able
+ * to setup a given timestamp for the generated visitor and actions.
+ * 
+ * 
+ * @package Piwik_LogStats
+ * @subpackage Piwik_LogStats_Generator
+ */
+class Piwik_LogStats_Generator_Visit extends Piwik_LogStats_Visit
+{
+	static protected $timestampToUse;
+	
+	function __construct( $db )
+	{
+		parent::__construct($db);
+	}
+	
+	static public function setTimestampToUse($time)
+	{
+		self::$timestampToUse = $time;
+	}
+	protected function getCurrentDate( $format = "Y-m-d")
+	{
+		return date($format, $this->getCurrentTimestamp() );
+	}
+	
+	protected function getCurrentTimestamp()
+	{
+		self::$timestampToUse = max(@$this->visitorInfo['visit_last_action_time'],self::$timestampToUse);
+		self::$timestampToUse += mt_rand(4,1840);
+		return self::$timestampToUse;
+	}
+		
+	protected function getDatetimeFromTimestamp($timestamp)
+	{
+		return date("Y-m-d H:i:s",$timestamp);
+	}
+	
+}

Modified: trunk/modules/LogStats/Generator.php
===================================================================
--- trunk/modules/LogStats/Generator.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/LogStats/Generator.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -34,6 +34,7 @@
  * 
  *  
  * @package Piwik_LogStats
+ * @subpackage Piwik_LogStats_Generator
  * 
  * 											"Le Generator, il est trop Fort!"
  * 											- Random fan
@@ -41,21 +42,76 @@
 
 class Piwik_LogStats_Generator
 {
+	/**
+	 * GET parameters array of values to be used for the current visit
+	 *
+	 * @var array ('res' => '1024x768', 'urlref' => 'http://google.com/search?q=piwik', ...)
+	 */
 	protected $currentget	=	array();
+	
+	/**
+	 * Array of all the potential values for the visit parameters
+	 * Values of 'resolution', 'urlref', etc. will be randomly read from this array
+	 *
+	 * @var array ( 
+	 * 			'res' => array('1024x768','800x600'), 
+	 * 			'urlref' => array('google.com','intel.com','amazon.com'),
+	 * 			....)
+	 */
 	protected $allget		=	array();
+	
+	/**
+	 * See @see setMaximumUrlDepth
+	 *
+	 * @var int
+	 */
 	protected $maximumUrlDepth = 1;
+	
+	/**
+	 * Unix timestamp to use for the generated visitor 
+	 *
+	 * @var int Unix timestamp
+	 */
 	protected $timestampToUse;
 	
-	public $profiling 	= true;
+	/**
+	 * See @see disableProfiler()
+	 * The profiler is enabled by default
+	 *
+	 * @var bool
+	 */
+	protected $profiling 	= true;
+	
+	/**
+	 * If set to true, this will TRUNCATE the profiling tables at every new generated visit 
+	 * @see initProfiler()
+	 * 
+	 * @var bool
+	 */
 	public $reinitProfilingAtEveryRequest = true;
 	
-	//we could make this variable dynamic so that a visitor can make hit on several hosts and 
-	// only the good ones are kept
+	/**
+	 * Hostname used to prefix all the generated URLs
+	 * we could make this variable dynamic so that a visitor can make hit on several hosts and
+	 * only the good ones should be kept (feature not yet implemented in piwik)
+	 * 
+	 * @var string
+	 */
 	public $host = 'http://localhost';
 	
+	/**
+	 * IdSite to generate visits for (@see setIdSite())
+	 *
+	 * @var int
+	 */
 	public $idSite = 1;
 	
-	
+	/**
+	 * Overwrite the global GET/POST/COOKIE variables and set the fake ones @see setFakeRequest()
+	 * Reads the configuration file but disables write to this file
+	 * Creates the database object & enable profiling by default (@see disableProfiler())
+	 *
+	 */
 	public function __construct()
 	{
 		$_COOKIE = $_GET = $_REQUEST = $_POST = array();
@@ -89,7 +145,7 @@
 	
 	/**
 	 * Set the timestamp to use as the starting time for the visitors times
-	 * To be set with every day value
+	 * You have to call this method for every day you want to generate data
 	 * 
 	 * @param int Unix timestamp
 	 */
@@ -101,7 +157,7 @@
 	/**
 	 * Returns the timestamp to be used as the visitor timestamp
 	 * 
-	 * @return int
+	 * @return int Unix timestamp
 	 */
 	public function getTimestampToUse()
 	{
@@ -120,12 +176,14 @@
 	}
 	
 	/**
-	 * Add a parameter to the GET global array
-	 * We set an array value to the GET global array when we want to random select
-	 * a value for a given name. 
+	 * Add a value to the GET global array.
+	 * The generator script will then randomly read a value from this array.
 	 * 
+	 * For example, $name = 'res' $aValue = '1024x768' 
+	 * 
 	 * @param string Name of the parameter _GET[$name]
 	 * @param array|mixed Value of the parameter
+	 * @return void
 	 */
 	protected function addParam( $name, $aValue)
 	{
@@ -141,7 +199,10 @@
 	}
 	
 	/**
-	 * TRUNCATE all logs related tables to start a fresh logging database
+	 * TRUNCATE all logs related tables to start a fresh logging database.
+	 * Be careful, any data deleted this way is deleted forever
+	 * 
+	 * @return void
 	 */
 	public function emptyAllLogTables()
 	{
@@ -161,8 +222,10 @@
 	}
 	
 	/**
-	 * This marks the end of the Generator script 
-	 * and calls the Profiler output if the profiler is enabled
+	 * This is called at the end of the Generator script.
+	 * Calls the Profiler output if the profiler is enabled.
+	 * 
+	 * @return void
 	 */
 	public function end()
 	{
@@ -178,21 +241,20 @@
 	 * - init the random generator
 	 * - setup the different possible values for parameters such as 'resolution',
 	 * 		'color', 'hour', 'minute', etc.
-	 * - load and setup values for the other parameters
+	 * - load from DataFiles and setup values for the other parameters such as UserAgent, Referers, AcceptedLanguages, etc.
+	 *  @see /misc/generateVisitsData/
+	 * 
+	 * @return void
 	 */
 	public function init()
 	{
 		Piwik::createLogObject();
-		if($this->profiling)
-		{
-			if($this->reinitProfilingAtEveryRequest)
-			{
-				$db = Zend_Registry::get('db');
-				$all = $db->query('TRUNCATE TABLE '.Piwik::prefixTable('log_profiling').'' );
-			}
-		}
 		
-		// seed with microseconds
+		$this->initProfiler();
+		
+		/*
+		 * Init the random number generator 
+		 */ 
 		function make_seed()
 		{
 		  list($usec, $sec) = explode(' ', microtime());
@@ -200,6 +262,9 @@
 		}
 		mt_srand(make_seed());
 		
+		/*
+		 * Sets values for: resolutions, colors, idSite, times
+		 */
 		$common = array(
 			'res' => array('1289x800','1024x768','800x600','564x644','200x100','50x2000',),
 			'col' => array(24,32,16),
@@ -207,13 +272,16 @@
 			'h' => range(0,23),
 			'm' => range(0,59),
 			's' => range(0,59),
-			
 		);
+		
 		foreach($common as $label => $values)
 		{
 			$this->addParam($label,$values);
 		}
 		
+		/*
+		 * Sets values for: outlinks, downloads, campaigns
+		 */
 		// we get the name of the Download/outlink variables
 		$downloadOrOutlink = array(
 						Piwik_LogStats_Config::getInstance()->LogStats['download_url_var_name'],
@@ -233,6 +301,10 @@
 		$this->addParam('piwik_vars_campaign', $campaigns);
 		$this->addParam('piwik_vars_campaign', array_fill(0,15,''));
 		
+		
+		/*
+		 * Sets values for: Referers, user agents, accepted languages
+		 */
 		// we load some real referers to be used by the generator
 		$referers = array();
 		require_once "misc/generateVisitsData/Referers.php";
@@ -251,10 +323,34 @@
 	}
 	
 	/**
+	 * If the SQL profiler is enabled and if the reinit at every request is set to true,
+	 * then we TRUNCATE the profiling information so that we only profile one visitor at a time
+	 * 
+	 * @return void
+	 */
+	protected function initProfiler()
+	{
+		/*
+		 * Inits the profiler
+		 */
+		if($this->profiling)
+		{
+			if($this->reinitProfilingAtEveryRequest)
+			{
+				$db = Zend_Registry::get('db');
+				$all = $db->query('TRUNCATE TABLE '.Piwik::prefixTable('log_profiling').'' );
+			}
+		}
+	}
+	/**
 	 * Launches the process and generates an exact number of nbVisits
 	 * For each visit, we setup the timestamp to the common timestamp
 	 * Then we generate between 1 and nbActionsMaxPerVisit actions for this visit
+	 * The generated actions will have a growing timestamp so it looks like a real visit
 	 * 
+	 * @param int The number of visits to generate
+	 * @param int The maximum number of actions to generate per visit
+	 * 
 	 * @return int The number of total actions generated
 	 */
 	public function generate( $nbVisits, $nbActionsMaxPerVisit )
@@ -282,10 +378,13 @@
 	}
 	
 	/**
-	 * Generate a new visit. Load a random value for 
-	 * all the parameters that are read by the piwik logging engine.
+	 * Generates a new visitor. 
+	 * Loads random values for all the necessary parameters (resolution, local time, referers, etc.) from the fake GET array.
+	 * Also generates a random IP.
 	 * 
-	 * We even set the _SERVER values
+	 * We change the superglobal values of HTTP_USER_AGENT, HTTP_CLIENT_IP, HTTP_ACCEPT_LANGUAGE to the generated value.
+	 * 
+	 * @return void
 	 */
 	protected function generateNewVisit()
 	{
@@ -312,9 +411,13 @@
 	
 	/**
 	 * Generates a new action for the current visitor.
-	 * We random generate some campaigns, action names, 
-	 * download or outlink clicks, etc.
+	 * We random generate some campaigns, action names, download or outlink clicks, etc.
+	 * We generate a new Referer, that would be read in the case the visit last page is older than 30 minutes.
 	 * 
+	 * This function tries to generate actions that use the features of Piwik (campaigns, downloads, outlinks, action_name set in the JS tag, etc.)
+	 * 
+	 * @return void
+	 * 
 	 */
 	protected function generateActionVisit()
 	{		
@@ -390,6 +493,10 @@
 	/**
 	 * Returns a random URL using the $host as the URL host.
 	 * Depth level depends on @see setMaximumUrlDepth()
+	 * 
+	 * @param string Hostname of the URL to generate, eg. http://example.com/
+	 * 
+	 * @return string The generated URL
 	 */
 	protected function getRandomUrlFromHost( $host )
 	{
@@ -406,14 +513,13 @@
 	}
 	
 	/**
-	 * Generates a random string from minLength to maxLenght 
-	 * using a specified set of characters
+	 * Generates a random string from minLength to maxLength using a specified set of characters
 	 * 
-	 * From php.net and then badly hacked by myself
+	 * Taken from php.net and then badly hacked by some unknown monkey
 	 * 
-	 * @param int Maximum length
-	 * @param int Minimum length
-	 * @param string Characters set to use, ALL or lower or upper or numeric or ALPHA or ALNUM
+	 * @param int (optional) Maximum length of the string to generate
+	 * @param int (optional) Minimum length of the string to generate
+	 * @param string (optional) Characters set to use, 'ALL' or 'lower' or 'upper' or 'numeric' or 'ALPHA' or 'ALNUM'
 	 * 
 	 * @return string The generated random string
 	 */
@@ -480,7 +586,12 @@
 	}
 
 	/**
-	 * Set the _GET and _REQUEST superglobal to the current generated array of values
+	 * Sets the _GET and _REQUEST superglobal to the current generated array of values.
+	 * @see setCurrentRequest()
+	 * This method is called once the current action parameters array has been generated from 
+	 * the global parameters array
+	 * 
+	 * @return void
 	 */
 	protected function setFakeRequest()
 	{
@@ -488,7 +599,7 @@
 	}
 	
 	/**
-	 * Set a value in the current request
+	 * Sets a value in the current action request array.
 	 * 
 	 * @param string Name of the parameter to set
 	 * @param string Value of the parameter
@@ -499,11 +610,13 @@
 	}
 	
 	/**
-	 * Returns a value for the given parameter $name
+	 * Returns a value for the given parameter $name read randomly from the global parameter array.
+	 * @see init()
 	 * 
+	 * @param string Name of the parameter value to randomly load and return
+	 * @return mixed Random value for the parameter named $name
 	 * @throws Exception if the parameter asked for has never been set
 	 * 
-	 * @return mixed Random value for the parameter named $name
 	 */
 	protected function getRandom( $name )
 	{		
@@ -521,7 +634,8 @@
 
 	/**
 	 * Returns either 0 or 1
-	 * @return int
+	 * 
+	 * @return int 0 or 1
 	 */	
 	protected function getRandom01()
 	{
@@ -530,72 +644,20 @@
 	
 	/**
 	 * Saves the visit 
-	 * - set the fake request 
+	 * - replaces GET and REQUEST by the fake generated request
 	 * - load the LogStats class and call the method to launch the recording
+	 * 
+	 * This will save the visit in the database
+	 * 
+	 * @return void
 	 */
 	protected function saveVisit()
 	{
 		$this->setFakeRequest();
-		$process = new Piwik_LogStats_Generator_Main;
-		$process->main('Piwik_LogStats_Generator_Visit');
+		$process = new Piwik_LogStats_Generator_LogStats;
+		$process->main();
 	}
 	
 }
-
-/**
- * Fake Piwik_LogStats that simply overwrite the sendHeader method 
- * so that no headers are sent
- * 
- * @package Piwik_LogStats
- */
-class Piwik_LogStats_Generator_Main extends Piwik_LogStats
-{
-	protected function sendHeader($header)
-	{
-	//	header($header);
-	}
-	
-	protected function endProcess()
-	{
-	}
-}
-
-/**
- * Fake Piwik_LogStats_Visit class that overwrite all the Time related method to be able
- * to setup a given timestamp for the generated visitor and actions.
- * 
- * 
- * @package Piwik_LogStats
- */
-class Piwik_LogStats_Generator_Visit extends Piwik_LogStats_Visit
-{
-	static protected $timestampToUse;
-	
-	function __construct( $db )
-	{
-		parent::__construct($db);
-	}
-	
-	static public function setTimestampToUse($time)
-	{
-		self::$timestampToUse = $time;
-	}
-	protected function getCurrentDate( $format = "Y-m-d")
-	{
-		return date($format, $this->getCurrentTimestamp() );
-	}
-	
-	protected function getCurrentTimestamp()
-	{
-		self::$timestampToUse = max(@$this->visitorInfo['visit_last_action_time'],self::$timestampToUse);
-		self::$timestampToUse += mt_rand(4,1840);
-		return self::$timestampToUse;
-	}
-		
-	protected function getDatetimeFromTimestamp($timestamp)
-	{
-		return date("Y-m-d H:i:s",$timestamp);
-	}
-	
-}
-
+require_once "Generator/LogStats.php";
+require_once "Generator/Visit.php";

Modified: trunk/modules/LogStats/Visit.php
===================================================================
--- trunk/modules/LogStats/Visit.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/LogStats/Visit.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -17,8 +17,8 @@
  * - If a visit is KNOWN then we update the visit row in the log_visit table, updating the number of pages
  * views, time spent, etc.
  * 
- * Whether a visit is NEW or KNOWN we also save the action in the DB. One request to the piwik.php script
- * is associated to one action.
+ * Whether a visit is NEW or KNOWN we also save the action in the DB. 
+ * One request to the piwik.php script is associated to one action.
  * 
  * @package Piwik_LogStats
  */

Modified: trunk/modules/LogStats.php
===================================================================
--- trunk/modules/LogStats.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/LogStats.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -46,11 +46,11 @@
  */
 class Piwik_LogStats
 {	
-	private $stateValid;
+	protected $stateValid;
 	
-	private $urlToRedirect;
+	protected $urlToRedirect;
 	
-	private $db = null;
+	protected $db = null;
 	
 	const STATE_NOTHING_TO_NOTICE = 1;
 	const STATE_TO_REDIRECT_URL = 2;
@@ -159,17 +159,28 @@
 		$this->stateValid = $value;
 	}
 	
+	/**
+	 * Returns the LogStats_Visit object.
+	 * This method can be overwritten so that we use a different LogStats_Visit object
+	 *
+	 * @return LogStats_Visit
+	 */
+	protected function getNewVisitObject()
+	{
+		return new Piwik_LogStats_Visit($this->db);
+	}
+	
 	// main algorithm 
 	// => input : variables filtered
 	// => action : read cookie, read database, database logging, cookie writing
-	function main( $class_LogStats_Visit = "Piwik_LogStats_Visit")
+	function main()
 	{
 		$this->initProcess();
 		
 		if( $this->processVisit() )
 		{
 			$this->connectDatabase();
-			$visit = new $class_LogStats_Visit( $this->db );
+			$visit = $this->getNewVisitObject();
 			$visit->handle();
 		}
 		$this->endProcess();

Modified: trunk/modules/SmartyPlugins/function.hiddenurl.php
===================================================================
--- trunk/modules/SmartyPlugins/function.hiddenurl.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/SmartyPlugins/function.hiddenurl.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -6,7 +6,7 @@
  * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
  * @version $Id: function.url.php 168 2008-01-14 05:26:43Z matt $
  * 
- * @package Piwik_Visualization
+ * @package SmartyPlugins
  */
 
 require_once "Url.php";
@@ -17,6 +17,7 @@
  * Useful when using GET forms because we need to print the current parameters 
  * in hidden input so they are to the next URL after the form is submitted.
  *
+ * 
  * Examples:
  * <pre>
  * {hiddenurl module="API"} with a URL 'index.php?action=test&module=Home' will output
@@ -24,6 +25,8 @@
  *  <input type=hidden name=module value=API>
  * </pre>
  * 
+ * Set a value to null if you want this value not to be passed in the submitted form.
+ * 
  * @param	array
  * @param	Smarty
  * @return	string

Modified: trunk/modules/SmartyPlugins/function.postEvent.php
===================================================================
--- trunk/modules/SmartyPlugins/function.postEvent.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/SmartyPlugins/function.postEvent.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -6,12 +6,27 @@
  * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
  * @version $Id: function.url.php 168 2008-01-14 05:26:43Z matt $
  * 
- * @package Piwik_Visualization
+ * @package SmartyPlugins
  */
 
 require_once "Url.php";
 
 /**
+ * Posts an event from a smarty template. This event can then be hooked by another plugin.
+ * The even will be posted along with a string value that plugins can edit.
+ * This is useful to allow other plugins to add content at a specific entry point in the template.
+ * This string will be returned by the smarty function.
+ * 
+ * Examples:
+ * <pre>
+ * 		{postEvent name="template_footerUserCountry"}
+ * </pre>
+ * 
+ * Plugins can then hook on this event by using the Piwik_AddAction function: 
+ * 	Piwik_AddAction('template_footerUserCountry', 'functionToHookOnThisEvent');
+ * 
+ * @param string $name The name of the event
+ * @return string The string eventually modified by the plugins listening to this event
  */
 function smarty_function_postEvent($params, &$smarty)
 {

Modified: trunk/modules/SmartyPlugins/function.url.php
===================================================================
--- trunk/modules/SmartyPlugins/function.url.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/SmartyPlugins/function.url.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -6,13 +6,14 @@
  * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
  * @version $Id$
  * 
- * @package Piwik_Visualization
+ * @package SmartyPlugins
  */
 
 require_once "Url.php";
 
 /**
- * Smarty {url} function plugin
+ * Smarty {url} function plugin.
+ * Generates a piwik URL with the specified parameters modified.
  *
  * Examples:
  * <pre>
@@ -21,9 +22,8 @@
  * </pre>
  * 
  * @see Piwik_Url::getCurrentQueryStringWithParametersModified()
- * @param	array
- * @param	Smarty
- * @return	string
+ * @param $name=$value of the parameters to modify in the generated URL
+ * @return	string Something like index.php?module=X&action=Y 
  */
 function smarty_function_url($params, &$smarty)
 {

Modified: trunk/modules/SmartyPlugins/modifier.sumtime.php
===================================================================
--- trunk/modules/SmartyPlugins/modifier.sumtime.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/SmartyPlugins/modifier.sumtime.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -6,17 +6,23 @@
  * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
  * @version $Id$
  * 
- * @package Piwik_Visualization
+ * @package SmartyPlugins
  */
 
 /**
- * Returns a string stating the number of days and hours from a number of seconds
+ * Returns a string that displays the number of days and hours from a number of seconds
  * 
- * Example
+ * How to use:
+ * {4200|sumtime} will display '1h 10min'
+ * 
+ * Examples:
  * - 10 gives "10s"
  * - 4200 gives "1h 10min"
  * - 86400 gives "1 day"
  * - 90600 gives "1 day 1h" (it is exactly 1day 1h 10min but we truncate)
+ * 
+ * @return string
+ * 
  */
 function smarty_modifier_sumtime($string)
 {

Modified: trunk/modules/SmartyPlugins/modifier.translate.php
===================================================================
--- trunk/modules/SmartyPlugins/modifier.translate.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/SmartyPlugins/modifier.translate.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -6,17 +6,17 @@
  * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
  * @version $Id: modifier.sumtime.php 168 2008-01-14 05:26:43Z matt $
  * 
- * @package Piwik_Visualization
+ * @package SmartyPlugins
  */
 
 /**
- * Translates a string in the currently selected language in Piwik.
+ * Read the translation string from the given index (read form the selected language in Piwik).
  * The translations strings are located either in /lang/xx.php or within the plugin lang directory.
  * 
  * Example:
+ *  {'General_Unknown'|translate} will be translated as 'Unknown' (see the entry in /lang/en.php)
  * 
- * {'General_Unknown'|translate} will be translated as 'Unknown' (see the entry in /lang/en.php)
- * 
+ * @return string The translated string
  */
 function smarty_modifier_translate($string, $aValues = null)
 {

Modified: trunk/modules/SmartyPlugins/modifier.urlRewriteAdminView.php
===================================================================
--- trunk/modules/SmartyPlugins/modifier.urlRewriteAdminView.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/SmartyPlugins/modifier.urlRewriteAdminView.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -6,10 +6,13 @@
  * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
  * @version $Id: modifier.sumtime.php 168 2008-01-14 05:26:43Z matt $
  * 
- * @package Piwik_Visualization
+ * @package SmartyPlugins
  */
 
 /**
+ * Rewrites the given URL so that it looks like an Admin URL.
+ * 
+ * @return string
  */
 function smarty_modifier_urlRewriteAdminView($parameters)
 {

Modified: trunk/modules/SmartyPlugins/modifier.urlRewriteBasicView.php
===================================================================
--- trunk/modules/SmartyPlugins/modifier.urlRewriteBasicView.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/SmartyPlugins/modifier.urlRewriteBasicView.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -6,10 +6,14 @@
  * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
  * @version $Id: modifier.sumtime.php 168 2008-01-14 05:26:43Z matt $
  * 
- * @package Piwik_Visualization
+ * @package SmartyPlugins
  */
 
 /**
+ * Rewrites the given URL so that it looks like a URL that can be loaded directly.
+ * Useful for users who don't handle javascript / ajax, they can still use piwik with these rewritten URLs.
+ * 
+ * @return string
  */
 function smarty_modifier_urlRewriteBasicView($parameters)
 {

Modified: trunk/modules/SmartyPlugins/modifier.urlRewriteWithParameters.php
===================================================================
--- trunk/modules/SmartyPlugins/modifier.urlRewriteWithParameters.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/SmartyPlugins/modifier.urlRewriteWithParameters.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -6,10 +6,14 @@
  * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
  * @version $Id: modifier.sumtime.php 168 2008-01-14 05:26:43Z matt $
  * 
- * @package Piwik_Visualization
+ * @package SmartyPlugins
  */
 
 /**
+ * Rewrites the given URL and modify the given parameters.
+ * @see Piwik_Url::getCurrentQueryStringWithParametersModified()
+ * 
+ * @return string
  */
 function smarty_modifier_urlRewriteWithParameters($parameters)
 {

Modified: trunk/modules/ViewDataTable/Cloud.php
===================================================================
--- trunk/modules/ViewDataTable/Cloud.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/ViewDataTable/Cloud.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -11,14 +11,21 @@
 
 require_once "Visualization/Cloud.php";
 
-/**
+/** 
+ * Reads the requested DataTable from the API, and prepares the data to give 
+ * to Piwik_Visualization_Cloud that will display the tag cloud (via the template cloud.tpl).
  * 
  * @package Piwik_ViewDataTable
  *
  */
 class Piwik_ViewDataTable_Cloud extends Piwik_ViewDataTable
 {
+	//TODO test this
 	protected $displayLogoInsteadOfLabel = false;
+	
+	/**
+	 * @see Piwik_ViewDataTable::init()
+	 */
 	function init($currentControllerName,
 						$currentControllerAction, 
 						$moduleNameAndMethod )
@@ -32,6 +39,10 @@
 		$this->disableExcludeLowPopulation();
 	}
 	
+	/**
+	 * @see Piwik_ViewDataTable::main()
+	 *
+	 */
 	public function main()
 	{
 		$this->setLimit( 30 );
@@ -52,18 +63,13 @@
 		
 		
 		$view = new Piwik_View($this->dataTableTemplate);
-		$view->method = $this->method;
 		
-		$view->id 			= $this->getUniqIdTable();
-		
-		
-		$view->javascriptVariablesToSet = $this->getJavascriptVariablesToSet();
-//		echo $this->dataTable; exit;
 		$words = $labelDetails = array();
 		foreach($this->dataTable->getRows() as $row)
 		{
 			$label = $row->getColumn('label');
 			$value = $row->getColumn('nb_uniq_visitors');
+			
 			// case no unique visitors
 			if($value === false)
 			{
@@ -95,7 +101,10 @@
 		$view->labelDetails = $labelDetails;
 		$view->cloudValues = $cloudValues;
 		
-		$view->showFooter = $this->showFooter;
+		$view->method = $this->method;
+		$view->id = $this->getUniqIdTable();
+		$view->javascriptVariablesToSet = $this->getJavascriptVariablesToSet();
+		$view->showFooter = $this->getShowFooter();
 		$this->view = $view;
 	}
 }

Modified: trunk/modules/ViewDataTable/GenerateGraphData.php
===================================================================
--- trunk/modules/ViewDataTable/GenerateGraphData.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/ViewDataTable/GenerateGraphData.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -10,13 +10,30 @@
  */
 
 /**
- * 
+ * Reads data from the API and prepares data to give to the renderer Piwik_Visualization_Chart.
+ * This class is used to generate the data for the FLASH charts. It is given as a parameter of the SWF file.
+ * You can set the number of elements to appear in the graph using: setGraphLimit();
+ * Example:
+ * <pre>
+ * 	function getWebsites( $fetch = false)
+ * 	{
+ * 		$view = Piwik_ViewDataTable::factory();
+ * 		$view->init( $this->pluginName, 'getWebsites', 'Referers.getWebsites', 'getUrlsFromWebsiteId' );
+ * 		$view->setColumnsToDisplay( array('label','nb_visits') );
+ *		$view->setLimit(10);
+ * 		$view->setGraphLimit(12);
+ * 		return $this->renderView($view, $fetch);
+ * 	}
+ * </pre>
+ *  
  * @package Piwik_ViewDataTable
  *
  */
 abstract class Piwik_ViewDataTable_GenerateGraphData extends Piwik_ViewDataTable
 {
-	
+	/**
+	 * @see Piwik_ViewDataTable::init()
+	 */
 	function init($currentControllerName,
 						$currentControllerAction, 
 						$moduleNameAndMethod )
@@ -25,18 +42,34 @@
 						$currentControllerAction, 
 						$moduleNameAndMethod );
 	}
-	
+	
+	/**
+	 * Number of elements to display in the graph.
+	 *
+	 * @var int
+	 */
 	protected $graphLimit = 5;
-	
+	
+	/**
+	 * Sets the number max of elements to display (number of pie slice, vertical bars, etc.)
+	 * If the data has more elements than $limit then the last part of the data will be the sum of all the remaining data.
+	 *
+	 * @param int $limit
+	 */
 	function setGraphLimit( $limit )
 	{
 		$this->graphLimit = $limit;
 	}
-	
+	/**
+	 * Returns numbers of elemnts to display in the graph
+	 *
+	 * @return int
+	 */
 	function getGraphLimit()
 	{
 		return $this->graphLimit;
-	}
+	}
+	
 	public function main()
 	{
 		if($this->mainAlreadyExecuted)
@@ -66,6 +99,11 @@
 		}
 	}
 	
+	/**
+	 * Returns a format friendly array from the dataTable 
+	 *
+	 * @return array
+	 */
 	protected function generateDataFromDataTable()
 	{
 		$this->dataTable->applyQueuedFilters();
@@ -97,6 +135,12 @@
 	}
 }
 
+/**
+ * Piwik_ViewDataTable_GenerateGraphData for the Evolution graph (eg. Last 30 days visits) using Piwik_Visualization_ChartEvolution
+ * 
+ * @package Piwik_ViewDataTable
+ *
+ */
 class Piwik_ViewDataTable_GenerateGraphData_ChartEvolution extends Piwik_ViewDataTable_GenerateGraphData
 {
 	function __construct()
@@ -109,11 +153,14 @@
 	{
 		return $this->generateDataFromDataTableArray($this->dataTable);
 	}
-}
-/**
- * 
- * @package Piwik_ViewDataTable
- *
+}
+
+
+/**
+ * Piwik_ViewDataTable_GenerateGraphData for the pie chart, using Piwik_Visualization_ChartPie
+ * 
+ * @package Piwik_ViewDataTable
+ *
  */
 class Piwik_ViewDataTable_GenerateGraphData_ChartPie extends Piwik_ViewDataTable_GenerateGraphData
 {
@@ -123,7 +170,8 @@
 		$this->view = new Piwik_Visualization_ChartPie;
 	}
 }
-/**
+/**
+ * Piwik_ViewDataTable_GenerateGraphData for the vertical bar graph, using Piwik_Visualization_ChartVerticalBar
  * 
  * @package Piwik_ViewDataTable
  *

Modified: trunk/modules/ViewDataTable/Graph.php
===================================================================
--- trunk/modules/ViewDataTable/Graph.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/ViewDataTable/Graph.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -10,6 +10,8 @@
  */
 
 /**
+ * This class generates the HTML code to embed to flash graphs in the page.
+ * It doesn't call the API but simply prints the html snippet.
  * 
  * @package Piwik_ViewDataTable
  *
@@ -20,7 +22,10 @@
 	protected $height = 250;
 	protected $graphType = 'standard';
 	
-	
+	/**
+	 * @see Piwik_ViewDataTable::init()
+	 *
+	 */
 	function init($currentControllerName,
 						$currentControllerAction, 
 						$moduleNameAndMethod )
@@ -29,8 +34,7 @@
 						$currentControllerAction, 
 						$moduleNameAndMethod );
 		$this->dataTableTemplate = 'Home/templates/graph.tpl';
-//		var_dump($currentControllerName);
-//		var_dump($currentControllerAction);
+		
 		$this->disableOffsetInformation();
 		$this->disableExcludeLowPopulation();
 		$this->disableSearchBox();
@@ -44,11 +48,20 @@
 		);
 	}
 	
+	/**
+	 * Sets parameters to modify in the future generated URL
+	 *
+	 * @param array $array array('nameParameter' => $newValue, ...)
+	 */
 	public function setParametersToModify($array)
 	{
 		$this->parametersToModify = array_merge($this->parametersToModify, $array);
 	}
 	
+	/**
+	 * @see Piwik_ViewDataTable::main()
+	 *
+	 */
 	public function main()
 	{
 		if($this->mainAlreadyExecuted)
@@ -59,28 +72,24 @@
 		
 		$view = new Piwik_View($this->dataTableTemplate);
 		$this->id = $this->getUniqIdTable();
-		$view->id = $this->id;
-		$view->method = $this->method;
 		$view->graphType = $this->graphType;
 
 		$this->parametersToModify['action'] = $this->currentControllerAction;
 		$url = Piwik_Url::getCurrentQueryStringWithParametersModified($this->parametersToModify);
 		$view->jsInvocationTag = $this->getFlashInvocationCode($url);
-//		print($url);exit;
 		$view->urlData = $url;
 		
 		$view->formId = "formEmbed".$this->id;
 		$view->codeEmbed = $this->codeEmbed;
 		
+		$view->id = $this->id;
+		$view->method = $this->method;
 		$view->javascriptVariablesToSet = $this->getJavascriptVariablesToSet();
-		$view->showFooter = $this->showFooter;
+		$view->showFooter = $this->getShowFooter();
 		$this->view = $view;
 	}
 	
-	//TODO change $use_swfobject = true
-	public function getFlashInvocationCode(
-			$url = 'libs/open-flash-chart/data-files/nodata.txt',
-			$use_swfobject = true  )
+	protected function getFlashInvocationCode( $url = 'libs/open-flash-chart/data-files/nodata.txt', $use_swfobject = true  )
 	{ 
 		$width = $this->width; 
 		$height = $this->height; 
@@ -129,7 +138,8 @@
 }
 
 /**
- * 
+ * Generates HTML embed for the Evolution graph
+ *  
  * @package Piwik_ViewDataTable
  *
  */
@@ -152,11 +162,12 @@
 						$currentControllerAction, 
 						$moduleNameAndMethod );
 		
-		$this->parametersToModify['date'] = 'last30';
+		$this->setParametersToModify(array('date' => 'last30'));
 		$this->doNotShowFooter();
 	}
 }
 /**
+ * Generates HTML embed for the Pie chart
  * 
  * @package Piwik_ViewDataTable
  *
@@ -170,6 +181,8 @@
 }
 
 /**
+ * 
+ * Generates HTML embed for the vertical bar chart
  * 
  * @package Piwik_ViewDataTable
  *

Modified: trunk/modules/ViewDataTable/Html.php
===================================================================
--- trunk/modules/ViewDataTable/Html.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/ViewDataTable/Html.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -11,15 +11,32 @@
 
 /**
  * 
+ * Outputs an AJAX Table for a given DataTable.
+ * 
+ * Reads the requested DataTable from the API.
+ * 
  * @package Piwik_ViewDataTable
  *
  */
 class Piwik_ViewDataTable_Html extends Piwik_ViewDataTable
 {
+	/**
+	 * Array of columns names to display
+	 *
+	 * @var array
+	 */
 	protected $columnsToDisplay = array();
 	
+	/**
+	 * PHP array conversion of the Piwik_DataTable 
+	 *
+	 * @var array
+	 */
 	public $arrayDataTable; // phpArray
 	
+	/**
+	 * @see Piwik_ViewDataTable::init()
+	 */
 	function init($currentControllerName,
 						$currentControllerAction, 
 						$moduleNameAndMethod,						
@@ -30,8 +47,14 @@
 						$moduleNameAndMethod,						
 						$actionToLoadTheSubTable);
 		$this->dataTableTemplate = 'Home/templates/datatable.tpl';
+		
+		$this->variablesDefault['enable_sort'] = true;
 	}
 	
+	/**
+	 * @see Piwik_ViewDataTable::main()
+	 *
+	 */
 	public function main()
 	{
 		if($this->mainAlreadyExecuted)
@@ -54,7 +77,6 @@
 		
 		$view = new Piwik_View($this->dataTableTemplate);
 		
-		$view->id 			= $this->getUniqIdTable();
 		
 		// We get the PHP array converted from the DataTable
 		$phpArray = $this->getPHPArrayFromDataTable();
@@ -74,16 +96,19 @@
 		
 		$view->nbColumns = $nbColumns;
 		
+		$view->id = $this->getUniqIdTable();
 		$view->javascriptVariablesToSet = $this->getJavascriptVariablesToSet();
-		
-		$view->showFooter = $this->showFooter;
-		
+		$view->showFooter = $this->getShowFooter();
 		$this->view = $view;
 	}
 
-	protected function getPHPArrayFromDataTable( )
-	{
-		
+	/**
+	 * Returns friendly php array from the Piwik_DataTable
+	 * @see Piwik_DataTable_Renderer_Php
+	 * @return array
+	 */
+	protected function getPHPArrayFromDataTable()
+	{		
 		$renderer = Piwik_DataTable_Renderer::factory('php');
 		$renderer->setTable($this->dataTable);
 		$renderer->setSerialize( false );
@@ -91,15 +116,27 @@
 		// but conserving the original datatable format, which means rows 'columns', 'details' and 'idsubdatatable'
 		$phpArray = $renderer->originalRender();
 		return $phpArray;
-	}
-
+	}	
 	
-	
-	public function setColumnsToDisplay( $arrayIds)
+	/**
+	 * Sets the columns that will be displayed in the HTML output
+	 * By default all columns are displayed ($columnsNames = array() will display all columns)
+	 * 
+	 * @param array $columnsNames Array of column names eg. array('nb_visits','nb_hits')
+	 */
+	public function setColumnsToDisplay( $columnsNames)
 	{
-		$this->columnsToDisplay = $arrayIds;
+		$this->columnsToDisplay = $columnsNames;
 	}
 	
+	/**
+	 * Returns array(
+	 * 				array('id' => 1, 'name' => 'nb_visits'),
+	 * 				array('id' => 3, 'name' => 'nb_uniq_visitors'),
+	 *
+	 * @param array PHP array conversion of the data table
+	 * @return array
+	 */
 	protected function getColumnsToDisplay($phpArray)
 	{
 		$dataTableColumns = array();
@@ -119,6 +156,13 @@
 		return $dataTableColumns;
 	}
 
+	/**
+	 * Returns true if the given column (id = $idColumn or name = $nameColumn) is set to be displayed.
+	 *
+	 * @param int $idColumn
+	 * @param string $nameColumn
+	 * @return bool
+	 */
 	protected function isColumnToDisplay( $idColumn, $nameColumn )
 	{
 		// we return true
@@ -133,13 +177,34 @@
 		return false;
 	}
 
+	/**
+	 * Sets the columns in the HTML table as not sortable (they are not clickable) 
+	 *
+	 * @return void
+	 */
+	public function disableSort()
+	{
+		$this->variablesDefault['enable_sort'] = 'false';		
+	}
+		
+	/**
+	 * Sets the search on a table to be recursive (also searches in subtables)
+	 * Works only on Actions/Downloads/Outlinks tables.
+	 *
+	 * @return bool If the pattern for a recursive search was set in the URL
+	 */
 	public function setSearchRecursive()
 	{
 		$this->variablesDefault['search_recursive'] = true;
+		return $this->setRecursiveLoadDataTableIfSearchingForPattern();
 	}
 	
-	
-	public function setRecursiveLoadDataTableIfSearchingForPattern()
+	/**
+	 * Set the flag to load the datatable recursively so we can search on subtables as well
+	 *
+	 * @return bool if recursive search is enabled
+	 */
+	protected function setRecursiveLoadDataTableIfSearchingForPattern()
 	{
 		try{
 			$requestValue = Piwik_Common::getRequestVar('filter_column_recursive');

Modified: trunk/modules/ViewDataTable/Sparkline.php
===================================================================
--- trunk/modules/ViewDataTable/Sparkline.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/ViewDataTable/Sparkline.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -1,7 +1,29 @@
 <?php
+/**
+ * Piwik - Open source web analytics
+ * 
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id: Html.php 404 2008-03-23 01:09:59Z matt $
+ * 
+ * @package Piwik_ViewDataTable
+ */
+
+
+require_once "Visualization/Sparkline.php";
+
+/**
+ * Reads the requested DataTable from the API and prepare data for the Sparkline view.
+ * 
+ * @package Piwik_ViewDataTable
+ *
+ */
 class Piwik_ViewDataTable_Sparkline extends Piwik_ViewDataTable
 {
 	
+	/**
+	 * @see Piwik_ViewDataTable::init()
+	 */
 	function init($currentControllerName,
 						$currentControllerAction, 
 						$moduleNameAndMethod )
@@ -10,6 +32,10 @@
 						$currentControllerAction, 
 						$moduleNameAndMethod );
 	}
+	
+	/**
+	 * @see Piwik_ViewDataTable::main()
+	 */
 	public function main()
 	{
 		if($this->mainAlreadyExecuted)
@@ -21,7 +47,6 @@
 		// we load the data with the filters applied
 		$this->loadDataTableFromAPI();
 		
-//		echo $this->dataTable; exit;
 		$this->dataAvailable = $this->dataTable->getRowsCount() != 0;
 		
 		if(!$this->dataAvailable)
@@ -32,87 +57,11 @@
 		{
 			$data = $this->generateDataFromDataTableArray($this->dataTable);
 			
-			$graph = new Piwik_Sparkline_Graph;
+			$graph = new Piwik_Visualization_Sparkline;
 			$graph->setData($data);
 			$graph->main();
 //			var_dump($data);exit;
 			$this->view = $graph;
 		}
 	}
-	
 }
-
-require_once 'sparkline/lib/Sparkline_Line.php';
-
-class Piwik_Sparkline_Graph
-{
-	function setData($data)
-	{
-		$this->data = $data;
-	}
-	
-	function main()
-	{
-		$data = $this->data;
-		$sparkline = new Sparkline_Line();
-		
-//		$sparkline->SetColorHtml('lineColor', '000000');
-		$sparkline->SetColor('lineColor', 22,44,74); // dark blue
-//		$sparkline->SetColor('lineColor', 0,119,204);
-		$sparkline->SetColorHtml('red', '#FF7F7F');
-		$sparkline->SetColorHtml('blue', '#55AAFF');
-		$sparkline->SetColorHtml('green', '#75BF7C');
-//		$sparkline->SetDebugLevel(DEBUG_NONE);
-//		$sparkline->SetDebugLevel(DEBUG_ERROR | DEBUG_WARNING | DEBUG_STATS | DEBUG_CALLS | DEBUG_DRAW, 'log.txt');
-		
-		$data = array_reverse($data);
-		$min = $max= $last = null;
-		$i = 0;
-		
-		foreach($this->data as $row)
-		{
-			$value = $row['value'];
-					
-			$sparkline->SetData($i, $value);
-			if(	null == $min || $value <= $min[1])
-			{
-				$min = array($i, $value);
-			}
-		
-			if(null == $max || $value >= $max[1]) 
-			{
-				$max = array($i, $value);
-			}
-		
-			$last = array($i, $value);
-			
-			$i++;			
-		}
-//		echo imagefontwidth(FONT_2);exit;
-		// set y-bound, min and max extent lines
-		//
-		$sparkline->SetYMin(0);
-//		$sparkline->SetYMax($max);
-		$sparkline->SetPadding(2); // setpadding is additive
-		$sparkline->SetPadding(0,//13,//font height 
-					3,//4 * (strlen("$last[1]")), 
-					0, //imagefontheight(FONT_2), 
-					0);
-		$font = FONT_2;
-		$sparkline->SetFeaturePoint($min[0]-1,$min[1],'red', 5);//, $min[1], TEXT_TOP,$font);
-		$sparkline->SetFeaturePoint($max[0]-1,$max[1],  'green', 5);//, $max[1], TEXT_TOP,$font);
-		$sparkline->SetFeaturePoint($last[0]-1, $last[1], 'blue',5);//, " $last[1]", TEXT_RIGHT,$font);
-		
-		$sparkline->SetLineSize(3); // for renderresampled, linesize is on virtual image
-		$sparkline->RenderResampled(100, 20, 'lineColor');
-		
-		$this->sparkline = $sparkline;
-	}
-	
-	function render()
-	{
-		$this->sparkline->Output();
-	}
-}
-
-?>
\ No newline at end of file

Modified: trunk/modules/ViewDataTable.php
===================================================================
--- trunk/modules/ViewDataTable.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/ViewDataTable.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -9,57 +9,192 @@
  * @package Piwik_ViewDataTable
  */
 
+require_once "API/Request.php";
 
-require_once "API/Request.php";
 /**
+ * This class is used to load (from the API) and customize the output of a given DataTable.
+ * The main() method will create an object Piwik_iView
+ * You can customize the dataTable using the disable* methods.
  * 
- * @package Piwik_Visualization
+ * Example:
+ * In the Controller of the plugin VisitorInterest
+ * <pre>
+ * 	function getNumberOfVisitsPerVisitDuration( $fetch = false)
+ *  {
+ * 		$view = Piwik_ViewDataTable::factory( 'cloud' );
+ * 		$view->init( $this->pluginName,  __FUNCTION__, 'VisitorInterest.getNumberOfVisitsPerVisitDuration' );
+ * 		$view->setColumnsToDisplay( array('label','nb_visits') );
+ * 		$view->disableSort();
+ * 		$view->disableExcludeLowPopulation();
+ * 		$view->disableOffsetInformation();
+ * 
+ *		return $this->renderView($view, $fetch);
+ * 	} 
+ * </pre>
+ * 
+ * @see factory() for all the available output (cloud tags, html table, pie chart, vertical bar chart)
+ * @package Piwik_ViewDataTable
  *
  */
 
 abstract class Piwik_ViewDataTable
 {
+	/**
+	 * Template file that will be loaded for this view.
+	 * Usually set in the Piwik_ViewDataTable_*
+	 *
+	 * @var string eg. 'Home/templates/cloud.tpl'
+	 */
 	protected $dataTableTemplate = null;
 	
+	/**
+	 * Flag used to make sure the main() is only executed once
+	 *
+	 * @var bool
+	 */
 	protected $mainAlreadyExecuted = false;
 	
+	/**
+	 * Defines if we display the search box under the table
+	 * 
+	 * @see disableSearchBox()
+	 * @see getSearchBox()
+	 *
+	 * @var bool
+	 */
 	protected $JSsearchBox 				= true;
+	
+	/**
+	 * Defines if we display the "X-Y of Z" under the table
+	 * 
+	 * @see disableOffsetInformation()
+	 * @see getOffsetInformation()
+	 *
+	 * @var bool
+	 */
 	protected $JSoffsetInformation 		= true;
+	
+	/**
+	 * Defines if we display the "Include all population" link under the table
+	 * 
+	 * @see disableExcludeLowPopulation()
+	 * @see getExcludeLowPopulation() 
+	 *
+	 * @var bool
+	 */
 	protected $JSexcludeLowPopulation 	= true;
-	protected $JSsortEnabled 			= true;
+	
+	/**
+	 * Defines if we include the footer after the dataTable output.
+	 * The footer contains all the extra features like the search box, the links Next/Previous, the icons to export in several formats, etc.
+	 * Not showing the footer is useful for example when you want to only display a graph without anything else.
+	 * 
+	 * @see doNotShowFooter()
+	 * @see getShowFooter() 
+	 *
+	 * @var bool
+	 */
 	protected $showFooter				= true;
 	
+	/**
+	 * Contains the values set for the parameters
+	 * @see getJavascriptVariablesToSet()
+	 *
+	 * @var array
+	 */
+	protected $variablesDefault = array();
 	
+	/**
+	 * If the current dataTable refers to a subDataTable (eg. keywordsBySearchEngineId for id=X) this variable is set to the Id
+	 *
+	 * @var bool|int
+	 */
+	protected $idSubtable = false;
+	
+	/**
+	 * Set to true when the DataTable must be loaded along with all its children subtables
+	 * Useful when searching for a pattern in the DataTable Actions (we display the full hierarchy)
+	 * 
+	 * @var bool
+	 */
 	protected $recursiveDataTableLoad   = false;
 	
+	/**
+	 * DataTable loaded from the API for this ViewDataTable.
+	 *  
+	 * @var Piwik_DataTable
+	 */
+	protected $dataTable; 
+		
+	/**
+	 * @see init()
+	 *
+	 * @var string
+	 */
 	protected $currentControllerAction;
+	
+	/**
+	 * @see init()
+	 *
+	 * @var string
+	 */
 	protected $currentControllerName;
 	
+	/**
+	 * @see init()
+	 *
+	 * @var string
+	 */
 	protected $actionToLoadTheSubTable = null;
 	
 	/**
-	 * @var Piwik_DataTable
+	 * @see init()
+	 *
+	 * @var string
 	 */
-	public $dataTable; // data table
-	
 	protected $moduleNameAndMethod;
-		
-	protected $variablesDefault = array();
 	
-	protected $idSubtable = false;
+	/**
+	 * This view should be an implementation of the Interface Piwik_iView
+	 * The $view object should be created in the main() method.
+	 * 
+	 * @var Piwik_iView
+	 */
+	protected $view = null;
 	
 	/**
+	 * Method to be implemented by the ViewDataTable_*.
+	 * This method should create and initialize a $this->view object @see Piwik_iView
 	 * 
-	 * @return Piwik_ViewDataTable Data table
+	 * @return mixed either prints the result or returns the output string
 	 */
-	static public function factory( $type = null, $defaultType = null)
+	abstract public function main();
+	
+	/**
+	 * Returns a Piwik_ViewDataTable_* object.
+	 * By default it will return a ViewDataTable_Html
+	 * If there is a viewDataTable parameter in the URL, a ViewDataTable of this 'viewDataTable' type will be returned.
+	 * If defaultType is specified and if there is no 'viewDataTable' in the URL, a ViewDataTable of this $defaultType will be returned.
+	 * If force is set to true, a ViewDataTable of the $defaultType will be returned in all cases.
+	 * 
+	 * @param string defaultType Any of these: table, cloud, graphPie, graphVerticalBar, graphEvolution, sparkline, generateDataChart* 
+	 * @force bool If set to true, returns a ViewDataTable of the $defaultType
+	 * 
+	 * @return Piwik_ViewDataTable 
+	 */
+	static public function factory( $defaultType = null, $force = false)
 	{
 		if(is_null($defaultType))
 		{
 			$defaultType = 'table';	
 		}
-		if(is_null($type))
+		
+		if($force === true)
 		{
+			$type = $defaultType;
+		}
+		else
+		{
 			$type = Piwik_Common::getRequestVar('viewDataTable', $defaultType, 'string');
 		}
 		
@@ -114,8 +249,27 @@
 		}
 	}
 	
-	//TODO comment
-	function init( $currentControllerName,
+	/**
+	 * Inits the object given the $currentControllerName, $currentControllerAction of 
+	 * the calling controller action, eg. 'Referers' 'getLongListOfKeywords'.
+	 * The initialization also requires the $moduleNameAndMethod of the API method 
+	 * to call in order to get the DataTable, eg. 'Referers.getKeywords'.
+	 * The optional $actionToLoadTheSubTable defines the method name of the API to call when there is a idSubtable.
+	 * This value would be used by the javascript code building the GET request to the API.
+	 * 
+	 * Example: 
+	 * 	For the keywords listing, a click on the row loads the subTable of the Search Engines for this row.
+	 *  In this case $actionToLoadTheSubTable = 'getSearchEnginesFromKeywordId'.
+	 *  The GET request will hit 'Referers.getSearchEnginesFromKeywordId'.
+	 *
+	 * @param string $currentControllerName eg. 'Referers'
+	 * @param string $currentControllerAction eg. 'getKeywords'
+	 * @param string $moduleNameAndMethod eg. 'Referers.getKeywords'
+	 * @param string $actionToLoadTheSubTable eg. 'getSearchEnginesFromKeywordId'
+	 * 
+	 * @return void
+	 */
+	public function init( $currentControllerName,
 						$currentControllerAction, 
 						$moduleNameAndMethod, 
 						$actionToLoadTheSubTable = null)
@@ -135,89 +289,123 @@
 		$this->variablesDefault['filter_excludelowpop_value_default'] = 'false';	
 	}
 	
-	
-	abstract public function main();
-	
-	public function render()
+	/**
+	 * Forces the View to use a given template.
+	 * Usually the template to use is set in the specific ViewDataTable_* 
+	 * eg. 'Home/templates/cloud.tpl'
+	 *
+	 * But some users may want to force this template to some other value
+	 * 
+	 * @param string $tpl eg .'MyPlugin/templates/templateToUse.tpl'
+	 */
+	public function setTemplate( $tpl )
 	{
-		return $this->getView()->render();
+		$this->dataTableTemplate = $tpl;
 	}
-	
+		
 	/**
-	 * For convenience, the client code can call methods that are defined in a specific children class
-	 * without testing the children class type, which would trigger an error with a different children class.
-	 * For example, ViewDataTable/Html.php defines a setColumnsToDisplay(). The client code calls this methods even if
-	 * the ViewDataTable object is a ViewDataTable_Cloud instance. But ViewDataTable_Cloud doesn't define the 
-	 * setColumnsToDisplay() method. Because we don't want to force users to test for the object type we simply catch these
-	 * calls when they are not defined in the child and do nothing.  
+	 * Returns the iView.
+	 * You can then call render() on this object.
 	 *
-	 * @param string $function
-	 * @param array $args
+	 * @return Piwik_iView
+	 * @throws exception if the view object was not created
 	 */
-	public function __call($function, $args)
+	public function getView()
 	{
+		if(is_null($this->view))
+		{
+			throw new Exception('The $this->view object has not been created. 
+					It should be created in the main() method of the Piwik_ViewDataTable_* subclass you are using.');
+		}
+		return $this->view;
 	}
-	
-	
-	
-	// given a DataTable_Array made of DataTable_Simple
-	// returns PHP array containing rows of array( label => X, value => Y)
-	protected function generateDataFromDataTableArray( $dataTableArray)
-	{
-		// we have to fill a $data array with each row = array('label' => X, 'value' => y)
-		$data = array();
-		foreach($dataTableArray->getArray() as $keyName => $table)
+
+	/**
+	 * Function called by the ViewDataTable objects in order to fetch data from the API.
+	 * The function init() must have been called before, so that the object knows which API module and action to call.
+	 * It builds the API request string and uses Piwik_API_Request to call the API.
+	 * The requested Piwik_DataTable object is stored in $this->dataTable.
+	 * 
+	 * @return void
+	 */
+	protected function loadDataTableFromAPI()
+	{		
+		// we prepare the string to give to the API Request
+		// we setup the method and format variable
+		// - we request the method to call to get this specific DataTable
+		// - the format = original specifies that we want to get the original DataTable structure itself, not rendered
+		$requestString = 'method='.$this->moduleNameAndMethod
+						.'&format=original'
+					;
+		if( $this->recursiveDataTableLoad )
 		{
-			$value = false;
-			
-			$onlyRow = $table->getFirstRow();
-			if($onlyRow !== false)
-			{
-				$value = $onlyRow->getColumn('value');
-				if($value == false)
-				{
-					// TEMP
-					// quite a hack, useful in the case at this point we do have a normal row with nb_visits, nb_actions, nb_uniq_visitors, etc.
-					// instead of the dataTable_Simple row (label, value) 
-					// to do it properly we'd need to
-					// - create a filter that removes columns
-					// - apply this filter to keep only the column called nb_uniq_visitors
-					// - rename this column as 'value'
-					// and at this point the getcolumn('value') would have worked
-					// this code is executed eg. when displaying a sparkline for the last 30 days displaying the number of unique visitors coming from search engines
-					
-					//TODO solution: use a filter rename column etc.
-					
-					// another solution would be to add a method to the Referers API giving directly the integer 'visits from search engines'
-					// and we would build automatically the dataTable_array of datatatble_simple from these integers
-					// but we'd have to add this integer to be recorded during archiving etc.
-					$value = $onlyRow->getColumn('nb_uniq_visitors');
-				}
-			}
+			$requestString .= '&expanded=1';
+		}
 		
-			if($value === false)
+		$toSetEventually = array(
+			'filter_limit',
+			'filter_sort_column',
+			'filter_sort_order',
+			'filter_excludelowpop',
+			'filter_excludelowpop_value',
+			'filter_column', 
+			'filter_pattern',
+			'disable_generic_filters',
+			'disable_queued_filters',
+		);
+		foreach($toSetEventually as $varToSet)
+		{
+			$value = $this->getDefaultOrCurrent($varToSet);
+			if( false !== $value )
 			{
-				$value = 0;
+				$requestString .= '&'.$varToSet.'='.$value;
 			}
-			$data[] = array(
-					'label' => $keyName,
-					'value' => $value
-				);
 		}
-		return $data;
+		
+		// We finally make the request to the API
+		$request = new Piwik_API_Request($requestString);
+		
+		// and get the DataTable structure
+		$dataTable = $request->process();
+
+		$this->dataTable = $dataTable;
 	}
 	
-	public function getView()
+	
+	/**
+	 * For convenience, the client code can call methods that are defined in a specific children class
+	 * without testing the children class type, which would trigger an error with a different children class.
+	 * 
+	 * Example:
+	 *  ViewDataTable/Html.php defines a setColumnsToDisplay(). The client code calls this methods even if
+	 *  the ViewDataTable object is a ViewDataTable_Cloud instance (he doesn't know because of the factory()). 
+	 *  But ViewDataTable_Cloud doesn't define the setColumnsToDisplay() method. 
+	 *  Because we don't want to force users to test for the object type we simply catch these
+	 *  calls when they are not defined in the child and do nothing.  
+	 *
+	 * @param string $function
+	 * @param array $args
+	 */
+	public function __call($function, $args)
 	{
-		return $this->view;
 	}
-
+	
+	/**
+	 * Returns a unique ID for this ViewDataTable.
+	 * This unique ID is used in the Javascript code: 
+	 *  Any ajax loaded data is loaded within a DIV that has id=$unique_id 
+	 *  The jquery code then replaces the existing html div id=$unique_id in the code with this data.
+	 * 
+	 * @see datatable.js
+	 * @return string
+	 */
 	protected function getUniqIdTable()
 	{
-		$uniqIdTable = '';
 		// if we request a subDataTable the $this->currentControllerAction DIV ID is already there in the page
 		// we make the DIV ID really unique by appending the ID of the subtable requested
-		if( $this->idSubtable != false)
+		if( $this->idSubtable != 0 // parent DIV has a idSubtable = 0 but the html DIV must have the name of the module.action
+			&&  $this->idSubtable !== false // case there is no idSubtable 
+			)
 		{
 			// see also datatable.js (the ID has to match with the html ID created to be replaced by the result of the ajax call)
 			$uniqIdTable = 'subDataTable_' . $this->idSubtable;
@@ -231,6 +419,22 @@
 		return $uniqIdTable;
 	}
 	
+	/**
+	 * This functions reads the customization values for the DataTable and returns an array (name,value) to be printed in Javascript.
+	 * This array defines things such as:
+	 * - name of the module & action to call to request data for this table
+	 * - display the search box under the table
+	 * - display the links Next & Previous under the table
+	 * - optional filters information, eg. filter_limit and filter_offset
+	 * - etc.
+	 *
+	 * The values are loaded:
+	 * - from the generic filters that are applied by default @see Piwik_API_Request::getGenericFiltersInformation()
+	 * - from the values already available in the GET array
+	 * - from the values set using methods from this class (eg. setSearchPattern(), setLimit(), etc.)
+	 * 
+	 * @return array eg. array('show_offset_information' => 0, 'show_
+	 */
 	protected function getJavascriptVariablesToSet()
 	{
 		// build javascript variables to set
@@ -299,11 +503,10 @@
 		if($this->dataTable)
 		{
 			$javascriptVariablesToSet['totalRows'] = $this->dataTable->getRowsCountBeforeLimitFilter();
-		}	
+		}
 		$javascriptVariablesToSet['show_search'] = $this->getSearchBox();
 		$javascriptVariablesToSet['show_offset_information'] = $this->getOffsetInformation();
 		$javascriptVariablesToSet['show_exclude_low_population'] = $this->getExcludeLowPopulation();
-		$javascriptVariablesToSet['enable_sort'] = $this->getSort();
 		
 		// we escape the values that will be displayed in the javascript footer of each datatable
 		// to make sure there is malicious code injected (the value are already htmlspecialchar'ed as they
@@ -317,59 +520,12 @@
 	}
 	
 	/**
-	 * Function called by the ViewDataTable objects in order to fetch data from the API.
-	 * They must set $this->moduleNameAndMethod before (using the $this->init() method).
-	 * 
+	 * Returns, for a given parameter, the value of this parameter in the REQUEST array.
+	 * If not set, returns the default value for this parameter @see getDefault()
 	 *
+	 * @param string $nameVar
+	 * @return string|mixed Value of this parameter
 	 */
-	protected function loadDataTableFromAPI()
-	{		
-		// we prepare the string to give to the API Request
-		// we setup the method and format variable
-		// - we request the method to call to get this specific DataTable
-		// - the format = original specifies that we want to get the original DataTable structure itself, not rendered
-		$requestString = 'method='.$this->moduleNameAndMethod
-						.'&format=original'
-					;
-		if( $this->recursiveDataTableLoad )
-		{
-			$requestString .= '&expanded=1';
-		}
-		
-		$toSetEventually = array(
-			'filter_limit',
-			'filter_sort_column',
-			'filter_sort_order',
-			'filter_excludelowpop',
-			'filter_excludelowpop_value',
-			'filter_column', 
-			'filter_pattern',
-			'disable_generic_filters',
-			'disable_queued_filters',
-		);
-		foreach($toSetEventually as $varToSet)
-		{
-			$value = $this->getDefaultOrCurrent($varToSet);
-			if( false !== $value )
-			{
-				$requestString .= '&'.$varToSet.'='.$value;
-			}
-		}
-		
-		// We finally make the request to the API
-		$request = new Piwik_API_Request($requestString);
-		
-		// and get the DataTable structure
-		$dataTable = $request->process();
-
-		$this->dataTable = $dataTable;
-	}
-
-	public function setTemplate( $tpl )
-	{
-		$this->dataTableTemplate = $tpl;
-	}
-	
 	protected function getDefaultOrCurrent( $nameVar )
 	{
 		if(isset($_REQUEST[$nameVar]))
@@ -380,7 +536,13 @@
 		return $default;
 	}
 
-	
+	/**
+	 * Returns the default value for a given parameter.
+	 * For example, these default values can be set using the disable* methods.
+	 * 
+	 * @param string $nameVar
+	 * @return mixed
+	 */
 	protected function getDefault($nameVar)
 	{
 		if(!isset($this->variablesDefault[$nameVar]))
@@ -390,35 +552,55 @@
 		return $this->variablesDefault[$nameVar];
 	}
 	
-	public function disableSort()
-	{
-		$this->JSsortEnabled = 'false';		
-	}
-	
-	public function getSort()
-	{
-		return $this->JSsortEnabled;		
-	}
-
+	/**
+	 * The generic filters (limit, offset, sort by visit desc) will not be applied to this datatable.
+	 * 
+	 * @return void
+	 *
+	 */
 	public function disableGenericFilters()
 	{
 		$this->variablesDefault['disable_generic_filters'] = true;
 	}
+	/**
+	 * The "X-Y of Z" won't be displayed under this table
+	 * 
+	 * @return void
+	 *
+	 */
 	public function disableOffsetInformation()
 	{
 		$this->JSoffsetInformation = 'false';		
 	}
-	public function getOffsetInformation()
+	
+	/**
+	 * @see disableOffsetInformation()
+	 * 
+	 * @return bool|string If this parameter is enabled or not
+	 *
+	 */
+	protected function getOffsetInformation()
 	{
 		return $this->JSoffsetInformation;
 	}
 	
+	/**
+	 * The search box won't be displayed under this table
+	 *
+	 * @return void
+	 */
 	public function disableSearchBox()
 	{
 		$this->JSsearchBox = 'false';
 	}
 	
-	public function getSearchBox()
+	/**
+	 * @see disableSearchBox()
+	 * 
+	 * @return bool|string If this parameter is enabled or not
+	 *
+	 */
+	protected function getSearchBox()
 	{
 		return $this->JSsearchBox;
 	}
@@ -433,46 +615,91 @@
 		$this->showFooter = false;
 	}
 	
+	/**
+	 * Returns true if the footer should be included in the template 
+	 * 
+	 * @return bool
+	 *
+	 */
+	protected function getShowFooter()
+	{
+		return $this->showFooter;
+	}
+	
+	/**
+	 * The "Include low population" link won't be displayed under this table
+	 *
+	 * @return void
+	 */
 	public function disableExcludeLowPopulation()
 	{
 		$this->JSexcludeLowPopulation = 'false';
 	}
 	
-	public function getExcludeLowPopulation()
+	/**
+	 * @see disableExcludeLowPopulation()
+	 * 
+	 * @return bool|string If this parameter is enabled or not
+	 *
+	 */
+	protected function getExcludeLowPopulation()
 	{
 		return $this->JSexcludeLowPopulation;
 	}
 	
 	
-	public function setExcludeLowPopulation( $value = null, $columnId = null )
+	/**
+	 * Sets the value to use for the Exclude low population filter.
+	 * 
+	 * @param int|float If a row value is less than this value, it will be removed from the dataTable
+	 * @param string The name of the column for which we compare the value to $minValue
+	 *
+	 * @return void
+	 */
+	public function setExcludeLowPopulation( $minValue = null, $columnName = null )
 	{
-		if( is_null( $value) ) 
+		if( is_null( $minValue) ) 
 		{
 			throw new Exception("setExcludeLowPopulation() value shouldn't be null");
 		}
 		
-		if(is_null($columnId))
+		if(is_null($columnName))
 		{
-			$columnId = Piwik_Archive::INDEX_NB_VISITS;
+			$columnName = Piwik_Archive::INDEX_NB_VISITS;
 		}
 		
 		// column to use to enable low population exclusion if != false
 		$this->variablesDefault['filter_excludelowpop_default'] 
 			= $this->variablesDefault['filter_excludelowpop']
-			= $columnId;
+			= $columnName;
 		
 		// the minimum value a row must have to be returned 
 		$this->variablesDefault['filter_excludelowpop_value_default'] 
 			= $this->variablesDefault['filter_excludelowpop_value']
-			= $value;	
+			= $minValue;	
 	}
 	
+	/**
+	 * Sets the pattern to look for in the table (only rows matching the pattern will be kept)
+	 *
+	 * @param string $pattern to look for
+	 * @param string $column to compare the pattern to
+	 * 
+	 * @return void
+	 */
 	public function setSearchPattern($pattern, $column)
 	{
 		$this->variablesDefault['filter_pattern'] = $pattern;
 		$this->variablesDefault['filter_column'] = $column;
 	}
 
+	/**
+	 * Sets the maximum number of rows of the table
+	 *
+	 * @param int $limit
+	 * 
+	 * @return void
+	 */
 	public function setLimit( $limit )
 	{
 		if($limit != 0)
@@ -480,9 +707,78 @@
 			$this->variablesDefault['filter_limit'] = $limit;
 		}
 	}
+	
+	/**
+	 * Sets the dataTable column to sort by. This sorting will be applied before applying the (offset, limit) filter. 
+	 *
+	 * @param int|string $columnId eg. 'nb_visits' for some tables, or Piwik_Archive::INDEX_NB_VISITS for others
+	 * @param string $order desc or asc
+	 * 
+	 * @return void
+	 */
 	public function setSortedColumn( $columnId, $order = 'desc')
 	{
 		$this->variablesDefault['filter_sort_column']= $columnId;
 		$this->variablesDefault['filter_sort_order']= $order;
 	}
+	
+	
+	/**
+	 * Given a Piwik_DataTable_Array made of DataTable_Simple rows, returns a php array with the structure:
+	 * array(
+	 * 	array( label => X, value => Y),
+	 * 	array( label => A, value => B),
+	 * ...
+	 * )
+	 *
+	 * This is used for example for the evolution graph (last 30 days visits) or the sparklines.
+	 * 
+	 * @param Piwik_DataTable_Array $dataTableArray
+	 * @return array
+	 */
+	protected function generateDataFromDataTableArray( Piwik_DataTable_Array $dataTableArray)
+	{
+		// we have to fill a $data array with each row = array('label' => X, 'value' => y)
+		$data = array();
+		foreach($dataTableArray->getArray() as $keyName => $table)
+		{
+			$value = false;
+			
+			$onlyRow = $table->getFirstRow();
+			if($onlyRow !== false)
+			{
+				$value = $onlyRow->getColumn('value');
+				if($value == false)
+				{
+					// TEMP
+					// quite a hack, useful in the case at this point we do have a normal row with nb_visits, nb_actions, nb_uniq_visitors, etc.
+					// instead of the dataTable_Simple row (label, value) 
+					// to do it properly we'd need to
+					// - create a filter that removes columns
+					// - apply this filter to keep only the column called nb_uniq_visitors
+					// - rename this column as 'value'
+					// and at this point the getcolumn('value') would have worked
+					// this code is executed eg. when displaying a sparkline for the last 30 days displaying the number of unique visitors coming from search engines
+					
+					//TODO solution: use a filter rename column etc.
+					
+					// another solution would be to add a method to the Referers API giving directly the integer 'visits from search engines'
+					// and we would build automatically the dataTable_array of datatatble_simple from these integers
+					// but we'd have to add this integer to be recorded during archiving etc.
+					$value = $onlyRow->getColumn('nb_uniq_visitors');
+				}
+			}
+		
+			if($value === false)
+			{
+				$value = 0;
+			}
+			$data[] = array(
+					'label' => $keyName,
+					'value' => $value
+				);
+		}
+		return $data;
+	}
+	
 }
\ No newline at end of file

Modified: trunk/modules/Visualization/Chart.php
===================================================================
--- trunk/modules/Visualization/Chart.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/Visualization/Chart.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -12,11 +12,14 @@
 require_once "Visualization/OpenFlashChart.php";
 
 /**
+ * Generates the data in the Open Flash Chart format, from the given data.
+ * Uses Open flash chart PHP library @see Piwik_Visualization_OpenFlashChart
  * 
  * @package Piwik_Visualization
  */
 abstract class Piwik_Visualization_Chart extends Piwik_Visualization_OpenFlashChart
 {
+	
 	protected $dataGraph = array();
 	
 	function setData($data)

Modified: trunk/modules/Visualization/ChartEvolution.php
===================================================================
--- trunk/modules/Visualization/ChartEvolution.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/Visualization/ChartEvolution.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -12,6 +12,7 @@
 require_once "Visualization/Chart.php";
 
 /**
+ * Customize the Evolution chart style for the flash graph
  * 
  * @package Piwik_Visualization
  *
@@ -21,11 +22,41 @@
 	
 	function customizeGraph()
 	{
-		//TODO add this call in other child
 		parent::customizeGraph();
 		$this->prepareData();
 		$this->set_y_max( $this->maxData );
-		$this->set_data( $this->arrayData );
+		
+		$line_1 = new line_hollow( 1, 3, '0x3357A0' );
+		$line_1->key( 'visits', 10 );
+		
+		$i = 0;
+		foreach($this->arrayData as $value)
+		{
+			// hack until we have proper date handling
+			$spacePosition = strpos($this->arrayLabel[$i],' ');
+			if($spacePosition === false)
+			{
+				$spacePosition = strlen($this->arrayLabel[$i]);
+			}
+			
+			// generate the link on the dot
+			// links to the given day statistics
+			$link = Piwik_Url::getCurrentScriptName() 
+							. Piwik_Url::getCurrentQueryStringWithParametersModified( array(
+										'date' => substr($this->arrayLabel[$i],0,$spacePosition),
+										'module' => 'Home',
+										'action' => 'index',
+										'viewDataTable' => null// we reset the viewDataTable parameter (useless in the link)
+										));
+										
+//			$link = 'http://piwik.org';
+			
+			$line_1->add_link($value, $link );
+			$i++;
+		}
+		$this->data_sets[] = $line_1;
+		
+		
 		$this->set_x_labels( $this->arrayLabel );
 		$this->area_hollow( 1, 3, 4,'0x3357A0',  ' visits', 10 );	
 	}

Modified: trunk/modules/Visualization/ChartPie.php
===================================================================
--- trunk/modules/Visualization/ChartPie.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/Visualization/ChartPie.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -12,6 +12,8 @@
 
 /**
  * 
+ * Customize the Pie chart style for the flash graph
+ * 
  * @package Piwik_Visualization
  */
 class Piwik_Visualization_ChartPie extends Piwik_Visualization_Chart

Modified: trunk/modules/Visualization/ChartVerticalBar.php
===================================================================
--- trunk/modules/Visualization/ChartVerticalBar.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/Visualization/ChartVerticalBar.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -13,6 +13,8 @@
 
 /**
  * 
+ * Customize the Vertical bar chart style for the flash graph
+ * 
  * @package Piwik_Visualization
  *
  */

Modified: trunk/modules/Visualization/Cloud.php
===================================================================
--- trunk/modules/Visualization/Cloud.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/Visualization/Cloud.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -9,16 +9,21 @@
  * @package Piwik_Visualization
  */
 
-// inspired from Derek Harvey (www.derekharvey.co.uk)
 
-/**
- *
+/**
+ * Generates a tag cloud from a given data array.
+ * The generated tag cloud can be in PHP format, or in HTML. 
+ *
+ * Inspired from Derek Harvey (www.derekharvey.co.uk)
+ * 
  * @package Piwik_Visualization
  */
 class Piwik_Visualization_Cloud
 {
 	protected $wordsArray = array();
+	
 	public $truncatingLimit = 30;
+	
 	/**
 	 * @param array array( word => 10, word2 => 50, word3 => 1)
 	 */
@@ -83,8 +88,7 @@
 	 * Get the class range using a percentage
 	 *
 	 * @returns int $class
-	 */
-	 
+	 */	 
 	function getClassFromPercent($percent)
 	{
 		$mapping = array(

Modified: trunk/modules/Visualization/OpenFlashChart.php
===================================================================
--- trunk/modules/Visualization/OpenFlashChart.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/modules/Visualization/OpenFlashChart.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -5,30 +5,33 @@
  * @link http://piwik.org
  * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
  * @version $Id$
- *
- * @package Piwik_Visualization
+ *
+ * @package Piwik_Visualization
+ * @subpackage OFC
  */
 
 require_once "iView.php";
+
 
 /**
  * Original class provided by Open Flash Chart
  *
  * @package Piwik_Visualization
  */
-
 abstract class Piwik_Visualization_OpenFlashChart implements Piwik_iView
 {
 	function __construct()
 	{
+
 		$this->data_sets = array();
-
-
+		
+		
 		$this->data = array();
 		$this->links = array();
 		$this->width = 250;
 		$this->height = 200;
-		$this->base = 'js/';
+		$this->js_path = 'js/';
+		$this->swf_path = '';
 		$this->x_labels = array();
 		$this->y_min = '';
 		$this->y_max = '';
@@ -38,7 +41,7 @@
 		$this->title = '';
 		$this->title_style = '';
 		$this->occurence = 0;
-
+		
 		$this->x_offset = '';
 
 		$this->x_tick_size = -1;
@@ -54,54 +57,56 @@
 		$this->y_axis_colour = '';
 		$this->y_grid_colour = '';
 		$this->y2_axis_colour = '';
-
-		// AXIS LABEL styles:
+		
+		// AXIS LABEL styles:         
 		$this->x_label_style = '';
 		$this->y_label_style = '';
 		$this->y_label_style_right = '';
-
-
+	
+	
 		// AXIS LEGEND styles:
 		$this->x_legend = '';
 		$this->x_legend_size = 20;
 		$this->x_legend_colour = '#000000';
-
+	
 		$this->y_legend = '';
 		$this->y_legend_right = '';
 		//$this->y_legend_size = 20;
 		//$this->y_legend_colour = '#000000';
-
+	
 		$this->lines = array();
 		$this->line_default['type'] = 'line';
 		$this->line_default['values'] = '3,#87421F';
 		$this->js_line_default = 'so.addVariable("line","3,#87421F");';
-
+		
 		$this->bg_colour = '';
 		$this->bg_image = '';
-
+	
 		$this->inner_bg_colour = '';
 		$this->inner_bg_colour_2 = '';
 		$this->inner_bg_angle = '';
-
+		
 		// PIE chart ------------
 		$this->pie = '';
 		$this->pie_values = '';
 		$this->pie_colours = '';
 		$this->pie_labels = '';
-
+		
 		$this->tool_tip = '';
-
+		
 		// which data lines are attached to the
 		// right Y axis?
 		$this->y2_lines = array();
-
+		
 		// Number formatting:
 		$this->y_format='';
 		$this->num_decimals='';
 		$this->is_fixed_num_decimals_forced='';
 		$this->is_decimal_separator_comma='';
 		$this->is_thousand_separator_disabled='';
-
+		
+		$this->output_type = '';
+		
 		//
 		// set some default value incase the user forgets
 		// to set them, so at least they see *something*
@@ -114,72 +119,66 @@
 	}
 
 	/**
-	 * Set the unique_id to use for the flash object id.
-	 */
+	* Set the unique_id to use for the flash object id.
+	*/
 	function set_unique_id()
 	{
-		$this->unique_id = uniqid();
+		$this->unique_id = uniqid(rand(), true);
 	}
-
+	
 	/**
-	 * Get the flash object ID for the last rendered object.
-	 */
+	* Get the flash object ID for the last rendered object.
+	*/
 	function get_unique_id()
 	{
 		return ($this->unique_id);
 	}
-
+	
 	/**
-	 * Set the base path for the swfobject.js
-	 *
-	 * @param base_path a string argument.
-	 *   The path to the swfobject.js file
-	 */
+	* Set the base path for the swfobject.js
+	*
+	* @param base_path a string argument.
+	*   The path to the swfobject.js file
+	*/
 	function set_js_path($path)
 	{
 		$this->js_path = $path;
 	}
-
+	
 	/**
-	 * Set the base path for the open-flash-chart.swf
-	 *
-	 * @param path a string argument.
-	 *   The path to the open-flash-chart.swf file
-	 */
+	* Set the base path for the open-flash-chart.swf
+	*
+	* @param path a string argument.
+	*   The path to the open-flash-chart.swf file
+	*/
 	function set_swf_path($path)
 	{
 		$this->swf_path = $path;
 	}
 
 	/**
-	 * Set the type of output data.
-	 *
-	 * @param type a string argument.
-	 *   The type of data.  Currently only type is js, or nothing.
-	 */
+	* Set the type of output data.
+	*
+	* @param type a string argument.
+	*   The type of data.  Currently only type is js, or nothing.
+	*/
 	function set_output_type($type)
 	{
 		$this->output_type = $type;
 	}
 
-	// is this needed now?
-	function increment_occurence()
-	{
-		$this->occurence++;
-	}
-
 	/**
-	 * returns the next line label for multiple lines.
-	 */
+	* returns the next line label for multiple lines.
+	*/
 	function next_line()
 	{
 		$line_num = '';
 		if( count( $this->lines ) > 0 )
-		$line_num = '_'. (count( $this->lines )+1);
+			$line_num = '_'. (count( $this->lines )+1);
 
 		return $line_num;
 	}
-
+	
 	// escape commas (,)
 	function esc( $text )
 	{
@@ -188,16 +187,17 @@
 		// which is no good if we are splitting the
 		// string on commas.
 		$tmp = str_replace( ',', '#comma#', $text );
+		//$tmp = utf8_encode( $tmp );
 		// now we urlescape all dodgy characters (like & % $ etc..)
 		return urlencode( $tmp );
 	}
 
 	/**
-	 * Format the text to the type of output.
-	 */
-	function format_output($output_type,$function,$values)
+	* Format the text to the type of output.
+	*/
+	function format_output($function,$values)
 	{
-		if($output_type == 'js')
+		if($this->output_type == 'js')
 		{
 			$tmp = 'so.addVariable("'. $function .'","'. $values . '");';
 		}
@@ -210,18 +210,18 @@
 	}
 
 	/**
-	 * Set the text and style of the title.
-	 *
-	 * @param title a string argument.
-	 *   The text of the title.
-	 * @param style a string.
-	 *   CSS styling of the title.
-	 */
+	* Set the text and style of the title.
+	*
+	* @param title a string argument.
+	*   The text of the title.
+	* @param style a string.
+	*   CSS styling of the title.
+	*/
 	function set_title( $title, $style='' )
 	{
-		$this->title = $title;
+		$this->title = $this->esc( $title );
 		if( strlen( $style ) > 0 )
-		$this->title_style = $style;
+			$this->title_style = $style;
 	}
 
 	/**
@@ -234,7 +234,7 @@
 	{
 		$this->width = $width;
 	}
-
+	
 	/**
 	 * Set the height of the chart.
 	 *
@@ -256,28 +256,28 @@
 	{
 		$this->base = $base;
 	}
-
+	
 	// Number formatting:
 	function set_y_format( $val )
 	{
-		$this->y_format = $val;
+		$this->y_format = $val;	
 	}
-
+	
 	function set_num_decimals( $val )
 	{
 		$this->num_decimals = $val;
 	}
-
+	
 	function set_is_fixed_num_decimals_forced( $val )
 	{
 		$this->is_fixed_num_decimals_forced = $val?'true':'false';
 	}
-
+	
 	function set_is_decimal_separator_comma( $val )
 	{
 		$this->is_decimal_separator_comma = $val?'true':'false';
 	}
-
+	
 	function set_is_thousand_separator_disabled( $val )
 	{
 		$this->is_thousand_separator_disabled = $val?'true':'false';
@@ -292,13 +292,14 @@
 	{
 		$this->data[] = implode(',',$a);
 	}
-
+	
 	// UGH, these evil functions are making me fell ill
-	function set_links( $a )
+	function set_links( $links )
 	{
-		$this->links[] = implode(',',$a);
+		// TO DO escape commas:
+		$this->links[] = implode(',',$links);
 	}
-
+	
 	// $val is a boolean
 	function set_x_offset( $val )
 	{
@@ -315,7 +316,7 @@
 	 * #x_label# - The X label string. \n
 	 * #x_legend# - The X axis legend text. \n
 	 * Default string is: "#x_label#<br>#val#" \n
-	 *
+	 * 
 	 * @param tip a string argument.
 	 *   A formatted string to show as the tooltip.
 	 */
@@ -332,7 +333,10 @@
 	 */
 	function set_x_labels( $a )
 	{
-		$this->x_labels = $a;
+		$tmp = array();
+		foreach( $a as $item )
+			$tmp[] = $this->esc( $item );
+		$this->x_labels = $tmp;
 	}
 
 	/**
@@ -354,18 +358,18 @@
 	function set_x_label_style( $size, $colour='', $orientation=0, $step=-1, $grid_colour='' )
 	{
 		$this->x_label_style = $size;
-
+		
 		if( strlen( $colour ) > 0 )
-		$this->x_label_style .= ','. $colour;
+			$this->x_label_style .= ','. $colour;
 
 		if( $orientation > -1 )
-		$this->x_label_style .= ','. $orientation;
+			$this->x_label_style .= ','. $orientation;
 
 		if( $step > 0 )
-		$this->x_label_style .= ','. $step;
+			$this->x_label_style .= ','. $step;
 
 		if( strlen( $grid_colour ) > 0 )
-		$this->x_label_style .= ','. $grid_colour;
+			$this->x_label_style .= ','. $grid_colour;
 	}
 
 	/**
@@ -405,7 +409,7 @@
 	}
 
 	/**
-	 * Set the background colour of the grid portion of the chart.
+ 	 * Set the background colour of the grid portion of the chart.
 	 * @param col a string argument.
 	 *   The hex colour value of the background.
 	 * @param col2 a string argument.
@@ -416,12 +420,12 @@
 	function set_inner_background( $col, $col2='', $angle=-1 )
 	{
 		$this->inner_bg_colour = $col;
-
+		
 		if( strlen($col2) > 0 )
-		$this->inner_bg_colour_2 = $col2;
-
+			$this->inner_bg_colour_2 = $col2;
+		
 		if( $angle != -1 )
-		$this->inner_bg_angle = $angle;
+			$this->inner_bg_angle = $angle;
 	}
 
 	/**
@@ -430,9 +434,9 @@
 	function _set_y_label_style( $size, $colour )
 	{
 		$tmp = $size;
-
+		
 		if( strlen( $colour ) > 0 )
-		$tmp .= ','. $colour;
+			$tmp .= ','. $colour;
 		return $tmp;
 	}
 
@@ -464,56 +468,56 @@
 
 	function set_x_max( $max )
 	{
-		$this->x_max = intval( $max );
+		$this->x_max = floatval( $max );
 	}
 
 	function set_x_min( $min )
 	{
-		$this->x_min = intval( $min );
+		$this->x_min = floatval( $min );
 	}
 
 	/**
 	 * Set the maximum value of the y axis.
 	 *
-	 * @param max an int argument.
+	 * @param max an float argument.
 	 *   The maximum value.
 	 */
 	function set_y_max( $max )
 	{
-		$this->y_max = intval( $max );
+		$this->y_max = floatval( $max );
 	}
 
 	/**
 	 * Set the minimum value of the y axis.
 	 *
-	 * @param min an int argument.
+	 * @param min an float argument.
 	 *   The minimum value.
 	 */
 	function set_y_min( $min )
 	{
-		$this->y_min = intval( $min );
+		$this->y_min = floatval( $min );
 	}
 
 	/**
 	 * Set the maximum value of the right y axis.
 	 *
-	 * @param max an int argument.
+	 * @param max an float argument.
 	 *   The maximum value.
-	 */
+	 */  
 	function set_y_right_max( $max )
 	{
-		$this->y2_max = intval($max);
+		$this->y2_max = floatval($max);
 	}
 
 	/**
 	 * Set the minimum value of the right y axis.
 	 *
-	 * @param min an int argument.
+	 * @param min an float argument.
 	 *   The minimum value.
 	 */
 	function set_y_right_min( $min )
 	{
-		$this->y2_min = intval($min);
+		$this->y2_min = floatval($min);
 	}
 
 	/**
@@ -524,14 +528,14 @@
 	 */
 	function y_label_steps( $val )
 	{
-		$this->y_steps = intval( $val );
+		 $this->y_steps = intval( $val );
 	}
-
+	
 	function title( $title, $style='' )
 	{
-		$this->title = $this->esc( $title );
-		if( strlen( $style ) > 0 )
-		$this->title_style = $style;
+		 $this->title = $this->esc( $title );
+		 if( strlen( $style ) > 0 )
+				 $this->title_style = $style;
 	}
 
 	/**
@@ -542,16 +546,16 @@
 	 * @param font_size an int argument.
 	 *   The font size of the x legend text.
 	 * @param colour a string argument
-	 *   The hex value of the font colour.
+	 *   The hex value of the font colour. 
 	 */
 	function set_x_legend( $text, $size=-1, $colour='' )
 	{
 		$this->x_legend = $this->esc( $text );
 		if( $size > -1 )
-		$this->x_legend_size = $size;
-
+			$this->x_legend_size = $size;
+		
 		if( strlen( $colour )>0 )
-		$this->x_legend_colour = $colour;
+			$this->x_legend_colour = $colour;
 	}
 
 	/**
@@ -563,7 +567,7 @@
 	function set_x_tick_size( $size )
 	{
 		if( $size > 0 )
-		$this->x_tick_size = $size;
+				$this->x_tick_size = $size;
 	}
 
 	/**
@@ -575,7 +579,7 @@
 	function set_x_axis_steps( $steps )
 	{
 		if ( $steps > 0 )
-		$this->x_axis_steps = $steps;
+			$this->x_axis_steps = $steps;
 	}
 
 	/**
@@ -587,24 +591,24 @@
 	function set_x_axis_3d( $size )
 	{
 		if( $size > 0 )
-		$this->x_axis_3d = intval($size);
+			$this->x_axis_3d = intval($size);
 	}
-
+	
 	/**
 	 * The private method of building the y legend output.
 	 */
 	function _set_y_legend( $text, $size, $colour )
 	{
 		$tmp = $text;
-
+	
 		if( $size > -1 )
-		$tmp .= ','. $size;
+			$tmp .= ','. $size;
 
 		if( strlen( $colour )>0 )
-		$tmp .= ','. $colour;
+			$tmp .= ','. $colour;
 
 		return $tmp;
-	}
+		}
 
 	/**
 	 * Set the parameters of the y legend.
@@ -614,7 +618,7 @@
 	 * @param font_size an int argument.
 	 *   The font size of the y legend text.
 	 * @param colour a string argument
-	 *   The hex colour value of the font colour.
+	 *   The hex colour value of the font colour. 
 	 */
 	function set_y_legend( $text, $size=-1, $colour='' )
 	{
@@ -629,20 +633,20 @@
 	 * @param font_size an int argument.
 	 *   The font size of the right y legend text.
 	 * @param colour a string argument
-	 *   The hex value of the font colour.
+	 *   The hex value of the font colour. 
 	 */
 	function set_y_right_legend( $text, $size=-1, $colour='' )
 	{
 		$this->y_legend_right = $this->_set_y_legend( $text, $size, $colour );
 	}
-
+	
 	/**
 	 * Set the colour of the x axis line and grid.
 	 *
 	 * @param axis a string argument.
 	 *   The hex colour value of the x axis line.
 	 * @param grid a string argument.
-	 *   The hex colour value of the x axis grid.
+	 *   The hex colour value of the x axis grid. 
 	 */
 	function x_axis_colour( $axis, $grid='' )
 	{
@@ -656,14 +660,14 @@
 	 * @param axis a string argument.
 	 *   The hex colour value of the y axis line.
 	 * @param grid a string argument.
-	 *   The hex colour value of the y axis grid.
+	 *   The hex colour value of the y axis grid. 
 	 */
 	function y_axis_colour( $axis, $grid='' )
 	{
 		$this->y_axis_colour = $axis;
 
 		if( strlen( $grid ) > 0 )
-		$this->y_grid_colour = $grid;
+			$this->y_grid_colour = $grid;
 	}
 
 	/**
@@ -674,7 +678,7 @@
 	 */
 	function y_right_axis_colour( $colour )
 	{
-		$this->y2_axis_colour = $colour;
+		 $this->y2_axis_colour = $colour;
 	}
 
 	/**
@@ -708,8 +712,8 @@
 			$description .= ','. $size;
 		}
 
-		if( $circles > 0 )
-		$description .= ','. $circles;
+		if( $circles > 0 ) 
+			$description .= ','. $circles;
 
 		$this->lines[$type] = $description;
 	}
@@ -735,7 +739,7 @@
 		$description = "$width,$colour,$text";
 
 		if( strlen( $font_size ) > 0 )
-		$description .= ",$font_size,$dot_size";
+			$description .= ",$font_size,$dot_size";
 
 		$this->lines[$type] = $description;
 	}
@@ -761,7 +765,7 @@
 		$description = "$width,$colour,$text";
 
 		if( strlen( $font_size ) > 0 )
-		$description .= ",$font_size,$dot_size";
+			$description .= ",$font_size,$dot_size";
 
 		$this->lines[$type] = $description;
 	}
@@ -791,10 +795,10 @@
 		$description = "$width,$dot_size,$colour,$alpha";
 
 		if( strlen( $text ) > 0 )
-		$description .= ",$text,$font_size";
-
+			$description .= ",$text,$font_size";
+	
 		if( strlen( $fill_colour ) > 0 )
-		$description .= ','. $fill_colour;
+			$description .= ','. $fill_colour;
 
 		$this->lines[$type] = $description;
 	}
@@ -916,7 +920,7 @@
 
 		$this->lines[$type] = $description;
 	}
-
+	
 	function candle( $data, $alpha, $line_width, $colour, $text='', $size=-1 )
 	{
 		$type = 'candle'. $this->next_line();
@@ -924,14 +928,14 @@
 		$description = $alpha .','. $line_width .','. $colour .','. $text .','. $size;
 
 		$this->lines[$type] = $description;
-
+		
 		$a = array();
 		foreach( $data as $can )
-		$a[] = $can->toString();
+			$a[] = $can->toString();
 			
 		$this->data[] = implode(',',$a);
 	}
-
+	
 	function hlc( $data, $alpha, $line_width, $colour, $text='', $size=-1 )
 	{
 		$type = 'hlc'. $this->next_line();
@@ -939,10 +943,10 @@
 		$description = $alpha .','. $line_width .','. $colour .','. $text .','. $size;
 
 		$this->lines[$type] = $description;
-
+		
 		$a = array();
 		foreach( $data as $can )
-		$a[] = $can->toString();
+			$a[] = $can->toString();
 			
 		$this->data[] = implode(',',$a);
 	}
@@ -954,10 +958,10 @@
 		$description = $line_width .','. $colour .','. $text .','. $size;
 
 		$this->lines[$type] = $description;
-
+		
 		$a = array();
 		foreach( $data as $can )
-		$a[] = $can->toString();
+			$a[] = $can->toString();
 			
 		$this->data[] = implode(',',$a);
 	}
@@ -967,22 +971,22 @@
 	// Patch by, Jeremy Miller (14th Nov, 2007)
 	//
 	/**
-	* Draw a pie chart.
-	*
-	* @param alpha an int argument.
-	*   The percentage of transparency of the pie colour.
-	* @param line_colour a string argument.
-	*   The hex colour value of the outline.
-	* @param label_colour a string argument.
-	*   The hex colour value of the label.
-	* @param gradient a boolean argument.
-	*   Use a gradient true or false.
-	* @param border_size an int argument.
-	*   Size of the border in pixels.
-	*/
-	function pie( $alpha, $line_colour, $label_colour, $gradient = true, $border_size = false )
+	 * Draw a pie chart.
+	 *
+	 * @param alpha an int argument.
+	 *   The percentage of transparency of the pie colour.
+	 * @param $style a string argument.
+	 *   CSS style string
+	 * @param label_colour a string argument.
+	 *   The hex colour value of the label.
+	 * @param gradient a boolean argument.
+	 *   Use a gradient true or false.
+	 * @param border_size an int argument.
+	 *   Size of the border in pixels.
+	 */
+	function pie( $alpha, $line_colour, $style, $gradient = true, $border_size = false )
 	{
-		$this->pie = $alpha.','.$line_colour.','.$label_colour;
+		$this->pie = $alpha.','.$line_colour.','.$style;
 		if( !$gradient )
 		{
 			$this->pie .= ','.!$gradient;
@@ -1006,7 +1010,7 @@
 	 *   An array of the labels for the pie pieces.
 	 * @param links an array argument.
 	 *   An array of the links to the pie pieces.
-	 */
+	 */	
 	function pie_values( $values, $labels=array(), $links=array() )
 	{
 		$this->pie_values = implode(',',$values);
@@ -1024,23 +1028,27 @@
 	{
 		$this->pie_colours = implode(',',$colours);
 	}
+	
 
-
 	/**
 	 * Render the output.
 	 */
-	function render($output_type = '')
+	function render()
 	{
 		$tmp = array();
+		
+		//echo headers_sent() ?'yes':'no';
+		if( !headers_sent() )
+			header('content-type: text; charset: utf-8');
 
-		if($output_type == 'js')
+		if($this->output_type == 'js')
 		{
-			$this->increment_occurence();
-
-			$tmp[] = '<div id="my_chart' . $this->occurence . '"></div>';
-			$tmp[] = '<script type="text/javascript" src="' . $this->base . 'swfobject.js"></script>';
+			$this->set_unique_id();
+		
+			$tmp[] = '<div id="' . $this->unique_id . '"></div>';
+			$tmp[] = '<script type="text/javascript" src="' . $this->js_path . 'swfobject.js"></script>';
 			$tmp[] = '<script type="text/javascript">';
-			$tmp[] = 'var so = new SWFObject("open-flash-chart.swf", "ofc", "'. $this->width . '", "' . $this->height . '", "9", "#FFFFFF");';
+			$tmp[] = 'var so = new SWFObject("' . $this->swf_path . 'open-flash-chart.swf", "ofc", "'. $this->width . '", "' . $this->height . '", "9", "#FFFFFF");';
 			$tmp[] = 'so.addVariable("variables","true");';
 		}
 
@@ -1048,7 +1056,7 @@
 		{
 			$values = $this->title;
 			$values .= ','. $this->title_style;
-			$tmp[] = $this->format_output($output_type,'title',$values);
+			$tmp[] = $this->format_output('title',$values);
 		}
 
 		if( strlen( $this->x_legend ) > 0 )
@@ -1056,129 +1064,129 @@
 			$values = $this->x_legend;
 			$values .= ','. $this->x_legend_size;
 			$values .= ','. $this->x_legend_colour;
-			$tmp[] = $this->format_output($output_type,'x_legend',$values);
+			$tmp[] = $this->format_output('x_legend',$values);
 		}
-
+	
 		if( strlen( $this->x_label_style ) > 0 )
-		$tmp[] = $this->format_output($output_type,'x_label_style',$this->x_label_style);
-
+			$tmp[] = $this->format_output('x_label_style',$this->x_label_style);
+	
 		if( $this->x_tick_size > 0 )
-		$tmp[] = $this->format_output($output_type,'x_ticks',$this->x_tick_size);
+			$tmp[] = $this->format_output('x_ticks',$this->x_tick_size);
 
 		if( $this->x_axis_steps > 0 )
-		$tmp[] = $this->format_output($output_type,'x_axis_steps',$this->x_axis_steps);
+			$tmp[] = $this->format_output('x_axis_steps',$this->x_axis_steps);
 
 		if( strlen( $this->x_axis_3d ) > 0 )
-		$tmp[] = $this->format_output($output_type,'x_axis_3d',$this->x_axis_3d);
-
+			$tmp[] = $this->format_output('x_axis_3d',$this->x_axis_3d);
+		
 		if( strlen( $this->y_legend ) > 0 )
-		$tmp[] = $this->format_output($output_type,'y_legend',$this->y_legend);
-
+			$tmp[] = $this->format_output('y_legend',$this->y_legend);
+		
 		if( strlen( $this->y_legend_right ) > 0 )
-		$tmp[] = $this->format_output($output_type,'y2_legend',$this->y_legend_right);
+			$tmp[] = $this->format_output('y2_legend',$this->y_legend_right);
 
 		if( strlen( $this->y_label_style ) > 0 )
-		$tmp[] = $this->format_output($output_type,'y_label_style',$this->y_label_style);
+			$tmp[] = $this->format_output('y_label_style',$this->y_label_style);
 
 		$values = '5,10,'. $this->y_steps;
-		$tmp[] = $this->format_output($output_type,'y_ticks',$values);
+		$tmp[] = $this->format_output('y_ticks',$values);
 
 		if( count( $this->lines ) == 0 && count($this->data_sets)==0 )
 		{
-			$tmp[] = $this->format_output($output_type,$this->line_default['type'],$this->line_default['values']);
+			$tmp[] = $this->format_output($this->line_default['type'],$this->line_default['values']);	
 		}
 		else
 		{
 			foreach( $this->lines as $type=>$description )
-			$tmp[] = $this->format_output($output_type,$type,$description);
+				$tmp[] = $this->format_output($type,$description);	
 		}
-
+	
 		$num = 1;
 		foreach( $this->data as $data )
 		{
 			if( $num==1 )
 			{
-				$tmp[] = $this->format_output($output_type, 'values', $data);
+				$tmp[] = $this->format_output( 'values', $data);
 			}
 			else
 			{
-				$tmp[] = $this->format_output($output_type,'values_'. $num, $data);
+				$tmp[] = $this->format_output('values_'. $num, $data);
 			}
-
+		
 			$num++;
 		}
-
+		
 		$num = 1;
 		foreach( $this->links as $link )
 		{
 			if( $num==1 )
 			{
-				$tmp[] = $this->format_output($output_type, 'links', $link);
+				$tmp[] = $this->format_output( 'links', $link);
 			}
 			else
 			{
-				$tmp[] = $this->format_output($output_type,'links_'. $num, $link);
+				$tmp[] = $this->format_output('links_'. $num, $link);
 			}
-
+		
 			$num++;
 		}
 
 		if( count( $this->y2_lines ) > 0 )
 		{
-			$tmp[] = $this->format_output($output_type,'y2_lines',implode( ',', $this->y2_lines ));
+			$tmp[] = $this->format_output('y2_lines',implode( ',', $this->y2_lines ));
 			//
 			// Should this be an option? I think so...
 			//
-			$tmp[] = $this->format_output($output_type,'show_y2','true');
+			$tmp[] = $this->format_output('show_y2','true');
 		}
 
 		if( count( $this->x_labels ) > 0 )
-		$tmp[] = $this->format_output($output_type,'x_labels',implode(',',$this->x_labels));
+			$tmp[] = $this->format_output('x_labels',implode(',',$this->x_labels));
 		else
 		{
 			if( strlen($this->x_min) > 0 )
-			$tmp[] = $this->format_output($output_type,'x_min',$this->x_min);
-
+				$tmp[] = $this->format_output('x_min',$this->x_min);
+				
 			if( strlen($this->x_max) > 0 )
-			$tmp[] = $this->format_output($output_type,'x_max',$this->x_max);
+				$tmp[] = $this->format_output('x_max',$this->x_max);			
 		}
+		
+		$tmp[] = $this->format_output('y_min',$this->y_min);
+		$tmp[] = $this->format_output('y_max',$this->y_max);
 
-		$tmp[] = $this->format_output($output_type,'y_min',$this->y_min);
-		$tmp[] = $this->format_output($output_type,'y_max',$this->y_max);
-
 		if( strlen($this->y2_min) > 0 )
-		$tmp[] = $this->format_output($output_type,'y2_min',$this->y2_min);
+			$tmp[] = $this->format_output('y2_min',$this->y2_min);
 			
 		if( strlen($this->y2_max) > 0 )
-		$tmp[] = $this->format_output($output_type,'y2_max',$this->y2_max);
-
+			$tmp[] = $this->format_output('y2_max',$this->y2_max);
+		
 		if( strlen( $this->bg_colour ) > 0 )
-		$tmp[] = $this->format_output($output_type,'bg_colour',$this->bg_colour);
+			$tmp[] = $this->format_output('bg_colour',$this->bg_colour);
 
 		if( strlen( $this->bg_image ) > 0 )
 		{
-			$tmp[] = $this->format_output($output_type,'bg_image',$this->bg_image);
-			$tmp[] = $this->format_output($output_type,'bg_image_x',$this->bg_image_x);
-			$tmp[] = $this->format_output($output_type,'bg_image_y',$this->bg_image_y);
+			$tmp[] = $this->format_output('bg_image',$this->bg_image);
+			$tmp[] = $this->format_output('bg_image_x',$this->bg_image_x);
+			$tmp[] = $this->format_output('bg_image_y',$this->bg_image_y);
 		}
 
 		if( strlen( $this->x_axis_colour ) > 0 )
 		{
-			$tmp[] = $this->format_output($output_type,'x_axis_colour',$this->x_axis_colour);
-			$tmp[] = $this->format_output($output_type,'x_grid_colour',$this->x_grid_colour);
+			$tmp[] = $this->format_output('x_axis_colour',$this->x_axis_colour);
+			$tmp[] = $this->format_output('x_grid_colour',$this->x_grid_colour);
 		}
 
 		if( strlen( $this->y_axis_colour ) > 0 )
-		$tmp[] = $this->format_output($output_type,'y_axis_colour',$this->y_axis_colour);
+			$tmp[] = $this->format_output('y_axis_colour',$this->y_axis_colour);
 
 		if( strlen( $this->y_grid_colour ) > 0 )
-		$tmp[] = $this->format_output($output_type,'y_grid_colour',$this->y_grid_colour);
-
+			$tmp[] = $this->format_output('y_grid_colour',$this->y_grid_colour);
+  
 		if( strlen( $this->y2_axis_colour ) > 0 )
-		$tmp[] = $this->format_output($output_type,'y2_axis_colour',$this->y2_axis_colour);
-
+			$tmp[] = $this->format_output('y2_axis_colour',$this->y2_axis_colour);
+		
 		if( strlen( $this->x_offset ) > 0 )
-		$tmp[] = $this->format_output($output_type,'x_offset',$this->x_offset);
+			$tmp[] = $this->format_output('x_offset',$this->x_offset);
 
 		if( strlen( $this->inner_bg_colour ) > 0 )
 		{
@@ -1188,56 +1196,206 @@
 				$values .= ','. $this->inner_bg_colour_2;
 				$values .= ','. $this->inner_bg_angle;
 			}
-			$tmp[] = $this->format_output($output_type,'inner_background',$values);
+			$tmp[] = $this->format_output('inner_background',$values);
 		}
-
+	
 		if( strlen( $this->pie ) > 0 )
 		{
-			$tmp[] = $this->format_output($output_type,'pie',$this->pie);
-			$tmp[] = $this->format_output($output_type,'values',$this->pie_values);
-			$tmp[] = $this->format_output($output_type,'pie_labels',$this->pie_labels);
-			$tmp[] = $this->format_output($output_type,'colours',$this->pie_colours);
-			$tmp[] = $this->format_output($output_type,'links',$this->pie_links);
+			$tmp[] = $this->format_output('pie',$this->pie);
+			$tmp[] = $this->format_output('values',$this->pie_values);
+			$tmp[] = $this->format_output('pie_labels',$this->pie_labels);
+			$tmp[] = $this->format_output('colours',$this->pie_colours);
+			$tmp[] = $this->format_output('links',$this->pie_links);
 		}
 
 		if( strlen( $this->tool_tip ) > 0 )
-		$tmp[] = $this->format_output($output_type,'tool_tip',$this->tool_tip);
+			$tmp[] = $this->format_output('tool_tip',$this->tool_tip);
 			
 			
-
+		
 		if( strlen( $this->y_format ) > 0 )
-		$tmp[] = $this->format_output($output_type,'y_format',$this->y_format);
+			$tmp[] = $this->format_output('y_format',$this->y_format);
 			
 		if( strlen( $this->num_decimals ) > 0 )
-		$tmp[] = $this->format_output($output_type,'num_decimals',$this->num_decimals);
+			$tmp[] = $this->format_output('num_decimals',$this->num_decimals);
 			
 		if( strlen( $this->is_fixed_num_decimals_forced ) > 0 )
-		$tmp[] = $this->format_output($output_type,'is_fixed_num_decimals_forced',$this->is_fixed_num_decimals_forced);
+			$tmp[] = $this->format_output('is_fixed_num_decimals_forced',$this->is_fixed_num_decimals_forced);
 			
 		if( strlen( $this->is_decimal_separator_comma ) > 0 )
-		$tmp[] = $this->format_output($output_type,'is_decimal_separator_comma',$this->is_decimal_separator_comma);
+			$tmp[] = $this->format_output('is_decimal_separator_comma',$this->is_decimal_separator_comma);
 			
 		if( strlen( $this->is_thousand_separator_disabled ) > 0 )
-		$tmp[] = $this->format_output($output_type,'is_thousand_separator_disabled',$this->is_thousand_separator_disabled);
+			$tmp[] = $this->format_output('is_thousand_separator_disabled',$this->is_thousand_separator_disabled);
 
 
 		$count = 1;
 		foreach( $this->data_sets as $set )
 		{
-			$tmp[] = $set->toString( $output_type, $count>1?'_'.$count:'' );
+			$tmp[] = $set->toString( $this->output_type, $count>1?'_'.$count:'' );
 			$count++;
 		}
-
-		if($output_type == 'js')
+		
+		if($this->output_type == 'js')
 		{
-			$tmp[] = 'so.write("my_chart' . $this->occurence . '");';
+			$tmp[] = 'so.write("' . $this->unique_id . '");';
 			$tmp[] = '</script>';
 		}
-
+		
 		return implode("\r\n",$tmp);
 	}
 }
 
+class line
+{
+	var $line_width;
+	var $colour;
+	var $_key;
+	var $key;
+	var $key_size;
+	// hold the data
+	var $data;
+	// extra tool tip info:
+	var $tips;
+	
+	function line( $line_width, $colour )
+	{
+		$this->var = 'line';
+		
+		$this->line_width = $line_width;
+		$this->colour = $colour;
+		$this->data = array();
+		$this->links = array();
+		$this->tips = array();
+		$this->_key = false;
+	}
+
+
+	function key( $key, $size )
+	{
+		$this->_key = true;
+		$this->key = graph::esc( $key );
+		$this->key_size = $size;
+	}
+	
+	function add( $data )
+	{
+		$this->data[] = $data;
+	}
+	
+	function add_link( $data, $link )
+	{
+		$this->data[] = $data;
+		$this->links[] = graph::esc( $link );
+	}
+	
+	function add_data_tip( $data, $tip )
+	{
+		$this->data[] = $data;
+		$this->tips[] = graph::esc( $tip );
+	}
+	
+	function add_data_link_tip( $data, $link, $tip )
+	{
+		$this->data[] = $data;
+		$this->links[] = graph::esc( $link );
+		$this->tips[] = graph::esc( $tip );
+	}
+	
+	// return the variables for this chart
+	function _get_variable_list()
+	{
+		$values = array();
+		$values[] = $this->line_width;
+		$values[] = $this->colour;
+		
+		if( $this->_key )
+		{
+			$values[] = $this->key;
+			$values[] = $this->key_size;
+		}
+		
+		return $values;
+	}
+	
+	function toString( $output_type, $set_num )
+	{
+		$values = implode( ',', $this->_get_variable_list() );
+		
+		$tmp = array();
+		
+		if( $output_type == 'js' )
+		{
+			$tmp[] = 'so.addVariable("'. $this->var.$set_num .'","'. $values . '");'; 
+
+			$tmp[] = 'so.addVariable("values'. $set_num .'","'. implode( ',', $this->data ) .'");';
+			
+			if( count( $this->links ) > 0 )
+				$tmp[] = 'so.addVariable("links'. $set_num .'","'. implode( ',', $this->links ) .'");';
+				
+			if( count( $this->tips ) > 0 )
+				$tmp[] = 'so.addVariable("tool_tips_set'. $set_num .'","'. implode( ',', $this->tips ) .'");';
+
+		}
+		else
+		{
+			$tmp[]  = '&'. $this->var. $set_num .'='. $values .'&';
+			$tmp[] = '&values'. $set_num .'='. implode( ',', $this->data ) .'&';
+			
+			if( count( $this->links ) > 0 )
+				$tmp[] = '&links'. $set_num .'='. implode( ',', $this->links ) .'&';
+				
+			if( count( $this->tips ) > 0 )
+				$tmp[] = '&tool_tips_set'. $set_num .'='. implode( ',', $this->tips ) .'&';	
+		}
+
+		return implode( "\r\n", $tmp );
+	}
+}
+
+class line_hollow extends line
+{
+	var $dot_size;
+	
+	function line_hollow( $line_width, $dot_size, $colour )
+	{
+		parent::line( $line_width, $colour );
+		$this->var = 'line_hollow';
+		$this->dot_size = $dot_size;
+	}
+	
+	// return the variables for this chart
+	function _get_variable_list()
+	{
+		$values = array();
+		$values[] = $this->line_width;
+		$values[] = $this->colour;
+		
+		if( $this->_key )
+		{
+			$values[] = $this->key;
+			$values[] = $this->key_size;
+		}
+		else
+		{
+			$values[] = '';
+			$values[] = '';
+		}
+		$values[] = $this->dot_size;
+		
+		return $values;
+	}
+}
+
+class line_dot extends line_hollow
+{
+	function line_dot( $line_width, $dot_size, $colour )
+	{
+		parent::line_hollow( $line_width, $dot_size,$colour );
+		$this->var = 'line_dot';
+	}
+}
+
 class bar
 {
 	var $colour;
@@ -1248,15 +1406,18 @@
 	var $key;
 	var $key_size;
 	var $var;
-
+	// extra tool tip info:
+	var $tips;
+	
 	function bar( $alpha, $colour )
 	{
 		$this->var = 'bar';
-
+		
 		$this->alpha = $alpha;
 		$this->colour = $colour;
 		$this->data = array();
 		$this->links = array();
+		$this->tips = array();
 		$this->_key = false;
 	}
 
@@ -1266,13 +1427,24 @@
 		$this->key = graph::esc( $key );
 		$this->key_size = $size;
 	}
+	
+	function add( $data )
+	{
+		$this->data[] = $data;
+	}
 
-	function add( $data, $link )
+	function add_link( $data, $link )
 	{
 		$this->data[] = $data;
-		$this->links[] = $link;
+		$this->links[] = graph::esc( $link );
 	}
-
+	
+	function add_data_tip( $data, $tip )
+	{
+		$this->data[] = $data;
+		$this->tips[] = graph::esc( $tip );
+	}
+	
 	// return the variables for this
 	// bar chart
 	function _get_variable_list()
@@ -1280,44 +1452,50 @@
 		$values = array();
 		$values[] = $this->alpha;
 		$values[] = $this->colour;
-
+		
 		if( $this->_key )
 		{
 			$values[] = $this->key;
 			$values[] = $this->key_size;
 		}
-
+		
 		return $values;
 	}
-
+	
 	function toString( $output_type, $set_num )
 	{
 		$values = implode( ',', $this->_get_variable_list() );
-
+		
 		$tmp = array();
-
+		
 		if( $output_type == 'js' )
 		{
-			$tmp[] = 'so.addVariable("'. $this->var .'","'. $values . '");';
+			$tmp[] = 'so.addVariable("'. $this->var.$set_num .'","'. $values . '");'; 
 
 			$tmp[] = 'so.addVariable("values'. $set_num .'","'. implode( ',', $this->data ) .'");';
+			
+			if( count( $this->links ) > 0 )
+				$tmp[] = 'so.addVariable("links'. $set_num .'","'. implode( ',', $this->links ) .'");';
 				
-			if( count( $this->links ) > 0 )
-			$tmp[] = 'so.addVariable("values'. $set_num .'","'. implode( ',', $this->links ) .'");';
+			if( count( $this->tips ) > 0 )
+				$tmp[] = 'so.addVariable("tool_tips_set'. $set_num .'","'. implode( ',', $this->tips ) .'");';
 
 		}
 		else
 		{
 			$tmp[]  = '&'. $this->var. $set_num .'='. $values .'&';
 			$tmp[] = '&values'. $set_num .'='. implode( ',', $this->data ) .'&';
+			
+			if( count( $this->links ) > 0 )
+				$tmp[] = '&links'. $set_num .'='. implode( ',', $this->links ) .'&';
 				
-			if( count( $this->links ) > 0 )
-			$tmp[] = '&links'. $set_num .'='. implode( ',', $this->links ) .'&';
+			if( count( $this->tips ) > 0 )
+				$tmp[] = '&tool_tips_set'. $set_num .'='. implode( ',', $this->tips ) .'&';	
 		}
 
 		return implode( "\r\n", $tmp );
 	}
-
+	
 }
 
 class bar_3d extends bar
@@ -1341,14 +1519,14 @@
 class bar_outline extends bar
 {
 	var $outline_colour;
-
+	
 	function bar_outline( $alpha, $colour, $outline_colour )
 	{
 		parent::bar( $alpha, $colour );
 		$this->var = 'filled_bar';
 		$this->outline_colour = $outline_colour;
 	}
-
+	
 	// override the base method
 	function _get_variable_list()
 	{
@@ -1356,13 +1534,13 @@
 		$values[] = $this->alpha;
 		$values[] = $this->colour;
 		$values[] = $this->outline_colour;
-
+		
 		if( $this->_key )
 		{
 			$values[] = $this->key;
 			$values[] = $this->key_size;
 		}
-
+		
 		return $values;
 	}
 }
@@ -1383,14 +1561,14 @@
 class bar_sketch extends bar_outline
 {
 	var $offset;
-
+	
 	function bar_sketch( $alpha, $offset, $colour, $outline_colour )
 	{
 		parent::bar_outline( $alpha, $colour, $outline_colour );
 		$this->var = 'bar_sketch';
 		$this->offset = $offset;
 	}
-
+	
 	// override the base method
 	function _get_variable_list()
 	{
@@ -1399,13 +1577,13 @@
 		$values[] = $this->offset;
 		$values[] = $this->colour;
 		$values[] = $this->outline_colour;
-
+		
 		if( $this->_key )
 		{
 			$values[] = $this->key;
 			$values[] = $this->key_size;
 		}
-
+		
 		return $values;
 	}
 }
@@ -1413,7 +1591,7 @@
 class candle
 {
 	var $out;
-
+	
 	function candle( $high, $open, $close, $low )
 	{
 		$this->out = array();
@@ -1422,7 +1600,7 @@
 		$this->out[] = $close;
 		$this->out[] = $low;
 	}
-
+	
 	function toString()
 	{
 		return '['. implode( ',', $this->out ) .']';
@@ -1432,7 +1610,7 @@
 class hlc
 {
 	var $out;
-
+	
 	function hlc( $high, $low, $close )
 	{
 		$this->out = array();
@@ -1440,7 +1618,7 @@
 		$this->out[] = $low;
 		$this->out[] = $close;
 	}
-
+	
 	function toString()
 	{
 		return '['. implode( ',', $this->out ) .']';
@@ -1450,7 +1628,7 @@
 class point
 {
 	var $out;
-
+	
 	function point( $x, $y, $size_px )
 	{
 		$this->out = array();
@@ -1458,10 +1636,12 @@
 		$this->out[] = $y;
 		$this->out[] = $size_px;
 	}
-
+	
 	function toString()
 	{
 		return '['. implode( ',', $this->out ) .']';
 	}
 }
- 
\ No newline at end of file
+
+// PIWIK SPECIAL ALIAS HACK - when updating Open Flash Chart, leave this line unchanged
+class graph extends Piwik_Visualization_OpenFlashChart {}
\ No newline at end of file

Added: trunk/modules/Visualization/Sparkline.php
===================================================================
--- trunk/modules/Visualization/Sparkline.php	                        (rev 0)
+++ trunk/modules/Visualization/Sparkline.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -0,0 +1,94 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id: OpenFlashChart.php 386 2008-03-18 19:27:54Z julien $
+ *
+ * @package Piwik_Visualization
+ */
+
+require_once 'sparkline/lib/Sparkline_Line.php';
+
+
+/**
+ * Renders a sparkline image given a PHP data array.
+ * Using the Sparkline PHP Graphing Library sparkline.org 
+ * 
+ * @package Piwik_Visualization
+ */
+class Piwik_Visualization_Sparkline implements Piwik_iView
+{
+	/**
+	 * Sets data. Must have format: array( array('value' => X),array('value' =>Y ), ...)
+	 *
+	 * @param array $data
+	 */
+	function setData($data)
+	{
+		$this->data = $data;
+	}
+	
+	
+	function main()
+	{
+		$data = $this->data;
+		$sparkline = new Sparkline_Line();
+		
+		$sparkline->SetColor('lineColor', 22,44,74); // dark blue
+		$sparkline->SetColorHtml('red', '#FF7F7F');
+		$sparkline->SetColorHtml('blue', '#55AAFF');
+		$sparkline->SetColorHtml('green', '#75BF7C');
+//		$sparkline->SetDebugLevel(DEBUG_NONE);
+//		$sparkline->SetDebugLevel(DEBUG_ERROR | DEBUG_WARNING | DEBUG_STATS | DEBUG_CALLS | DEBUG_DRAW, 'log.txt');
+		
+		$data = array_reverse($data);
+		$min = $max= $last = null;
+		$i = 0;
+		
+		foreach($this->data as $row)
+		{
+			$value = $row['value'];
+					
+			$sparkline->SetData($i, $value);
+			if(	null == $min || $value <= $min[1])
+			{
+				$min = array($i, $value);
+			}
+		
+			if(null == $max || $value >= $max[1]) 
+			{
+				$max = array($i, $value);
+			}
+		
+			$last = array($i, $value);
+			
+			$i++;			
+		}
+//		echo imagefontwidth(FONT_2);exit;
+		// set y-bound, min and max extent lines
+		//
+		$sparkline->SetYMin(0);
+//		$sparkline->SetYMax($max);
+		$sparkline->SetPadding(2); // setpadding is additive
+		$sparkline->SetPadding(0,//13,//font height 
+					3,//4 * (strlen("$last[1]")), 
+					0, //imagefontheight(FONT_2), 
+					0);
+		$font = FONT_2;
+		$sparkline->SetFeaturePoint($min[0]-1,$min[1],'red', 5);//, $min[1], TEXT_TOP,$font);
+		$sparkline->SetFeaturePoint($max[0]-1,$max[1],  'green', 5);//, $max[1], TEXT_TOP,$font);
+		$sparkline->SetFeaturePoint($last[0]-1, $last[1], 'blue',5);//, " $last[1]", TEXT_RIGHT,$font);
+		
+		$sparkline->SetLineSize(3); // for renderresampled, linesize is on virtual image
+		$sparkline->RenderResampled(100, 20, 'lineColor');
+		
+		$this->sparkline = $sparkline;
+	}
+	
+	function render()
+	{
+		$this->sparkline->Output();
+	}
+}
\ No newline at end of file

Modified: trunk/plugins/Actions/Controller.php
===================================================================
--- trunk/plugins/Actions/Controller.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/plugins/Actions/Controller.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -18,7 +18,6 @@
 		$view->setLimit( 15 );
 		$view->disableSort();
 		
-		$view->main();
 		return $this->renderView($view, $fetch);
 	}
 	function getDownloadsSubDataTable($fetch = false)
@@ -75,7 +74,6 @@
 		$view->setLimit( 15 );
 		$view->disableSort();
 		
-		$view->main();
 		return $this->renderView($view, $fetch);
 	}
 	function getOutlinksSubDataTable($fetch = false)
@@ -93,7 +91,6 @@
 		$view->setLimit( 15 );
 		$view->disableSort();
 		
-		$view->main();
 		return $this->renderView($view, $fetch);
 	}
 	
@@ -126,9 +123,8 @@
 		{
 			$view->setTemplate('Home/templates/datatable_actions_subdatable.tpl');
 		}
-		$view->setSearchRecursive();
+		$currentlySearching = $view->setSearchRecursive();
 		
-		$currentlySearching = $view->setRecursiveLoadDataTableIfSearchingForPattern();
 		if($currentlySearching)
 		{
 			$view->setTemplate('Home/templates/datatable_actions_recursive.tpl');

Modified: trunk/plugins/Provider/Controller.php
===================================================================
--- trunk/plugins/Provider/Controller.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/plugins/Provider/Controller.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -16,7 +16,6 @@
 		$view->setSortedColumn( 1 );
 		$view->setLimit( 5 );
 		
-		$view->main();
 		return $this->renderView($view, $fetch);
 	}
 	

Modified: trunk/plugins/Referers/Controller.php
===================================================================
--- trunk/plugins/Referers/Controller.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/plugins/Referers/Controller.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -57,7 +57,7 @@
 	 */
 	function getRefererType( $fetch = false)
 	{
-		$view = Piwik_ViewDataTable::factory(null, 'cloud');
+		$view = Piwik_ViewDataTable::factory('cloud');
 		$view->init( $this->pluginName,  	
 									'getRefererType', 
 									'Referers.getRefererType'
@@ -81,6 +81,7 @@
 											'getSearchEnginesFromKeywordId'
 								);
 		$view->disableExcludeLowPopulation();
+		
 		$view->setColumnsToDisplay( array('label','nb_visits') );
 
 		return $this->renderView($view, $fetch);

Modified: trunk/plugins/UserCountry/UserCountry.php
===================================================================
--- trunk/plugins/UserCountry/UserCountry.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/plugins/UserCountry/UserCountry.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -126,7 +126,7 @@
 	
 	function getContinent( $fetch = false)
 	{
-		$view = Piwik_ViewDataTable::factory( null, 'graphVerticalBar' );
+		$view = Piwik_ViewDataTable::factory( 'graphVerticalBar' );
 		$view->init( 'UserCountry', __FUNCTION__, "UserCountry.getContinent" );
 		$view->disableExcludeLowPopulation();
 		$view->disableSearchBox();

Modified: trunk/plugins/UserSettings/Controller.php
===================================================================
--- trunk/plugins/UserSettings/Controller.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/plugins/UserSettings/Controller.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -27,7 +27,7 @@
 												$APItoCall,
 												$defaultDatatableType = null )
 	{
-		$view = Piwik_ViewDataTable::factory( null, $defaultDatatableType);
+		$view = Piwik_ViewDataTable::factory( $defaultDatatableType);
 		$view->init( $this->pluginName,  $currentControllerAction, $APItoCall );
 		$view->disableSearchBox();
 		$view->disableExcludeLowPopulation();
@@ -100,7 +100,7 @@
 	
 	function getPlugin( $fetch = false)
 	{
-		$view = Piwik_ViewDataTable::factory( null, 'graphVerticalBar');
+		$view = Piwik_ViewDataTable::factory( 'graphVerticalBar');
 		$view->init( $this->pluginName,  __FUNCTION__, 'UserSettings.getPlugin' );
 		$view->disableSearchBox();
 		$view->disableExcludeLowPopulation();
@@ -108,7 +108,7 @@
 		$view->disableOffsetInformation();
 		
 		$view->setColumnsToDisplay( array('label','nb_visits') );
-		$view->setSortedColumn( 2 );
+		$view->setSortedColumn( 'nb_visits' );
 		$view->setGraphLimit( 10 );
 		$view->setLimit( 10 );
 		

Modified: trunk/plugins/VisitTime/Controller.php
===================================================================
--- trunk/plugins/VisitTime/Controller.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/plugins/VisitTime/Controller.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -19,7 +19,7 @@
 	 */
 	function getVisitInformationPerServerTime( $fetch = false)
 	{
-		$view = Piwik_ViewDataTable::factory(null, 'graphVerticalBar');
+		$view = Piwik_ViewDataTable::factory( 'graphVerticalBar');
 		$view->init( $this->pluginName,  __FUNCTION__, 
 								"VisitTime.getVisitInformationPerServerTime" );
 		
@@ -36,7 +36,7 @@
 	
 	function getVisitInformationPerLocalTime( $fetch = false)
 	{
-		$view = Piwik_ViewDataTable::factory(null, 'graphVerticalBar');
+		$view = Piwik_ViewDataTable::factory( 'graphVerticalBar');
 		$view->init( $this->pluginName,  __FUNCTION__, 
 								"VisitTime.getVisitInformationPerLocalTime" );
 		

Modified: trunk/plugins/VisitorInterest/Controller.php
===================================================================
--- trunk/plugins/VisitorInterest/Controller.php	2008-03-23 01:47:17 UTC (rev 409)
+++ trunk/plugins/VisitorInterest/Controller.php	2008-03-26 01:38:45 UTC (rev 410)
@@ -19,7 +19,7 @@
 	 */
 	function getNumberOfVi