<?php
/**
* @version	$Id: page_revision_eh.php 15165 2012-03-09 10:24:24Z alex $
* @package	In-Portal
* @copyright	Copyright (C) 1997 - 2011 Intechnic. All rights reserved.
* @license      GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/

defined('FULL_PATH') or die('restricted access!');

class PageRevisionEventHandler extends kDBEventHandler {

	/**
	 * Checks permissions of user
	 *
	 * @param kEvent $event
	 * @return bool
	 * @access public
	 */
	public function CheckPermission(kEvent $event)
	{
		if ( $event->Name == 'OnItemBuild' ) {
			return true;
		}

		if ( $event->Name == 'OnGetInfo' || $event->Name == 'OnDiscard' ) {
			return $this->Application->isAdminUser;
		}

		$perm_helper = $this->Application->recallObject('PermissionsHelper');
		/* @var $perm_helper kPermissionsHelper */

		if ( $event->Name == 'OnSave' ) {
				$perm_status = $this->Application->CheckPermission('CATEGORY.REVISION.ADD', 0) || $this->Application->CheckPermission('CATEGORY.REVISION.ADD.PENDING', 0);

			return $perm_helper->finalizePermissionCheck($event, $perm_status);
		}

		if ( $event->Name == 'OnPublish' || $event->Name == 'OnDecline' ) {
			$perm_status = $this->Application->CheckPermission('CATEGORY.REVISION.MODERATE', 0);

			return $perm_helper->finalizePermissionCheck($event, $perm_status);
		}

		return parent::CheckPermission($event);
	}

	/**
	 * Lists all current page revisions
	 *
	 * @param kEvent $event
	 * @return void
	 * @access protected
	 */
	protected function SetCustomQuery(kEvent $event)
	{
		parent::SetCustomQuery($event);

		$object = $event->getObject();
		/* @var $object kDBList */

		$page_id = $event->getEventParam('page_id');

		if ( $this->Application->isAdmin ) {
			$user_id = $this->Application->RecallVar('user_id');
		}
		else {
			$user_id = $this->Application->RecallVar('admin_user_id');
		}

		$object->addFilter('draft_filter', 'IF(%1$s.IsDraft = 1, %1$s.CreatedById = ' . $user_id . ', TRUE)');

		if ( $page_id !== false ) {
			$object->addFilter('parent_filter', '%1$s.PageId = ' . $page_id);
		}
	}

	/**
	 * Returns current page revision
	 *
	 * @param kEvent $event
	 * @return int
	 * @access public
	 */
	public function getPassedID(kEvent $event)
	{
		if ( $event->Special == 'current' ) {
			$page = $this->Application->recallObject('st.-virtual');
			/* @var $page kDBItem */

			$page_helper = $this->Application->recallObject('PageHelper');
			/* @var $page_helper PageHelper */

			$page_id = $page->GetID();
			$revision_clause = $page_helper->getRevsionWhereClause($page_id, $page->GetDBField('LiveRevisionNumber'));

			$sql = 'SELECT RevisionId
					FROM ' . TABLE_PREFIX . 'PageRevisions
					WHERE (PageId = ' . $page_id . ') AND (' . $revision_clause . ')
					ORDER BY IsDraft DESC, RevisionNumber DESC';
			$id = $this->Conn->GetOne($sql);

			if ( $id ) {
				return $id;
			}

			// no revisions -> create live revision
			$object = $event->getObject();
			/* @var $object kDBItem */

			$object->SetDBField('PageId', $page_id);
			$object->SetDBField('RevisionNumber', 1);
			$object->SetDBField('Status', STATUS_ACTIVE);
			$object->Create();

			return $object->GetID();
		}

		return parent::getPassedID($event);
	}

	/**
	 * Remembers, who created revision
	 *
	 * @param kEvent $event
	 * @return void
	 * @access protected
	 */
	protected function OnBeforeItemCreate(kEvent $event)
	{
		parent::OnBeforeItemCreate($event);

		$object = $event->getObject();
		/* @var $object kDBItem */

		if ( $this->Application->isAdmin ) {
			$object->SetDBField('CreatedById', $this->Application->RecallVar('user_id'));
		}
		else {
			$object->SetDBField('CreatedById', $this->Application->RecallVar('admin_user_id'));
		}
	}

	/**
	 * Updates revision creation time
	 *
	 * @param kEvent $event
	 * @return void
	 * @access protected
	 */
	protected function OnBeforeItemUpdate(kEvent $event)
	{
		parent::OnBeforeItemUpdate($event);

		$object = $event->getObject();
		/* @var $object kDBItem */

		if ( $object->GetDBField('IsDraft') == 0 && $object->GetOriginalField('IsDraft') == 1 ) {
			$object->SetDBField('CreatedOn_date', adodb_mktime());
			$object->SetDBField('CreatedOn_time', adodb_mktime());
		}
	}

	/**
	 * Creates new content blocks based on source revision
	 *
	 * @param kEvent $event
	 * @return void
	 * @access protected
	 */
	protected function OnAfterItemCreate(kEvent $event)
	{
		parent::OnAfterItemCreate($event);

		$object = $event->getObject();
		/* @var $object kDBItem */

		if ( !$object->GetDBField('FromRevisionId') ) {
			return ;
		}

		$content = $this->Application->recallObject('content.-item', null, Array ('skip_autoload' => true));
		/* @var $content kDBItem */

		$sql = 	$content->GetSelectSQL() . '
				WHERE pr.RevisionId = ' . $object->GetDBField('FromRevisionId');
		$content_blocks = $this->Conn->Query($sql);

		foreach ($content_blocks as $content_block) {
			$content->LoadFromHash($content_block);
			$content->SetDBField('RevisionId', $object->GetID());
			$content->Create();
		}
	}

	/**
	 * Mark revision as current, once it's approved
	 *
	 * @param kEvent $event
	 * @return void
	 * @access protected
	 */
	protected function OnAfterItemUpdate(kEvent $event)
	{
		parent::OnAfterItemUpdate($event);

		$object = $event->getObject();
		/* @var $object kDBItem */

		$status = $object->GetDBField('Status');

		if ( $status != $object->GetOriginalField('Status') && $status == STATUS_ACTIVE ) {
			$page = $this->Application->recallObject('c.revision', null, Array ('skip_autoload' => true));
			/* @var $page kDBItem */

			$page->Load($object->GetDBField('PageId'));
			$page->SetDBField('LiveRevisionNumber', $object->GetDBField('RevisionNumber'));
			$page->Update();
		}
	}

	/**
	 * Returns user, who are editing current page right now
	 *
	 * @param kEvent $event
	 */
	function OnGetInfo($event)
	{
		$event->status = kEvent::erSTOP;

		if ( $this->Application->GetVar('ajax') != 'yes' ) {
			return ;
		}

		$page_helper = $this->Application->recallObject('PageHelper');
		/* @var $page_helper PageHelper */

		$page_id = $this->Application->GetVar('m_cat_id');
		echo json_encode( $page_helper->getPageInfo($page_id) );
	}

	/**
	 * Saves user draft into live revision
	 *
	 * @param kEvent $event
	 * @return void
	 * @access protected
	 */
	protected function OnSave(kEvent $event)
	{
		$revision_id = $this->getCurrentDraftRevision($event);

		if ( $revision_id ) {
			$object = $event->getObject(Array ('skip_autoload' => true));
			/* @var $object kDBItem */

			$object->Load($revision_id);
			$object->SetDBField('IsDraft', 0);
			$object->SetDBField('RevisionNumber', $this->getNextAvailableRevision($event));

			if ( $this->Application->CheckPermission('CATEGORY.REVISION.ADD', 0) ) {
				$object->SetDBField('Status', STATUS_ACTIVE);
			}
			elseif ( $this->Application->CheckPermission('CATEGORY.REVISION.ADD.PENDING', 0) ) {
				$object->SetDBField('Status', STATUS_PENDING);
			}

			$object->Update();
		}

		$event->SetRedirectParam('opener', 'u');
	}

	/**
	 * Discards user draft
	 *
	 * @param kEvent $event
	 */
	function OnDiscard($event)
	{
		$revision_id = $this->getCurrentDraftRevision($event);

		if ( $revision_id ) {
			$temp_handler = $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler');
			/* @var $temp_handler kTempTablesHandler */

			$temp_handler->DeleteItems($event->Prefix, $event->Special, Array ($revision_id));
		}

		$event->SetRedirectParam('opener', 'u');
	}

	/**
	 * Makes revision live
	 *
	 * @param kEvent $event
	 */
	function OnPublish($event)
	{
		$revision = $this->Application->recallObject('page-revision.current');
		/* @var $revision kDBItem */

		if ( !$revision->isLoaded() || $revision->GetDBField('Status') == STATUS_ACTIVE || $revision->GetDBField('IsDraft') ) {
			return ;
		}

		$revision->SetDBField('Status', STATUS_ACTIVE);
		$revision->Update();

		$event->SetRedirectParam('opener', 'u');
	}

	/**
	 * Denies changes made in revision
	 *
	 * @param kEvent $event
	 */
	function OnDecline($event)
	{
		$revision = $this->Application->recallObject('page-revision.current');
		/* @var $revision kDBItem */

		if ( !$revision->isLoaded() || $revision->GetDBField('Status') == STATUS_DISABLED || $revision->GetDBField('IsLive') || $revision->GetDBField('IsDraft') ) {
			return ;
		}

		$revision->SetDBField('Status', STATUS_DISABLED);
		$revision->Update();

		$event->SetRedirectParam('opener', 'u');
	}

	/**
	 * Returns revision id of user's draft
	 *
	 * @param kEvent $event
	 * @return int
	 */
	function getCurrentDraftRevision($event)
	{
		$where_clause = Array (
			'IsDraft = 1',
			'PageId = ' . $this->Application->GetVar('m_cat_id'),
			'CreatedById = ' . $this->Application->RecallVar('user_id'),
		);

		$sql = 'SELECT ' . $this->Application->getUnitOption($event->Prefix, 'IDField') . '
				FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . '
				WHERE (' . implode(') AND (', $where_clause) . ')';

		return $this->Conn->GetOne($sql);
	}

	/**
	 * Returns next available revision number for current page
	 *
	 * @param kEvent $event
	 * @return int
	 */
	function getNextAvailableRevision($event)
	{
		$sql = 'SELECT MAX(RevisionNumber)
				FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . '
				WHERE PageId = ' . $this->Application->GetVar('m_cat_id');
		$max_revision = (int)$this->Conn->GetOne($sql);

		return $max_revision + 1;
	}
}
