<?php
/*
 * $RCSfile: GalleryView.class,v $
 *
 * Gallery - a web based photo album viewer and editor
 * Copyright (C) 2000-2005 Bharat Mediratta
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA  02110-1301, USA.
 */
/**
 * @version $Revision: 1.68.4.1 $ $Date: 2005/10/13 17:37:50 $
 * @package GalleryCore
 * @author Bharat Mediratta <bharat@menalto.com>
 */

/**
 * The API for module views
 *
 * This class defines the API for view classes used by the various modules to
 * render HTML and binary data to the browser.
 *
 * @package GalleryCore
 * @subpackage Classes
 */
class GalleryView {

    /*
     * ****************************************
     *                 Members
     * ****************************************
     */

    /**
     * The localization domain for this view
     *
     * @access private
     */
    var $_l10Domain;

    /*
     * ****************************************
     *                 Methods
     * ****************************************
     */

    /**
     * Initialize the view
     *
     * @param string the name of the module
     */
    function init($moduleId) {
	global $gallery;
	$this->_l10Domain = 'modules_' . $moduleId;
    }

    /**
     * Is this an immediate or a buffered view?
     *
     * @return boolean true if it's an immediate view.
     */
    function isImmediate() {
	return false;
    }

    /**
     * Print out the immediate output for this view.  This will bypass any
     * global templating.  This style of view should be reserved for binary
     * data.
     *
     * @param array any status information from a delegating controller
     * @param array any error information from a delegating controller
     * @return object GalleryStatus a status code
     */
    function renderImmediate($status, $error) {
	return GalleryStatus::success();
    }

    /**
     * Load the template with data from this view.
     *
     * @param object GalleryTemplate the template instance
     * @param array the form values
     * @return array object GalleryStatus a status code
     *               array ('body'/'html' => string template or 'redirect' => array)
     */
    function loadTemplate(&$template, &$form) {
	return array(GalleryStatus::success(), null);
    }

    /**
     * Load a view
     *
     * Be very security conscious about checking the inputs for possible
     * misuse. The view name is in the format <module>.<classname>, where
     * - <module> is the module the view belongs to
     * - <classname> is the name of the .inc-file to be loaded. The class
     *   that is loaded is the <classname>View, that must extend GalleryView class
     *
     * @param string a view name in the format <module>.<classname> (eg 'core.ShowItem')
     * @return array object GalleryStatus a status code
     *               object GalleryView a view
     * @static
     */
    function loadView($viewName) {
	global $gallery;

	/* Continue to support old style : separator for a while */
	if (preg_match('/^(\w+)[.:](\w+)$/', $viewName, $regs) == 1) {
	    $module = $regs[1];
	    $class = $regs[2];
	} else {
	    return array(GalleryStatus::error(ERROR_BAD_PARAMETER, __FILE__, __LINE__,
					      "$viewName can't be parsed"), null);
	}

	/* If the module is not active, only let site admins see the config view */
	list ($ret, $plugin) = GalleryCoreApi::loadPlugin('module', $module);
	if ($ret->isError()) {
	    return array($ret->wrap(__FILE__, __LINE__), null);
	}
	list ($ret, $isActive) = $plugin->isActive();
	if ($ret->isError()) {
	    return array($ret->wrap(__FILE__, __LINE__), null);
	}
	if (!$isActive) {
	    if ($viewName == $plugin->getConfigurationView()) {
		$ret = GalleryCoreApi::assertUserIsSiteAdministrator();
		if ($ret->isError()) {
		    return array($ret->wrap(__FILE__, __LINE__), null);
		}
	    } else {
		return array(GalleryStatus::error(ERROR_PERMISSION_DENIED, __FILE__, __LINE__),
			     null);
	    }
	}

	$viewClassName = $class . 'View';
	if (!class_exists($viewClassName)) {
	    $moduleBaseDir = dirname(__FILE__) . '/../../../';
	    $moduleDir = 'modules/' . $module . '/';
	    $fileName = $moduleDir . $class . '.inc';

	    $platform = $gallery->getPlatform();
	    if (!$platform->file_exists($moduleBaseDir . $fileName)) {
		return array(GalleryStatus::error(ERROR_BAD_PARAMETER, __FILE__, __LINE__,
						  $moduleBaseDir . $fileName), null);
	    }

	    /*
	     * We bundle view and controller classes together, so we need the controller
	     * superclass to load the view
	     */
	    GalleryCoreApi::relativeRequireOnce('modules/core/classes/GalleryController.class');
	    GalleryCoreApi::relativeRequireOnce($fileName);

	    if (!class_exists($viewClassName)) {
		return array(GalleryStatus::error(ERROR_BAD_PARAMETER, __FILE__, __LINE__,
			     "Class $viewClassName not defined in $viewName"), null);
	    }
	}

	$view = new $viewClassName();
	if (!GalleryUtilities::isA($view, 'GalleryView')) {
	    return array(GalleryStatus::error(ERROR_BAD_PARAMETER, __FILE__, __LINE__,
			 "Class $viewClassName is not a subclass of GalleryView"), null);
	}

	/* Tell the view what module its in */
	$view->init($module);

	return array(GalleryStatus::success(), $view);
    }

