<?php
/**
 * Auto generation of graphics using Google Graphs or JPGraph.
 *
 * @author Camilo Carromeu <camilo@carromeu.com>
 * @category class
 * @package core
 * @subpackage form
 * @copyright 2005-2017 Titan Framework
 * @license http://www.titanframework.com/license/ BSD License (3 Clause)
 * @see Form, View, Instance, Business
 */
class Graph
{
	private $file = '';

	private $primary = '';

	private $table = '';

	public $fields = array ();

	protected $groups = array ();

	protected $groupsInfo = array ();

	private $sth = NULL;

	private $default = FALSE;

	private $sql = FALSE;

	private $where = '';

	private $total = NULL;

	private $type = 'PIE';

	const JPGRAPH = '__JPGRAPH__';
	const GOOGLE  = '__GOOGLE__';

	public function __construct ()
	{
		global $section, $action;

		$args = func_get_args();

		$fileName = FALSE;

		if ($action->getXmlPath () !== FALSE && trim ($action->getXmlPath ()) != '')
			array_unshift ($args, $action->getXmlPath ());

		foreach ($args as $trash => $arg)
		{
			if (!file_exists ('section/'. $section->getName () .'/'. $arg))
				continue;

			$fileName = $arg;

			break;
		}

		if ($fileName === FALSE)
			throw new Exception ('Arquivo XML não encontrado em [section/'. $section->getName () .'/].');

		$file = 'section/'. $section->getName () .'/'. $fileName;

		$cacheFile = Instance::singleton ()->getCachePath () .'parsed/'. fileName ($file) .'_'. md5_file ($file) .'.php';

		if (file_exists ($cacheFile))
			$array = include $cacheFile;
		else
		{
			$xml = new Xml ($file);

			$array = $xml->getArray ();

			if (!isset ($array ['form'][0]))
				throw new Exception ('A tag &lt;form&gt;&lt;/form&gt; não foi encontrada no XML ['. $fileName .']!');

			xmlCache ($cacheFile, $array);
		}

		$array = $array ['form'][0];

		$this->file = $fileName;

		if (array_key_exists ('table', $array))
			$this->table = $array ['table'];

		if (array_key_exists ('primary', $array))
			$this->primary = $array ['primary'];

		$user = User::singleton ();

		$groupId = 0;

		$this->groupsInfo [$groupId] = array ();

		if (array_key_exists ('field', $array) && is_array ($array ['field']))
			foreach ($array ['field'] as $trash => $field)
				if ($obj = Type::factory ($this->getTable (), $field))
				{
					if (!$obj->forGraph ())
						continue;

					while ($perm = $obj->getRestrict ())
						if (!$user->hasPermission ($perm))
							continue 2;

					$this->fields [$obj->getAssign ()] = $obj;
					$this->groups [$groupId][] = $obj->getAssign ();
				}

		if (array_key_exists ('group', $array) && is_array ($array ['group']))
			foreach ($array ['group'] as $trash => $group)
			{
				$groupId++;

				if (array_key_exists ('label', $group))
					$label = $group ['label'];
				else
					$label = '';

				if (array_key_exists ('display', $group))
					$display = $group ['display'];
				else
					$display = 'visible';

				$this->groupsInfo [$groupId] = array ($groupId, $label, $display);

				if (array_key_exists ('field', $group) && is_array ($group ['field']))
					foreach ($group ['field'] as $trash => $field)
						if ($obj = Type::factory ($this->getTable (), $field))
						{
							if (!$obj->forGraph ())
								continue;

							while ($perm = $obj->getRestrict ())
								if (!$user->hasPermission ($perm))
									continue 2;

							$this->fields [$obj->getAssign ()] = $obj;
							$this->groups [$groupId][] = $obj->getAssign ();
						}
			}

		reset ($this->fields);
		reset ($this->groupsInfo);
		reset ($this->groups);
	}

