<?php
/**
 *------------------------------------------------------------------------------
 * @package       T4 Page Builder for Joomla!
 *------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2004-2020 JoomlArt.com. All Rights Reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       JoomlArt, JoomlaBamboo, (contribute to this project at github
 *                & Google group to become co-author)
 *------------------------------------------------------------------------------
 */


defined('_JEXEC') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\Router\Route;
use Joomla\Registry\Registry;
use Joomla\CMS\Language\Text;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\MVC\View\HtmlView;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\Access\Exception\NotAllowed;
/**
 * HTML Page View class for the T4 Page builder component
 *
 * @since  1.5
 */
class T4pagebuilderViewPage extends HtmlView
{
	protected $item;

	protected $params;

	protected $print;

	protected $state;

	protected $user;

	/**
	 * Constructor
	 *
	 * @param   array  $config  A named configuration array for object construction.
	 *                          name: the name (optional) of the view (defaults to the view class name suffix).
	 *                          charset: the character set to use for display
	 *                          escape: the name (optional) of the function to use for escaping strings
	 *                          base_path: the parent path (optional) of the views directory (defaults to the component folder)
	 *                          template_plath: the path (optional) of the layout directory (defaults to base_path + /views/ + view name
	 *                          helper_path: the path (optional) of the helper files (defaults to base_path + /helpers/)
	 *                          layout: the layout (optional) to use to display the view
	 *
	 * @since   3.0
	 */
	public function __construct($config = array())
	{
		parent::__construct($config);
		$this->app = Factory::getApplication();
		$this->root = Uri::root(true);
	}
	/**
	 * Execute and display a template script.
	 *
	 * @param   string  $tpl  The name of the template file to parse; automatically searches through the template paths.
	 *
	 * @return  mixed  A string if successful, otherwise an Error object.
	 */
	public function display($tpl = null)
	{
		$app = Factory::getApplication();
		$user = Factory::getUser();
		$doc = Factory::getDocument();

		$this->item = $this->get('Item');
		$this->item->text = $this->item->page_html;
		$this->print = $app->input->getBool('print');
		$this->state = $this->get('State');
		$this->user = $user;
		$this->templateDefault = $app->getTemplate('template')->id;
		$this->params = $this->state->get('params', '');
		$this->plg_t4 = defined("T4_PLUGIN") ? true : false;
		$active = $app->getMenu()->getActive();
		$this->loadlegacy = $this->params->get('loadlegacy', 0);
		$this->bt4 = false;
		$this->t4 = $this->get('IsT4');
		HTMLHelper::_('jquery.framework');
		HTMLHelper::_('behavior.keepalive');
		$item = $this->item;
		// Check for errors.
		if (count($errors = $this->get('Errors'))) {
			throw new NotAllowed(implode("\n", $errors), 500);
			return false;
		}

		$access = $user->getAuthorisedViewLevels();
		if (empty($this->item) && !in_array($this->item->access, $access)) {
			if ($this->user->get('guest')) {
				$return = base64_encode(Uri::getInstance());
				$login_url_with_return = Route::_('index.php?option=com_users&view=login&return=' . $return);
				$app->enqueueMessage(Text::_('JERROR_ALERTNOAUTHOR'), 'notice');
				$app->redirect($login_url_with_return, 403);
				return;
			}
			else {
				$app->enqueueMessage(Text::_('JERROR_ALERTNOAUTHOR'), 'error');
				$app->setHeader('status', 403, true);

				return;
			}
		}

		$groups_can_view_unpublish = array(
			'6' => '6',
			'7' => '7',
			'8' => '8'
		);
		if (!Factory::getApplication()->input->get('preview') && $this->item->state == 0 && count(array_intersect($user->groups, $groups_can_view_unpublish)) == 0) {
			$app->enqueueMessage(Text::_('JERROR_ALERTNOAUTHOR'), 'error');
			$app->setHeader('status', 403, true);

			return;
		}
		$offset = $this->state->get('list.offset');
		/**
		 * Check for no 'access-view',
		 * - Redirect guest users to login
		 * - Deny access to logged users with 403 code
		 * NOTE: we do not recheck for no access-view + show_noauth disabled ... since it was checked above
		 */
		if ($this->item->params->get('access-view') == false) {
			if ($this->user->get('guest')) {
				$return = base64_encode(Uri::getInstance());
				$login_url_with_return = Route::_('index.php?option=com_users&view=login&return=' . $return);
				$app->enqueueMessage(Text::_('JERROR_ALERTNOAUTHOR'), 'notice');
				$app->redirect($login_url_with_return, 403);
			}
			else {
				$app->enqueueMessage(Text::_('JERROR_ALERTNOAUTHOR'), 'error');
				$app->setHeader('status', 403, true);

				return;
			}
		}

		// Process the content plugins.
		PluginHelper::importPlugin('content');
		$this->_triggerEvent('onContentPrepare', array('com_t4pagebuilder.page', &$item, &$item->params, $offset));

		$item->event = new stdClass;
		$results = $this->_triggerEvent('onContentAfterTitle', array('com_t4pagebuilder.page', &$item, &$item->params, $offset));
		$item->event->afterDisplayTitle = trim(implode("\n", $results));

		$results = $this->_triggerEvent('onContentBeforeDisplay', array('com_t4pagebuilder.page', &$item, &$item->params, $offset));
		$item->event->beforeDisplayContent = trim(implode("\n", $results));

		$results = $this->_triggerEvent('onContentAfterDisplay', array('com_t4pagebuilder.page', &$item, &$item->params, $offset));
		$item->event->afterDisplayContent = trim(implode("\n", $results));

		// Escape strings for HTML output
		$this->pageclass_sfx = $this->item->params->get('pageclass_sfx') ? htmlspecialchars($this->item->params->get('pageclass_sfx'), ENT_QUOTES) : "";

		$this->_prepareDocument();

		parent::display($tpl);
	}
	protected function _triggerEvent($event, $arr)
	{
		if (version_compare(JVERSION, '4', 'ge')) {
			$results = Factory::getApplication()->triggerEvent($event, $arr);
		}
		else {
			$dispatcher = JEventDispatcher::getInstance();
			$results = $dispatcher->trigger($event, $arr);
		}
		return $results;
	}

