<?php

/**
 * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 * @package clearFusionCMS
 * @copyright Copyright (c) 2012 - 2017 clearFusionCMS. All rights reserved.
 * @link http://clearfusioncms.com
 */

/**
 * cfContentController Class
 *
 * Base class for public site content controllers.
 *
 * @package clearFusionCMS
 */
class cfContentController extends flController {
	/**
	 * The database object.
	 *
	 * @var flDb
	 */
	protected $db;

	/**
	 * The content object.
	 *
	 * @var cfContent
	 */
	public $content;

	/**
	 * The raw page data held in the database.
	 *
	 * @var array
	 */
	public $pageData = null;

	/**
	 * Additional crumbs.
	 *
	 * @var array
	 */
	protected $crumbs = array();

	/**
	 * Construct the public site controller object.
	 *
	 * @param flRouter $router The router object.
	 * @param flRequest $request The request object.
	 * @param cfContent $content The content object to use, only given if controller being created within a container page.
	 * @param array $pageData The data for the page, only given if controller being created within a container page.
	 * @throws flExceptionNotFound
	 */
	function __construct($router, $request, $content = null, $pageData = null) {
		parent::__construct($router, $request);

		$this->db = flApp::getDb();

		if($content === null) {
			// Look up the site that we're running
			if(!($r = $this->db->fetchRow('SELECT shortname,displayname,redirectto,locale,twitterusername,puressl FROM cf_sites WHERE domain=?', $request->getServerName())))
				throw new flExceptionNotFound();

			// If redirected site
			if(!empty($r['redirectto']))
				clearFusionCMS::getResponse()->redirectTo($r['redirectto'] . $this->request->getSelf(), true);

			clearFusionCMS::setSite($r['shortname'], $r['displayname'], $r['twitterusername'], $r['puressl']);
			fusionLib::setLocale($r['locale']);
			$this->content = new cfContent($this->db, $r['shortname']);
		}
		else {
			$this->content = $content;
			$this->pageData = $pageData;
		}
	}

	/**
	 * The action for processing public content, derived classes should replace this.
	 *
	 * @throws flExceptionForbidden
	 * @throws flExceptionNotFound
	 */
	function renderAction() {

		// Deal with entering/exiting preview mode
		if($this->request->hasCookie('__preview')) {
			// Disable preview
			if(!clearFusionCMS::getUser()->hasPermission('core.accessmgr') || ($this->request->hasQuery('__preview') && $this->request->getQuery('__preview', 'false') != 'true') || ($this->request->hasCookie('__preview') && $this->request->getCookie('__preview', 'false') != 'true'))
				$this->response->setCookie('__preview', 'false', -3600, '', $this->request->getBasePath());
			// Enable preview
			else {
				$this->response->setCookie('__preview', 'true', 0, '', $this->request->getBasePath())->noCache();
				clearFusionCMS::disableCache();
				cfContent::setPreview();
				$this->response->noCache();
			}
		}

		// Lookup the page
		if(!($data = $this->content->getPage($this->request->getParam('*', array()), $this->request->getParam('extension', ''))) || (!$data['published'] && !cfContent::isPreview())) {
			if($this->content->getDefaultPage() || $this->db->fetchOne('SELECT COUNT(*) FROM fl_content_' . clearFusionCMS::getSite()))
				throw new flExceptionNotFound();
			else
				throw new flExceptionNotFound(__('New installation. Website coming soon.', 'cf'));
		}

		// If this is the default page then don't allow access by page name
		if($data['id'] == $this->content->getDefaultPage() && $this->request->hasParam('*') && (!$data['iscontainer'] || !count($data['childpath'])))
			$this->response->redirectTo($this->request->getBasePath(true), true);

		// If permissions required to view page, check authenticated user and user has all permissions
		if(count($data['permissions']) && !clearFusionCMS::getUser()->hasPermission($data['permissions']))
			throw new flExceptionForbidden();

		$data['module'] = 'content';
		$data['contentid'] = $data['id'];

		// If module container then route to module
		if($data['iscontainer'] && $data['container'] != '#') {
			@list($cls, $action, $extra) = explode('.', $data['container']);
			$data['container_extra'] = isset($extra) ? $extra : '';
			try {
				class_exists($cls = $cls . 'PublicController');
				flApp::setController($controller = new $cls($this->router, $this->request, $this->content, $data));
			} catch(flExceptionLoadClass $e) {
				throw new flExceptionNotFound();
			}
			$controller->setResponse($this->response)->dispatch($action);
		}
		// Else output the page
		else {
			$data['container_extra'] = '';
			$this->pageData = $data;
			cfContentFilter::useTemplateEngine($tpl = new cfTemplateEngine($this));
			if(!$this->content->renderPage($tpl, $data))
				throw new flExceptionNotFound();
		}
	}

	/**
	 * Build a breadcrumb trail.
	 *
	 * @param int $id The id of the page to get the trail to, null for current.
	 * @return flWidgetBreadcrumb The breadcrumb widget.
	 */
	function getBreadcrumb($id = null) {
		$breadcrumb = new flWidgetBreadcrumb();

		$first = true;
		$def = $this->content->getDefaultPage();
		$path = $this->content->getPath($id = ($id === null ? $this->pageData['id'] : $id), array('id', 'title', 'menutitle', 'published'));
		foreach($path as $seg) {
			if($first && $def && $seg['id'] != $def) {
				$d = $this->content->getNodeData($def, array('title', 'menutitle'));
				$breadcrumb->addCrumb(empty($d['menutitle']) ? $d['title'] : $d['menutitle'], $this->content->getPageURI($def));
			}
			if($seg['published'])
				$breadcrumb->addCrumb(empty($seg['menutitle']) ? $seg['title'] : $seg['menutitle'], $this->content->getPageURI($seg['id']));
			$first = false;
		}

		// Add additional crumbs
		if(isset($this->crumbs[$id])) {
			foreach($this->crumbs[$id] as $c)
				$breadcrumb->addCrumb($c[0], $c[1]);
		}

		return $breadcrumb;
	}

	/**
	 * Add a crumb to the trail.
	 *
	 * @param int $id The ID of the page to add the crumb to the end of.
	 * @param string $name The anchor text for the link.
	 * @param string $link The link URI
	 * @return cfContentController This object.
	 */
	function addCrumb($id, $name, $link) {
		$this->crumbs[$id === null ? $this->pageData['id'] : $id][] = array($name, $link);
		return $this;
	}
}