    /**
     * Prepare all the various things that a view requires in order to load up the
     * template properly (like the theme, the form variables, the status variables, etc
     * then call the view's loadTemplate() method and pass in the given template.
     *
     * @return array object GalleryStatus a status code
     *               array ('body'/'html' => string template or 'redirect' => array)
     *               object GalleryTheme the current theme
     */
    function doLoadTemplate(&$template) {
	global $gallery;

	/* -------------------------------------------------- */
	/* Get our form variables */
	$form = GalleryUtilities::getFormVariables('form');
	if (!isset($form['formName'])) {
	    $form['formName'] = '';
	}
	$template->setVariableByReference('form', $form);

	/* -------------------------------------------------- */
	/* Get our status */
	$statusId = GalleryUtilities::getRequestVariables('statusId');
	if (!empty($statusId)) {
	    $session =& $gallery->getSession();
	    $status = $session->getStatus($statusId);
	} else {
	    $status = array();
	}
	$template->setVariable('status', $status);

	/* -------------------------------------------------- */
	/* Load up the theme. */
	list ($ret, $item) = $this->_getItem();
	if ($ret->isError()) {
	    return array($ret->wrap(__FILE__, __LINE__), null, null);
	}

	list ($ret, $theme) = GalleryView::loadThemeForItem($item);
	if ($ret->isError()) {
	    return array($ret->wrap(__FILE__, __LINE__), null, null);
	}

	if (!isset($theme)) {
	    /*
	     * Need to be able to show error page, login and site admin even if we have
	     * no theme!  (In case our default theme is incompatible with current APIs)
	     */
	    switch (strtolower(get_class($this))) {
	    case 'showitemerrorview':
	    case 'useradminview':
	    case 'siteadminview':
		$theme = new GalleryTheme();
		$theme->setId('fallbackTheme');
		break;

	    default:
		return array(GalleryStatus::success(),
			     array('redirect' => array('view' => 'core.ShowItemError',
						       'problem' => 'missingTheme',
						       'itemId' => $item->getId())),
			     null);
	    }
	}

	/* Albums have their own settings.  Items use their parent album's settings */
	if (GalleryUtilities::isA($item, 'GalleryItem') && !$item->getCanContainChildren()) {
	    $targetId = $item->getParentId();
	} else {
	    $targetId = $item->getId();
	}
	list ($ret, $params) = $theme->fetchParameters($targetId);
	if ($ret->isError()) {
	    return array($ret->wrap(__FILE__, __LINE__), null, null);
	}

	$templateAdapter =& $gallery->getTemplateAdapter();
	$templateAdapter->setTheme($theme);

	/* -------------------------------------------------- */
	/* Standard user info available for every view */
	$user = $gallery->getActiveUser();
	$user = $user->getMemberData();
	list ($ret, $guestId) =
	    GalleryCoreApi::getPluginParameter('module', 'core', 'id.anonymousUser');
	if ($ret->isError()) {
	    return array($ret->wrap(__FILE__, __LINE__), null, null);
	}

	$user['isGuest'] = ($user['id'] == $guestId);
	$user['isRegisteredUser'] = !$user['isGuest'];
	list ($ret, $user['isAdmin']) = GalleryCoreApi::isUserInSiteAdminGroup();
	if ($ret->isError()) {
	    $user['isAdmin'] = false;
	}
	$template->setVariable('user', $user);

	/* -------------------------------------------------- */
	/* Delegate to the theme to draw this view */
	list ($ret, $results) = $theme->loadTemplate($this, $template, $item, $params);
	if ($ret->isError()) {
	    return array($ret->wrap(__FILE__, __LINE__), null, null);
	}

	/* -------------------------------------------------- */
	/* Check for icon pack */
	list ($ret, $iconPack) = GalleryCoreApi::newFactoryInstance('IconsInterface_1_0');
	if ($ret->isError()) {
	    return array($ret->wrap(__FILE__, __LINE__), null, null);
	}
	if (isset($iconPack)) {
	    $ret = $iconPack->init($template);
	    if ($ret->isError()) {
		return array($ret->wrap(__FILE__, __LINE__), null, null);
	    }
	}
	return array(GalleryStatus::success(), $results, $theme);
    }