	/**
	 * Prepares the document.
	 *
	 * @return  void
	 */
	protected function _prepareDocument()
	{
		$app = Factory::getApplication();
		$menus = $app->getMenu();
		$pathway = $app->getPathway();
		$params = $this->params;
		$attribs = new Registry();
		if(!empty($this->item->attribs)){
			$attribs->loadString($this->item->attribs);
		}
		$params->merge($attribs);
		$bootstrap4 = $params->get('bootstrap4', "-");
		$icons = $params->get('loadconfigicons') ? $params->get('loadconfigicons') : '{"awesome_icons":{"awesome_icons":true,"url_type":"cdn","custom_url":"null"},"material_icons":{"material_icons":true,"url_type":"cdn","custom_url":""}}';
		$bootstrap_assigned = $params->get('btAssigned') ? json_decode($params->get('btAssigned')) : [];
		$title = null;
		/**
		 * Because the application sets a default page title,
		 * we need to get it from the menu item itself
		 */
		$menu = $menus->getActive();
		$menuParams = version_compare(JVERSION, '4', 'lt') ? $menu->params??[] : $menu->getParams();
		$params->merge($menuParams);
		if ($menu) {
			$this->params->def('page_heading', $this->params->get('page_title', $menu->title));
		}
		else {
			$this->params->def('page_heading', Text::_('JGLOBAL_ARTICLES'));
		}

		$title = $this->params->get('page_title', '');

		$id = (int)@$menu->query['id'];

		// If the menu item does not concern this article
		if ($menu && ($menu->query['option'] !== 'com_t4pagebuilder' || $menu->query['view'] !== 'page' || $id != $this->item->id)) {
			// If a browser page title is defined, use that, then fall back to the article title if set, then fall back to the page_title option
			$title = $this->item->params->get('page_title', $this->item->title ?: $title);
		}
		// Check for empty title and add site name if param is set
		if (empty($title)) {
			$title = $app->get('sitename');
		}
		elseif ($app->get('sitename_pagetitles', 0) == 1) {
			$title = Text::sprintf('JPAGETITLE', $app->get('sitename'), $title);
		}
		elseif ($app->get('sitename_pagetitles', 0) == 2) {
			$title = Text::sprintf('JPAGETITLE', $title, $app->get('sitename'));
		}

		if (empty($title)) {
			$title = $this->item->title;
		}

		$this->document->setTitle($title);
		$metaDesc = $params->get('menu-meta_description') ?: $params->get('metadesc');
		if ($metaDesc) {
			$this->document->setDescription($metaDesc);
		}
		$metakey = $params->get('menu-meta_keywords') ?: $params->get('metakey');
		if ($metakey) {
			$this->document->setMetadata('keywords', $metakey);
		}
		$metaRights = $params->get('rights') ?: "";
		if ($metaRights) {
			$this->document->setMetadata('rights', $metaRights);
		}

		if ($this->params->get('robots')) {
			$this->document->setMetadata('robots', $this->params->get('robots'));
		}

		if ($app->get('MetaAuthor') == '1') {
			$author = $this->params->get('author') ?: ($this->item->created_by ?: $this->item->author);
			$this->document->setMetaData('author', $author);
		}

		// If there is a pagebreak heading or title, add it to the page title
		if (!empty($this->item->page_title)) {
			$this->item->title = $this->item->title . ' - ' . $this->item->page_title;
			$this->document->setTitle(
				$this->item->page_title . ' - ' . Text::sprintf('PLG_CONTENT_PAGEBREAK_PAGE_NUM', $this->state->get('list.offset') + 1)
			);
		}
		if ($bootstrap4 !== "-") {
			if ($bootstrap4 == 0) {
				$this->document->addStyleSheet($this->root . '/media/t4pagebuilder/builder/vendors/bootstrap4/css/bootstrap.min.css');
				$this->bt4 = true;
			}
			elseif ($bootstrap4 < 0) {
				if (in_array(-$menu->id, $bootstrap_assigned)) {
					$this->document->addStyleSheet($this->root . '/media/t4pagebuilder/builder/vendors/bootstrap4/css/bootstrap.min.css');
					$this->bt4 = true;
				}
			}
			elseif ($bootstrap4 > 0) {
				if (in_array($menu->id, $bootstrap_assigned)) {
					$this->document->addStyleSheet($this->root . '/media/t4pagebuilder/builder/vendors/bootstrap4/css/bootstrap.min.css');
					$this->bt4 = true;
				}
			}
		}
		if ($this->bt4) {
			if (version_compare(JVERSION, '4', 'lt')) HTMLHelper::_('bootstrap.framework');
			if ($bootstrap4 !== "-") $this->document->addScript($this->root . '/media/t4pagebuilder/builder/vendors/bootstrap4/js/bootstrap.bundle.js');
		}
		if (is_file(JPB_PATH_MEDIA_BUILDER . 'etc/' . $this->item->id . '/customfonts.json')) {
			self::loadCustomFont();
		}
		$this->_loadOther($params);
		$this->loadGoogleFonts();
		$this->document->addStyleSheet($this->root . '/media/t4pagebuilder/builder/css/ja_pagebuilder.css');
		$this->document->addStyleSheet($this->root . '/media/t4pagebuilder/builder/css/elements.css');
		$this->document->addStyleSheet($this->root . '/media/t4pagebuilder/builder/css/site.css');
		$this->document->addStyleSheet($this->root . '/media/t4pagebuilder/builder/vendors/animate/animate.css');
		$this->document->addStyleSheet($this->root . '/media/t4pagebuilder/builder/vendors/animate/t4b-animation.css');
		$this->document->addScript($this->root . '/media/t4pagebuilder/builder/vendors/animate/t4b-animation.js');
		$this->document->addScript($this->root . '/media/t4pagebuilder/builder/js/t4pagebuilder.js');
		$this->_loadFontIcons($icons);

		if (isset($this->item->css) || isset($this->item->bundle_css)) {
			$protocols = '[a-zA-Z0-9\-]+:';
			// Replace src links.
			$base = $this->root . '/';
			$regex_url = '\s*url\s*\(([\'\"]|\&\#0?3[49];)?(?!\/|\&\#0?3[49];|' . $protocols . '|\#)([^\)\'\"]+)([\'\"]|\&\#0?3[49];)?\)';
			$regex = '#' . $regex_url . '#m';
			$css = "";
			if ($this->item->bundle_css) {
				$css = $this->item->bundle_css;
			}
			$css .= (string)$this->item->css;

			if ($css) {
				$css = preg_replace($regex, 'url($1' . $base . '$2$3)', $css);
				preg_match_all($regex, $this->item->css, $matches);
				$this->document->addStyleDeclaration($css);
			}
		}
		if ($this->print) {
			$this->document->setMetaData('robots', 'noindex, nofollow');
		}
		$this->_renderOpenGraph();
		if ($this->app->isClient('site') && !$this->plg_t4) {
			$this->_renderOpenGraph();
		}
	}
	protected function loadCustomFont()
	{
		static $customFonts = null;
		static $loaded = [];
		if ($customFonts === null) {
			if (is_file(JPB_PATH_MEDIA_BUILDER . 'etc/' . $this->item->id . '/customfonts.json')) {
				$customFonts = json_decode(file_get_contents(JPB_PATH_MEDIA_BUILDER . 'etc/' . $this->item->id . '/customfonts.json'), true);
			}
			else {
				return;
			}
		}
		if (empty($customFonts['fonts'])) {
			return;
		}
		$names = array_keys($customFonts['fonts']);
		foreach ($names as $name) {
			$font = $customFonts['fonts'][$name];
			if (in_array($font['url'], $loaded)) {
				continue;
			}
			$loaded[] = $font['url'];
			if (!empty($font['type']) && $font['type'] == 'css') {
				if (!preg_match("/[^\/.\s+]/", $font['url'])) {
					$font['url'] = '/' . $font['url'];
				}
				$font_url = Uri::root(true) . $font['url'];
				// load css file
				$this->document->addStylesheet($font_url);
			}
			else {
				// add css declaration
				$css = '@font-face {';
				$css .= "font-family: '$name';";
				$css .= "src: url('{$font['url']}');";
				$css .= "}";

				$this->document->addStyleDeclaration($css);
			}
		}
	}
	protected function loadGoogleFonts()
	{
		$doc = Factory::getDocument();
		// Load google/custom font in field with suffix _font_family
		$googleFonts = $this->params->get('loadfonts') ? json_decode($this->params->get('loadfonts')) : [];

		$family = [];
		foreach ($googleFonts as $font => $weights) {
			$weight = implode(',', $weights->weight);
			$family[] = $font . ($weight == '400' ? '' : ':' . $weight);
		}

		if (count($family)) {
			$doc->addStylesheet('https://fonts.googleapis.com/css?family=' . urlencode(implode('|', $family)));
		}
	}
	protected function _loadFontIcons($data)
	{
		if (!$data) {
			return;
		}
		$doc = Factory::getDocument();

		$fData = json_decode($data, true);
		$aws = $fData['awesome_icons'];
		$material = $fData['material_icons'];
		if ($aws['awesome_icons'] == false && $material['material_icons'] == false) {
			return;
		}
		if ($aws['awesome_icons'] && $aws['url_type'] == 'cdn') {
			if (!$this->t4) {
				$doc->addStylesheet($this->root . '/media/t4pagebuilder/builder/css/fontawesome_6.min.css');
			}
		}
		elseif ($aws['awesome_icons'] && $aws['url_type'] == 'url') {
			if ($aws['custom_url']) {
				$doc->addStylesheet($aws['custom_url']);
			}
		}
		if ($material['material_icons'] && $material['url_type'] == 'cdn') {
			$doc->addStyleSheet('https://fonts.googleapis.com/icon?family=Material+Icons');
		}
		elseif ($material['material_icons'] && $material['url_type'] == 'url') {
			if ($material['custom_url']) {
				$doc->addStylesheet($material['custom_url']);
			}
		}
	}
	protected function _loadOther($params)
	{
		$otherCss = $params->get('loadothercss', '');
		$otherJs = $params->get('loadotherjs', '');
		if ($otherJs) {
			$arrJs = explode("\n", $otherJs);
			foreach ($arrJs as $js) {
				$this->document->addScript(trim($js));
			}
		}
		if ($otherCss) {
			$arrCss = explode("\n", $otherCss);
			foreach ($arrCss as $css) {
				$this->document->addStyleSheet(trim($css));
			}
		}
	}
	protected function _renderOpenGraph()
	{
		if (!empty($this->item->attribs) && !$this->t4) {
			FrontEndT4pagebuilderHelper::renderOpenGraph($this->item->attribs);
		}
	}
}
