<?php
/**
* @version	$Id: page_helper.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 PageHelper extends kHelper {

	/**
	 * Returns page info
	 *
	 * @param int $page_id
	 * @return Array
	 */
	function getPageInfo($page_id)
	{
		list ($user_id, $history_permission) = $this->getHistoryPermissionAndUser($page_id);

		$where_clause = Array (
			'pr.PageId = ' . $page_id,
			'pr.CreatedById <> ' . $user_id,
			'pr.IsDraft = 1',
		);

		$sql = 'SELECT CASE pr.CreatedById WHEN ' . USER_ROOT . ' THEN "root" WHEN ' . USER_GUEST . ' THEN "Guest" ELSE u.Username END
				FROM ' . $this->Application->getUnitOption('page-revision', 'TableName') . ' pr
				LEFT JOIN ' . TABLE_PREFIX . 'Users u ON u.PortalUserId = pr.CreatedById
				WHERE (' . implode(') AND (', $where_clause) . ')';
		$users = $this->Conn->GetCol($sql);

		$page_revisions = Array ();

		if ( $history_permission ) {
			$tag_params = Array ('per_page' => -1, 'skip_parent_filter' => 1, 'requery' => 1, 'page_id' => $page_id);

			$revisions = $this->Application->recallObject('page-revision.list', 'page-revision_List', $tag_params);
			/* @var $revisions kDBList */

			$revisions->Query();
			$revisions->GoFirst();

			$status_options = $revisions->GetFieldOptions('Status');
			$draft_label = $this->Application->Phrase('la_Draft', false, true);
			$title_label = $this->Application->Phrase('la_RevisionNumber', false, true);
			$by_label = $this->Application->Phrase('la_By', false, true);

			while ( !$revisions->EOL() ) {
				$status = $revisions->GetDBField('Status');
				$status_label = $this->Application->Phrase($status_options['options'][$status], false, true);

				$page_revisions[ 'r' . $revisions->GetDBField('RevisionNumber') ] = Array (
					'title' => $revisions->GetDBField('IsDraft') ? $draft_label : sprintf($title_label, $revisions->GetDBField('RevisionNumber')),
					'status' => $status,
					'status_label' => mb_strtolower($status_label),
					'datetime' => $revisions->GetField('CreatedOn'),
					'author' => $by_label . ': ' . $revisions->GetField('CreatedById'),
					'draft' => (int)$revisions->GetDBField('IsDraft'),
				);

				$revisions->GoNext();
			}
		}

		$current_revision = $this->Application->recallObject('page-revision.current');
		/* @var $current_revision kDBItem */

		$revision_status = $current_revision->GetDBField('Status');
		$status_options = $current_revision->GetFieldOptions('Status');
		$status_label = $this->Application->Phrase($status_options['options'][$revision_status], false, true);

		$revision_phase = $current_revision->GetDBField('IsDraft') ? 'la_title_EditingDraft' : 'la_title_ViewingRevision';
		$revision_title = sprintf($this->Application->Phrase($revision_phase, false, true), $current_revision->GetDBField('RevisionNumber'), mb_strtolower($status_label));
		$current_revision_info = Array ('title' => $revision_title, 'status' => $revision_status, 'saved' => '');

		$autosave_time = $current_revision->GetDBField('AutoSavedOn');

		if ( $autosave_time ) {
			$phrase = $this->Application->Phrase($current_revision->GetDBField('IsDraft') ? 'la_DraftSavedAt' : 'la_SavedAt', false, true);
			$current_revision_info['saved'] = sprintf($phrase, $current_revision->GetField('AutoSavedOn_time') . ' (' . $this->getAgoTime($autosave_time) . ')');
		}

		$currently_editing = $this->getPluralPhrase(
			count($users),
			Array (
				'phrase1' => 'la_PageCurrentlyEditing1',
				'phrase2' => 'la_PageCurrentlyEditing2',
				'phrase5' => 'la_PageCurrentlyEditing5',
			),
			false, true
		);

		$currently_editing = sprintf($currently_editing, implode(', ', $users));

		return Array ('current_revision' => $current_revision_info, 'editors' => $users, 'editors_warning' => $currently_editing, 'revisions' => $page_revisions);
	}

	/**
	 * Returns time passed between 2 given dates in "X minutes Y seconds ago" format
	 *
	 * @param int $from_date
	 * @param int $to_date
	 * @return string
	 */
	function getAgoTime($from_date, $to_date = null, $max_levels = 1)
	{
		$blocks = Array (
			Array ('name' => 'year', 'amount' => 60*60*24*365),
			Array ('name' => 'month' ,'amount' => 60*60*24*31),
			Array ('name' => 'week', 'amount' => 60*60*24*7),
			Array ('name' => 'day', 'amount' => 60*60*24),
			Array ('name' => 'hour', 'amount' => 60*60),
			Array ('name' => 'minute', 'amount' => 60),
			Array ('name' => 'second', 'amount' => 1),
		);

		if ( !isset($to_date) ) {
			$to_date = adodb_mktime();
		}

		$diff = abs($to_date - $from_date);

		if ( $diff == 0 ) {
			return 'now';
		}

		$current_level = 1;
		$result = Array ();

		foreach ($blocks as $block) {
			if ($current_level > $max_levels) {
				break;
			}

			if ( $diff / $block['amount'] >= 1 ) {
				$amount = floor($diff / $block['amount']);
				$plural = $amount > 1 ? 's' : '';

				$result[] = $amount . ' ' . $block['name'] . $plural;
				$diff -= $amount * $block['amount'];
				$current_level++;
			}
		}

		return implode(' ', $result) . ' ago';
	}

	/**
	 * Returns where clause for loading correct revision for a given page
	 *
	 * @param int $page_id
	 * @param int $live_revision_number
	 * @param string $table_name
	 * @return string
	 */
	function getRevsionWhereClause($page_id, $live_revision_number, $table_name = '')
	{
		$revision = (int)$this->Application->GetVar('revision');
		list ($user_id, $has_permission) = $this->getHistoryPermissionAndUser($page_id);

		if ( $has_permission && $revision ) {
			$revision_clause = $table_name . 'RevisionNumber = ' . $revision . ' AND ' . $table_name . 'IsDraft = 0';
		}
		else {
			$editing_mode = $this->Application->GetVar('editing_mode'); // not in a EDITING_MODE constant, while in admin console
			$revision_clause = $table_name . 'RevisionNumber = ' . $live_revision_number . ' AND ' . $table_name . 'IsDraft = 0';

			if ( $this->Application->GetVar('preview') || $editing_mode == EDITING_MODE_CONTENT ) {
				$revision_clause = '(' . $table_name . 'CreatedById = ' . $user_id . ' AND ' . $table_name . 'IsDraft = 1) OR (' . $revision_clause . ')';
			}
		}

		return $revision_clause;
	}

	/**
	 * Returns current admin user id (even, when called from front-end) and it's revision history view permission
	 *
	 * @param int $page_id
	 * @return Array
	 */
	function getHistoryPermissionAndUser($page_id)
	{
		$user_id = (int)$this->Application->RecallVar($this->Application->isAdmin ? 'user_id' : 'admin_user_id');
		$history_permission = $this->Application->CheckAdminPermission('CATEGORY.REVISION.HISTORY.VIEW', 0, $page_id);

		return Array ($user_id, $history_permission);
	}

	/**
	 * Creates new content block in every revision that misses it. Plus creates first page revision
	 *
	 * @param int $page_id
	 * @param int $num
	 */
	function createNewContentBlock($page_id, $num)
	{
		$sql = 'SELECT pc.PageContentId, pr.RevisionId
				FROM ' . TABLE_PREFIX . 'PageRevisions pr
				LEFT JOIN ' . TABLE_PREFIX . 'PageContent pc ON pc.RevisionId = pr.RevisionId AND pc.ContentNum = ' . $num . '
				WHERE pr.PageId = ' . $page_id;
		$revisions = $this->Conn->GetCol($sql, 'RevisionId');

		if ( !$revisions ) {
			// no revisions for a page -> create a live revision
			$revision = $this->Application->recallObject('page-revision.live', null, Array ('skip_autoload' => true));
			/* @var $revision kDBItem */

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

			$revisions[ $revision->GetID() ] = NULL;
		}

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

		$content_block->SetDBField('PageId', $page_id);
		$content_block->SetDBField('ContentNum', $num);

		foreach ($revisions as $revision_id => $content_block_id) {
			if ( is_numeric($content_block_id) ) {
				continue;
			}

			$content_block->SetDBField('RevisionId', $revision_id);
			$content_block->Create();
		}
	}

	/**
	 * Loads content block by it's number
	 *
	 * @param kDBItem $content_block
	 * @param CategoriesItem $page
	 * @param int $num
	 *
	 * @return bool
	 */
	function loadContentBlock(&$content_block, &$page, $num)
	{
		$page_id = $page->GetID();

		if ( !EDITING_MODE && !$this->Application->GetVar('preview') ) {
			$revision_clause = 'pr.RevisionNumber = ' . $page->GetDBField('LiveRevisionNumber') . ' AND pr.IsDraft = 0';
		}
		else {
			$revision_clause = $this->getRevsionWhereClause($page_id, $page->GetDBField('LiveRevisionNumber'), 'pr.');
		}


		$sql = 	$content_block->GetSelectSQL() . '
				WHERE (' . $content_block->TableName . '.PageId = ' . $page_id . ') AND (' . $content_block->TableName . '.ContentNum = ' . $num . ') AND (' . $revision_clause . ')
				ORDER BY pr.IsDraft DESC, pr.RevisionNumber DESC';
		$content_data = $this->Conn->GetRow($sql);

		$content_block->LoadFromHash($content_data);

		return $content_block->isLoaded();
	}

	/**
	 * Returns phrase based on given number
	 *
	 * @param int $number
	 * @param Array $forms
	 * @return string
	 */
	function getPluralPhrase($number, $forms, $allow_editing = true, $use_admin = false)
	{
		// normalize given forms
		if ( !array_key_exists('phrase5', $forms) ) {
			$forms['phrase5'] = $forms['phrase2'];
		}

		$phrase_type = $this->getPluralPhraseType($number);

		return $this->Application->Phrase( $forms['phrase' . $phrase_type], $allow_editing, $use_admin );
	}

	/**
	 * Returns phrase type based on given number
	 *
	 * @param int $number
	 * @return int
	 */
	function getPluralPhraseType($number)
	{
		$last_digit = substr($number, -1);
		$last_but_one_digit = strlen($number) > 1 ? substr($number, -2, 1) : false;
		$phrase_type = '5';

		if ($last_but_one_digit != 1) {
			if ($last_digit == 1) {
				$phrase_type = '1';
			}
			elseif ($last_digit >= 2 && $last_digit <= 4) {
				$phrase_type = '2';
			}
		}

		return $phrase_type;
	}
}
