<?php
/**
* @version	$Id: permissions_event_handler.php 15145 2012-03-04 09:04:08Z alex $
* @package	In-Portal
* @copyright	Copyright (C) 1997 - 2009 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 PermissionsEventHandler extends kDBEventHandler {

	/**
	 * Allows to override standard permission mapping
	 *
	 * @return void
	 * @access protected
	 * @see kEventHandler::$permMapping
	 */
	protected function mapPermissions()
	{
		parent::mapPermissions();

		$permissions = Array (
			'OnGroupSavePermissions' => Array ('subitem' => 'advanced:manage_permissions'),
		);

		$this->permMapping = array_merge($this->permMapping, $permissions);
	}

	/**
	 * Save category permissions
	 *
	 * @param kEvent $event
	 */
	function OnCategorySavePermissions($event)
	{
		$group_id = $this->Application->GetVar('current_group_id');
		$category_id = $this->Application->GetVar('c_id');
		$permissions = $this->Application->GetVar($event->getPrefixSpecial(true));

		if (isset($permissions[$group_id])) {
			$permissions = $permissions[$group_id];

			$object = $event->getObject( Array('skip_autoload' => true) );
			$permissions_helper = $this->Application->recallObject('PermissionsHelper');
			/* @var $permissions_helper kPermissionsHelper */

			$permissions_helper->LoadPermissions($group_id, $category_id, 0, 'c');

			// format: <perm_name>['inherited'] || <perm_name>['value']

			$delete_ids = Array();
			$create_sql = Array();
			$update_sql = Array();
			$create_mask = '(%s,%s,'.$group_id.',%s,0,'.$category_id.')';
			$new_id = (int)$this->Conn->GetOne('SELECT MIN('.$object->IDField.') FROM '.$object->TableName);
			if($new_id > 0) $new_id = 0;
			--$new_id;

			foreach ($permissions as $perm_name => $perm_data) {
				$inherited = $perm_data['inherited'];
				$perm_value = isset($perm_data['value']) ? $perm_data['value'] : false;
				$perm_id = $permissions_helper->getPermissionID($perm_name);

				if ($inherited && ($perm_id != 0)) {
					// permission become inherited (+ direct value was set before) => DELETE
					$delete_ids[] = $permissions_helper->getPermissionID($perm_name);
				}

				if (!$inherited) {
					// not inherited
					if (($perm_id != 0) && ($perm_value != $permissions_helper->getPermissionValue($perm_name))) {
						// record was found in db & new value differs from old one => UPDATE
						$update_sql[$perm_id] = '	UPDATE '.$object->TableName.'
													SET PermissionValue = '.$perm_value.'
													WHERE (PermissionId = '.$perm_id.')';
					}

					if ($perm_id == 0) {
						// not found in db, but set directly => INSERT
						$create_sql[] = sprintf($create_mask, $new_id--, $this->Conn->qstr($perm_name), $this->Conn->qstr($perm_value));
					}
				}
				// permission state was not changed in all other cases
			}

			$this->UpdatePermissions($event, $create_sql, $update_sql, $delete_ids);
		}

		$event->MasterEvent->SetRedirectParam('item_prefix', $this->Application->GetVar('item_prefix'));
		$event->MasterEvent->SetRedirectParam('group_id', $this->Application->GetVar('group_id'));
	}

	/**
	 * Saves permissions while editing group
	 *
	 * @param kEvent $event
	 *
	 * @return void
	 * @access protected
	 */
	protected function OnGroupSavePermissions($event)
	{
		if ( !$this->Application->CheckPermission('in-portal:user_groups.advanced:manage_permissions', 1) ) {
			// no permission to save permissions
			return ;
		}

		$permissions = $this->Application->GetVar($event->getPrefixSpecial(true));
		if ( !$permissions ) {
			return ;
		}

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

		$group_id = $this->Application->GetVar('g_id');
		$permissions_helper = $this->Application->recallObject('PermissionsHelper');
		/* @var $permissions_helper kPermissionsHelper */

		$permissions_helper->LoadPermissions($group_id, 0, 1, 'g');

		$delete_ids = $create_sql = Array ();
		$create_mask = '(%s,%s,' . $group_id . ',%s,1,0)';

		$new_id = (int)$this->Conn->GetOne('SELECT MIN(' . $object->IDField . ') FROM ' . $object->TableName);
		if ( $new_id > 0 ) {
			$new_id = 0;
		}
		--$new_id;

		$sections_helper = $this->Application->recallObject('SectionsHelper');
		/* @var $sections_helper kSectionsHelper */

		foreach ($permissions as $section_name => $section_permissions) {
			$section_data =& $sections_helper->getSectionData($section_name);

			if ( $section_data && isset($section_data['perm_prefix']) ) {
				// using permission from other prefix
				$section_name = $this->Application->getUnitOption($section_data['perm_prefix'] . '.main', 'PermSection');
			}

			foreach ($section_permissions as $perm_name => $perm_value) {
				if ( !$permissions_helper->isOldPermission($section_name, $perm_name) ) {
					$perm_name = $section_name . '.' . $perm_name;
				}

				$db_perm_value = $permissions_helper->getPermissionValue($perm_name);

				if ( $db_perm_value == 1 && $perm_value == 0 ) {
					// permission was disabled => delete it's record
					$delete_ids[] = $permissions_helper->getPermissionID($perm_name);
				}
				elseif ( $db_perm_value == 0 && $perm_value == 1 ) {
					// permission was enabled => created it's record
					$create_sql[$perm_name] = sprintf($create_mask, $new_id--, $this->Conn->qstr($perm_name), $this->Conn->qstr($perm_value));
				}
				// permission state was not changed in all other cases
			}
		}

		$this->UpdatePermissions($event, $create_sql, Array (), $delete_ids);

		if ( $this->Application->GetVar('advanced_save') == 1 ) {
			// advanced permission popup [save button]
			$this->finalizePopup($event);
//			$event->redirect = 'incs/just_close';
		}
		elseif ( $this->Application->GetVar('section_name') != '' ) {
			// save simple permissions before opening advanced permission popup
			$event->redirect = false;
		}
	}

	/**
	 * Apply modification sqls to permissions table
	 *
	 * @param kEvent $event
	 * @param Array $create_sql
	 * @param Array $update_sql
	 * @param Array $delete_ids
	 */
	function UpdatePermissions($event, $create_sql, $update_sql, $delete_ids)
	{
		$object = $event->getObject();
		/* @var $object kDBItem */

		if ($delete_ids) {
			$action = ChangeLog::DELETE;
			$object->Load($delete_ids[count($delete_ids) - 1]);

			$delete_sql = '	DELETE FROM '.$object->TableName.'
							WHERE '.$object->IDField.' IN ('.implode(',', $delete_ids).')';
			$this->Conn->Query($delete_sql);
		}

		if ($create_sql) {
			$create_sql = '	INSERT INTO '.$object->TableName.'
							VALUES '.implode(',', $create_sql);
			$this->Conn->Query($create_sql);

			$sql = 'SELECT MIN(' . $object->IDField . ')
					FROM ' . $object->TableName;
			$id = $this->Conn->GetOne($sql);

			$action = ChangeLog::CREATE;
			$object->Load($id);
		}

		if ($update_sql) {
			foreach ($update_sql as $id => $sql) {
				$this->Conn->Query($sql);
			}

			$action = ChangeLog::UPDATE;
			$object->Load($id);
			$object->SetDBField('PermissionValue', $object->GetDBField('PermissionValue') ? 0 : 1);
		}

		if ($delete_ids || $create_sql || $update_sql) {
			$object->setModifiedFlag($action);

			if ($event->Name == 'OnCategorySavePermissions') {
				$this->Application->StoreVar('PermCache_UpdateRequired', 1);
			}
		}
	}

	/**
	 * Don't delete permissions from live table in case of new category creation.
	 * Called as much times as permission count for categories set, so don't
	 * perform any sql queries here!
	 *
	 * @param kEvent $event
	 * @return void
	 * @access protected
	 */
	protected function OnBeforeDeleteFromLive(kEvent $event)
	{
		parent::OnBeforeDeleteFromLive($event);

		if ( $event->Prefix == 'c-perm' ) {
			// only when saving category permissions, not group permissions
			$foreign_keys = $event->getEventParam('foreign_key');

			if ( (count($foreign_keys) == 1) && ($foreign_keys[0] == 0) ) {
				// parent item has zero id
				$temp_object = $this->Application->recallObject('c');
				/* @var $temp_object CategoriesItem */

				if ( $temp_object->isLoaded() ) {
					// category with id = 0 found in temp table
					$event->status = kEvent::erFAIL;
				}
			}
		}
	}

}