<?php
/**
 * @version		$Id: scatter.php 135 2009-06-25 04:32:04Z eddieajau $
 * @copyright	Copyright (C) 2009 New Life in IT Pty Ltd. All rights reserved.
 * @license		GNU General Public License <http://www.gnu.org/copyleft/gpl.html>
 * @link		http://www.theartofjoomla.com
 */

// no direct access
defined('_JEXEC') or die;

JLoader::import('chart', JPATH_QUANTA.DS.'libraries');

/**
 * Scatter chart helper
 *
 * @package		TAOJ.Quanta
 * @subpackage	com_quanta
 */
class JChartScatter extends JChart
{
	/**
	 * @var	array	The available sub-types for this chart type.
	 */
	protected $_subtypes = array('line');

	/**
	 * Initialise the chart
	 */
	function _initialise()
	{
		// Load the chart dependancies (need to use a value before we add the chart).
		OFC_Chart::getInstance('Scatter');

		// Load the framework dependancies
		jimport('joomla.utilities.date');

		// Initialise variables.
		$app		= &JFactory::getApplication();
		$offset		= $app->getCfg('offset');
		$data		= array();
		$labels		= array();
		$xMin		= null;
		$xMax		= null;
		$yMin		= 0;
		$yMax		= 0;
		$rangeMode	= $this->_params->get('chart-range_mode', 1);
		$tipFormat	= $this->_params->get('chart-tip_format', '#val# of #total#<br>#percent# of 100%');

		// Loop through the items to group by set and find extrema.
		foreach ($this->_points as &$point)
		{
			// Create a shortcut to the set.
			$set = &$this->_sets[$point->set_id];

			// Compute the X-Value
			$time	= new JDate($point->x, $offset);
			$x		= $time->toUnix();

			$xMin = ($xMin === null) ? $x : min($xMin, $x);
			$xMax = ($xMax === null) ? $x : max($xMax, $x);

			// Avoid division by zero errors.
			if ($set->y_max == 0) {
				$relative = 0;
			}
			else {
				$relative = $point->y/$set->y_max*100.0;
			}
			$yMin = ($yMin === null) ? $point->y : min($yMin, $point->y);

			if ($rangeMode == 2)
			{
				// Find the extrema of the item maxima.
				$yMax	= 100;
				$value	= new OFC_Charts_Scatter_Value($x, $relative);
			}
			else if ($rangeMode == 1)
			{
				// Find the extrema of the item maxima.
				$yMax	= max($yMax, $set->y_max);
				$value	= new OFC_Charts_Scatter_Value($x, (double) $point->y);
			}
			else
			{
				// Find the extrema of the plotted values.
				$yMax	= max($yMax, $point->y);
				$value	= new OFC_Charts_Scatter_Value($x, (double) $point->y);
			}

			if ($tipFormat)
			{
				$tip = str_replace(
					array('#title#', '#val#', '#total#', '#percent#'),
					array(htmlspecialchars($set->title, ENT_QUOTES, 'utf-8'), number_format($point->y), number_format($set->y_max), sprintf('%.1f', $relative)),
					$tipFormat
				);

				$value->set_tooltip($tip);
			}

			if (!isset($data[$point->set_id])) {
				$data[$point->set_id] = array();
			}

			array_push($data[$point->set_id],	$value);
			//array_push($labels,	$point->label ? $point->label : $point->title);
		}

		//
		// Configure the chart.
		//

		// Chart title.
		if ($v = $this->_params->get('chart-title')) {
			$this->_chart->set_title($v);
		}

		// Chart background colour.
		if ($v = $this->_params->get('chart-bgcolour')) {
			$this->_chart->set_bg_colour($v);
		}

		// Chart data.
		foreach ($data as $setId => &$values)
		{
			$set = &$this->_sets[$setId];

			// Create an instance of the chart type.
			$scatter = OFC_Chart::getInstance('Scatter', $this->_subtype);
			$scatter->set_values($values);

			// Workaround bug in OFC2 to display a solid line.
			$scatter->set_default_dot_style(new OFC_Charts_Scatter_Hollow_Dot(0, 0));

			// Set the line colour based from the record _params.
			$scatter->set_colour($set->params->get('chart-set_colour'));

			$this->_chart->add_element($scatter);
		}

		// Setup the X-Axis.
		$this->_setXAxis($xMin, $xMax);

		// Setup the Y-Axis.
		$this->_setYAxis($yMin, $yMax);
	}

	/**
	 * Configures the X-Axis of the chart
	 *
	 * @param	object	The chart object
	 * @param	double	The minimum range of the x-axis
	 * @param	double	The maximum range of the x-axis
	 */
	protected function _setXAxis($xMin, $xMax)
	{
		parent::_setXAxis();

		// Round the xMin down to the nearest day
		if ($xMin % 86400) {
			$xMin = round($xMin / 86400) * 86400;
		}

		// Round the xMax up to the nearest day
		if ($xMax % 86400) {
			$xMax = (round($xMax / 86400) + 1) * 86400;
		}

		// Compute the absolute value of the step.
		$steps	= ($xMax - $xMin) / 10;
		$labels	= new OFC_Elements_Axis_X_Labels();
		$labels
			->set_text('#date:d M#')
			->set_steps($steps)
			->set_visible_steps(2)
			->set_rotate(270);
		$x = new OFC_Elements_Axis_X();
		$x->set_range($xMin, $xMax, $steps)
			->set_labels($labels);

		$this->_chart->set_x_axis($x);
	}

	/**
	 * Configures the Y-Axis of the chart
	 *
	 * @param	double	The minimum range of the y-axis
	 * @param	double	The maximum range of the y-axis
	 */
	protected function _setYAxis($yMin, $yMax)
	{
		parent::_setXAxis();

		// Adjust the Y-Axis Range
		$rangeMode	= $this->_params->get('chart-range_mode');
		$round		= $this->_params->get('chart-y_round');
		if ($round > 0 && $rangeMode < 2)
		{
			if ($round == 2)
			{
				foreach ($this->_sets as &$set) {
					$yMax = max($yMax, $set->y_max);
				}
			}

			// Round up to the nearset lower order of magitude
			// eg, round 2535 up to 3000.
			$mag	= floor(log10($yMax));
			$inc	= pow(10, $mag);
			$yMax	= round($yMax + $inc/2, -$mag);
		}

		$y		= new OFC_Elements_Axis_Y;
		$ySteps	= (int) $this->_params->get('chart-y_steps', 5);
		$y->set_range($yMin, $yMax, ($yMax - $yMin)/$ySteps);

		// Add the Y Axis object to the chart:
		$this->_chart->set_y_axis($y);
	}
}