    /**
     * This should return a description of the current view.
     *
     * It might return a static description or generate a dynamic description
     * using the current request status.
     *
     * @return array object GalleryStatus
     *               string localized description
     */
    function getViewDescription() {
	return array(GalleryStatus::error(ERROR_UNIMPLEMENTED, __FILE__, __LINE__), null);
    }

    /**
     * Get the localization domain for this view
     *
     * @return string
     */
    function getL10Domain() {
	return $this->_l10Domain;
    }

    /**
     * Return the current item, as specified in the 'itemId' request variable
     *
     * @return array object GalleryStatus a status code
     *               object GalleryItem an item
     */
    function _getItem() {
	global $gallery;
	list ($itemId, $path) = GalleryUtilities::getRequestVariables('itemId', 'path');
	$itemId = (int)$itemId;

	/* Check for path param if no itemId given */
	if (empty($itemId) && !empty($path)) {
	    if (substr($path, -5) == '.html') {
		$path = substr($path, 0, -5);
	    }

	    list ($ret, $itemId) = GalleryCoreApi::fetchItemIdByPath($path);
	    if ($ret->isError()) {
		return array($ret->wrap(__FILE__, __LINE__), null);
	    }
	    GalleryUtilities::putRequestVariable('itemId', $itemId);
	}

	/* If we still don't have an itemId, default to the root album */
	if (empty($itemId)) {
	    list ($ret, $itemId) =
		GalleryCoreApi::getPluginParameter('module', 'core', 'id.rootAlbum');
	    if ($ret->isError()) {
		return array($ret->wrap(__FILE__, __LINE__), null);
	    }
	}

	/* Load the item */
	list ($ret, $item) = GalleryCoreApi::loadEntitiesById($itemId);
	if ($ret->isError()) {
	    return array($ret->wrap(__FILE__, __LINE__), null);
	}

	return array(GalleryStatus::success(), $item);
    }

    /**
     * Get the theme for this item by finding the theme id for the nearest album.
     *
     * @return array object GalleryStatus a status code
     *               object GalleryTheme a theme instance
     */
    function loadThemeForItem($item=null) {
	if (!isset($item)) {
	    list ($ret, $item) = GalleryView::_getItem();
	    if ($ret->isError()) {
		return array($ret->wrap(__FILE__, __LINE__), null);
	    }
	}

	if (GalleryUtilities::isA($item, 'GalleryAlbumItem')) {
	    $nearestAlbum = $item;
	} else {
	    list ($ret, $nearestAlbum) = GalleryCoreApi::loadEntitiesById($item->getParentId());
	    if ($ret->isError()) {
		return array($ret->wrap(__FILE__, __LINE__), null);
	    }
	}

	/* Load the theme, fallback to the default theme if none is specified. */
	if (isset($nearestAlbum)) {
	    list ($ret, $themeId) = GalleryCoreApi::fetchThemeId($nearestAlbum);
	    if ($ret->isError()) {
		return array($ret->wrap(__FILE__, __LINE__), null);
	    }
	} else {
	    list ($ret, $themeId) =
		GalleryCoreApi::getPluginParameter('module', 'core', 'default.theme');
	    if ($ret->isError()) {
		return array($ret->wrap(__FILE__, __LINE__), null);
	    }
	}

	$validTheme = false;
	list ($ret, $theme) = GalleryCoreApi::loadPlugin('theme', $themeId);
	if ($ret->isError() && !($ret->getErrorCode() & ERROR_PLUGIN_VERSION_MISMATCH)) {
	    return array($ret->wrap(__FILE__, __LINE__), null);
	}
	if (isset($theme)) {
	    list ($ret, $validTheme) = $theme->isActive();
	    if ($ret->isError()) {
		return array($ret->wrap(__FILE__, __LINE__), null);
	    }
	}

	if (!$validTheme) {
	    $theme = null;
	}

	return array(GalleryStatus::success(), $theme);
    }
}
?>
