<?php
/**
 * Implements auto generation of user manual using markdown with library TypeFriendly.
 *
 * @author Camilo Carromeu <camilo@carromeu.com>
 * @category class
 * @package core
 * @subpackage business
 * @copyright 2005-2017 Titan Framework
 * @license http://www.titanframework.com/license/ BSD License (3 Clause)
 * @see Section, Action, Business, Instance
 * @link http://www.titanframework.com/docs/tutorials/manual/
 * @link https://github.com/TypeFriendly/TypeFriendly
 */
class Manual
{
	static private $mapping = array (
		'en_US' => 'en',
		'es_ES' => 'en',
		'pt_BR' => 'pt-BR'
	);

	static private $default = array (
		'title' => '',
		 'version' => '1.0',
		 'copyright' => 'Camilo Carromeu',
		 'copyrightLink' => 'http://www.carromeu.com/',
		 'license' => 'Creative Commons BY-ND 2.5 Brazil License',
		 'licenseLink' => 'http://creativecommons.org/licenses/by-nd/2.5/br/',
		 'projectType' => 'manual',
		 'outputs' => 'xhtml_single',
		 'baseLanguage' => 'en',
		 'navigation' => 'book',
		 'showNumbers' => 'true',
		 'versionControlInfo' => 'false'
	 );

	static public function generate ()
	{
		$instance = Instance::singleton ();

		$languages = array ('en', 'pt-BR');

		$path = $instance->getCachePath () .'doc/';

		if (!file_exists ($path) && !@mkdir ($path, 0777))
			throw new Exception (__ ('Impossible to create directory! [[1]]', $path));

		if (!file_exists ($path .'input') && !@mkdir ($path .'input', 0777))
			throw new Exception (__ ('Impossible to create directory! [[1]]', $path .'input'));

		if (!file_exists ($path .'output') && !@mkdir ($path .'output', 0777))
			throw new Exception (__ ('Impossible to create directory! [[1]]', $path .'output'));

		$originalLanguage = Localization::singleton ()->getLanguage ();

		foreach (self::$mapping as $language => $lang)
		{
			if (!file_exists ($path .'input/'. $lang) && !@mkdir ($path .'input/'. $lang, 0777))
				throw new Exception (__ ('Impossible to create directory! [[1]]', $path .'input/'. $lang));

			if (!file_exists ($path .'input/'. $lang .'/media') && !@mkdir ($path .'input/'. $lang .'/media', 0777))
				throw new Exception (__ ('Impossible to create directory! [[1]]', $path .'input/'. $lang .'/media'));

			$settings = self::$default;

			$settings ['title'] = $instance->getName ();

			$pathCustomDoc = Instance::singleton ()->getDocPath ();

			if (file_exists ($pathCustomDoc .'settings.ini'))
				copy ($pathCustomDoc .'settings.ini', $path .'settings.ini');
			elseif (!file_exists ($path .'settings.ini'))
				self::makeIniFile ($settings, $path .'settings.ini');

			Localization::singleton ()->setLanguage ($language);

			Business::reload ();

			self::generateSections ($language, $path);

			// self::generateTypes ($language, $path);

			if (file_exists ($pathCustomDoc .'input/'. self::$mapping [$language] .'/media/'))
				copyDir ($pathCustomDoc .'input/'. self::$mapping [$language] .'/media/', $path .'input/'. self::$mapping [$language] .'/media/');

			set_error_handler ('logPhpError');

			$errors = array ();

			$commands = array ('php', '/usr/bin/php', '/usr/local/bin/php');

			foreach ($commands as $trash => $cmd)
			{
				$line = exec ($cmd .' '. $instance->getCorePath () .'extra/TypeFriendly/typefriendly.php build "'. $path .'" -l '. $lang .' -o xhtml_single > '. $path .'log', $output, $return);

				if (is_dir ($path .'output/xhtml_single'))
					break;

				toLog ('Error on shell command. Last line: ['. $line .']. Output: ['. print_r ($output, TRUE) .']. Return: ['. $return .']. Command:  ['. $cmd .' '. $instance->getCorePath () .'extra/TypeFriendly/typefriendly.php build "'. $path .'" -l '. $lang .' -o xhtml_single > '. $path .'log].');
			}

			restore_error_handler ();

			if (!is_dir ($path .'output/xhtml_single'))
				throw new Exception ('Impossible to generate manual! View DEBUG LOG for more info.');

			removeDir ($path .'output/'. $language);

			if (!@rename ($path .'output/xhtml_single', $path .'output/'. $language))
				throw new Exception (__ ('Impossible to rename directory! [[1]] to [[2]]', $path .'output/xhtml_single', $path .'output/'. $language));
		}

		Localization::singleton ()->setLanguage ($originalLanguage);
	}

	static public function makeIniFile ($array, $path)
	{
		$buffer = array ();

		foreach ($array as $key => $value)
			$buffer [] = $key ." = \"". $value ."\"";

		if (file_put_contents ($path, "; ". date ('d-m-Y H:i:s') ."\n\n". implode ("\n", $buffer)) === FALSE)
			throw new Exception (__ ('Impossible to create file! [[1]]', $path));
	}