	public function setType ($type)
	{
		$valid = array ('PIE', 'BAR');

		if (!in_array ($type, $valid))
			return FALSE;

		$this->type = $type;

		return TRUE;
	}

	public function getType ()
	{
		return $this->type;
	}

	public function getFile ()
	{
		return $this->file;
	}

	public function getTable ()
	{
		return $this->table;
	}

	public function setTable ($table)
	{
		$this->table = $table;
	}

	public function getPrimary ()
	{
		return $this->primary;
	}

	public function getFields ()
	{
		return $this->fields;
	}

	public function getId ()
	{
		return $this->itemId;
	}

	public function getSth ()
	{
		return $this->sth;
	}

	public function getGroup ()
	{
		$group = each ($this->groupsInfo);

		if ($group !== FALSE)
			return new Group ($group ['value']);

		reset ($this->groupsInfo);

		return NULL;
	}

	public function getGraph ($assign = FALSE, $group = FALSE, $where = '', $type = self::JPGRAPH)
	{
		if ($assign !== FALSE)
		{
			if (array_key_exists ($assign, $this->fields))
				return $this->makeGraph ($this->fields [$assign], $where, $type);

			return NULL;
		}

		$field = each ($this->fields);

		while ($field !== FALSE)
		{
			if ($group === FALSE || (array_key_exists ($group, $this->groups) && in_array ($field ['value']->getAssign (), $this->groups [$group])))
				return $this->makeGraph ($field ['value'], $where, $type);

			$field = each ($this->fields);
		}

		reset ($this->fields);

		return NULL;
	}

	private function makeGraph ($field, $where, $type = self::JPGRAPH)
	{
		$db = Database::singleton ();

		$column = $field->getColumn ();
		$title = $field->getLabel ();

		$unique = '_result_'. randomHash (12);

		$sql = "
			(SELECT ". $field->getTable () .".". $column .", count(". $field->getTable () .".". $column .") AS ". $unique ." FROM ". $this->getTable () . (trim ($where) != '' ? " WHERE ". $where : "") . " GROUP BY ". $field->getTable () .".". $column .")
			UNION
			(SELECT NULL AS ". $column .", count(*) AS ". $unique ." FROM ". $this->getTable () ." WHERE ". $field->getTable () .".". $column ." IS NULL". (trim ($where) != '' ? " AND ". $where : "") . ")
		";

		$sth = $db->prepare ($sql);

		$sth->execute ();

		$pieces = array ();
		$legends = array ();

		while ($obj = $sth->fetch (PDO::FETCH_OBJ))
		{
			if (is_null ($obj->$column) && !(int) $obj->$unique)
				continue;

			$field = Database::fromDb ($field, $obj);

			if (trim ((string) $obj->$column) == '')
				$legends [] = __ ('N/A');
			else
				$legends [] = Form::toText ($field);

			$pieces [] = $obj->$unique;
		}

		if (!sizeof ($pieces))
			return 'titan.php?target=graph&type='. $this->getType () .'&title='. $title;

		switch ($type)
		{
			case self::GOOGLE:
				$total = array_sum ($pieces);

				$percent = array ();

				foreach ($pieces as $key => $value)
				{
					$percent [$key] = number_format ($value * 100 / $total, 1);
					$legends [$key] = urlencode (removeAccents ($legends [$key]) .' ('. $percent [$key] .'%)');
				}

				return 'http://chart.apis.google.com/chart?cht=p3&chd=t:'. implode (',', $percent) .'&chs=800x200&chl='. implode ('|', $legends) .'&chdl='. implode ('|', $pieces) .'&chtt='. urlencode (removeAccents ($title));

			default:
				foreach ($legends as $key => $value)
					$legends [$key] = urlencode ($value);

				return 'titan.php?target=graph&type='. $this->getType () .'&pieces[]='. implode ('&pieces[]=', $pieces) . '&title='. $title .'&legends[]='. implode ('&legends[]=', $legends);
		}
	}
}