	static private function generateSections ($language, $path)
	{
		$sections = self::getSections ();

		$chapters = self::getChapters ($sections);

		$pathCustomDoc = Instance::singleton ()->getDocPath ();

		if (file_exists ($pathCustomDoc .'sort_hints.txt'))
			copy ($pathCustomDoc .'sort_hints.txt', $path .'sort_hints.txt');
		elseif (file_put_contents ($path .'sort_hints.txt', implode ("\n", $chapters)) === FALSE)
			throw new Exception (__ ('Impossible to create file! [[1]]', $path));

		foreach ($chapters as $section => $chapter)
			if (file_exists ($pathCustomDoc .'input/'. self::$mapping [$language] .'/'. $chapter .'.txt'))
				copy ($pathCustomDoc .'input/'. self::$mapping [$language] .'/'. $chapter .'.txt', $path .'input/'. self::$mapping [$language] .'/'. $chapter .'.txt');
			else
				self::createChapter ($path, $chapter, $section, $language);
	}

	static private function getSections ($father = '')
	{
		$business = Business::singleton ();

		$children = $business->getChildren ($father);

		$sections = array ();
		foreach ($children as $section => $trash)
			$sections [$section] = self::getSections ($section);

		return $sections;
	}

	static private function getChapters ($sections, $level = '')
	{
		$chapters = array ();
		foreach ($sections as $section => $sub)
		{
			$chapters [$section] = $level . str_replace ('.', '_', $section);

			if (is_array ($sub) && sizeof ($sub))
				$chapters = array_merge ($chapters, self::getChapters ($sub, $level . str_replace ('.', '_', $section) .'.'));
		}

		return $chapters;
	}

	static private function createChapter ($path, $chapter, $sectionName, $language)
	{
		$originalSection = Business::singleton ()->getSection (Section::TCURRENT);
		$originalAction  = Business::singleton ()->getAction (Action::TCURRENT);

		$section = Business::singleton ()->getSection ($sectionName);

		$buffer  = "Title: ". $section->getLabel () ."\n\n";
		$buffer .= "---\n\n";

		if (trim ($section->getDoc ()) != "")
			$buffer .= $section->getDoc () ."\n\n";

		if (trim ($section->getDescription ()) != '')
		{
			$buffer .= "> [information]\n";
			$buffer .= "> ". $section->getDescription () ."\n\n";
		}

		while ($action = $section->getAction ())
		{
			Business::singleton ()->setCurrent ($section->getName (), $action->getName ());

			$buffer .= "# ". $action->getLabel () ." #\n\n";

			$content = $section->getDoc ($action->getName ());

			if (trim ($content) != "")
				$buffer .= $content ."\n\n";

			if (trim ($action->getDescription ()) != '')
			{
				$buffer .= "> [information]\n";
				$buffer .= "> ". $action->getDescription () ."\n\n<!-- # -->\n\n";
			}

			if (trim ($action->getWarning ()) != '')
			{
				$buffer .= "> [warning]\n";
				$buffer .= "> ". $action->getWarning () ."\n\n";
			}

			if (sizeof ($action->getMenu ()))
			{
				$buffer .= "### ". __ ('Menu Actions') ." ###\n\n";

				$buffer .= "| ". __ ('Menu button') ." | ". __ ('Action by clicking') ." |\n";
				$buffer .= "|-|:-|\n";

				$menu = new Menu ($action->getMenu ());

				while ($item = $menu->getItem ())
				{
					if (!@copy ($item->getImagePath (), $path .'input/'. self::$mapping [$language] .'/media/'. $item->getImage ()))
						continue;

					$buffer .= "| ![". $section->getName () ."_". $action->getName () ."_". $item->getImage () ."](media/". $item->getImage () ." \"". $item->getLabel () ."\") | **". $item->getLabel () ."**: ". $item->getDoc () ." |\n";
				}
			}

			try
			{
				$obj = NULL;

				try
				{
					$obj = new Form (array ($action->getXmlPath (), $action->getName () .'.xml', $action->getEngine () .'.xml', 'all.xml'));
				}
				catch (Exception $e)
				{
					try
					{
						$obj = new View (array ($action->getXmlPath (), $action->getName () .'.xml', $action->getEngine () .'.xml', 'all.xml'));
					}
					catch (Exception $e)
					{
						throw new Exception ();
					}
				}

				if (!is_object ($obj))
					throw new Exception ();

				$buffer .= "### ". __ ('This action contains the fowlling fields') .": ###\n\n";

				$controlKeys = array ('label', 'desc', 'help');

				while ($field = $obj->getField ())
				{
					$doc = $field->genDoc ();

					$buffer .= "####". (trim ($doc ['label']) != '' ? $doc ['label'] : __ ('Unlabed Field')) ."####\n\n";

					if (array_key_exists ('desc', $doc) && trim ($doc ['desc']) != '')
						$buffer .= ":    ". trim ($doc ['desc']) ."\n\n";

					foreach ($doc as $key => $value)
						if (!in_array ($key, $controlKeys) && trim ($value) != '')
							$buffer .= ":    ". trim ($value) ."\n\n";

					if (array_key_exists ('help', $doc) && trim ($doc ['help']) != '')
					{
						$buffer .= "> [help]\n";
						$buffer .= "> ". $doc ['help'] ."\n\n";
					}
				}
			}
			catch (Exception $e)
			{}
		}

		Business::singleton ()->setCurrent ($originalSection, $originalAction);

		if (file_put_contents ($path .'input/'. self::$mapping [$language] .'/'. $chapter .'.txt', $buffer) === FALSE)
			throw new Exception (__ ('Impossible to create file! [[1]]', $path));
	}

	static public function isActive ()
	{
		$doc = Instance::singleton ()->getDocPath ();

		return !empty ($doc);
	}
}