<?php
/*
 * $RCSfile: GalleryController.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.28 $ $Date: 2005/08/23 03:49:02 $
 * @package GalleryCore
 * @author Bharat Mediratta <bharat@menalto.com>
 */

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

    /**
     * Take the appropriate action based on the user input provided.
     *
     * When done, we return a data structure with results from the controller's actions and
     * information about where we should send the user next.  We can either delegate the user
     * to a view in the same request, or we can redirect the user to a different url.  Whenever
     * a controller makes a change to the data model, it should pass back a redirect so that
     * the browser is sent to a fresh page.  Otherwise if you hit reload on the browser it will
     * want to re-post the form data and it will attempt to change the model again, which may
     * not be what the user wants.
     *
     * To redirect, return:
     * <pre>
     *     array('redirect' => [url params],
     *           'status' => [status data])
     * </pre>
     *
     * To delegate, return:
     * <pre>
     *     array('delegate' => [url params],
     *           'return' => [boolean],   <i>optional</i>
     *           'error' => [error],
     *           'status' => [status data])
     * </pre>
     *
     * If you delegate, your form and request variables will persist to the view, since it is
     * being handled inside the same request.  However, if you redirect you'll have to put any
     * form variables that you want to pass to the subsequent view into the redirect url, since
     * it will be processed in a new request.  The browser will receive a redirect and then post
     * the new url.  So for example, if you want to redirect to a confirmation view and specify
     * a username to that view, you'd return:
     *
     * <pre>
     *    array('redirect' => array('view' => 'module.Confirmation',
     *                              'username' => 'johndoe'),
     *          'status' => array('success' => 'true'),
     *          'error' => array())
     * </pre>
     *
     * <b>Status</b> data is passed to the view and can be in any form that you want.
     * Typically it's simple key value pairs, like this:
     * <pre>
     *    array('myAction' => 'wasSuccessful')
     * </pre>
     *
     * If you pass status data back on a redirect, it will be automatically stored in the session
     * and the url will be modified to contain a marker to this status information.  After the
     * redirect, we'll retrieve it back from the database and pass it to the view.  Status data
     * sent back upon delegation is passed directly to the view.
     *
     * <b>Error</b> data is an array of values, like this:
     * <pre>
     *    array('form[widget][missing]')
     * </pre>
     *
     * This data is only processed on delegation.  It gets put into the request and is accessible
     * when the delegated view is called.  Since we only redirect on success, you never pass back
     * error data when you redirect.
     *
     * <b>Return</b> is a special parameter.  If you set this to a non-false value, it will look
     * for a special request variable called "return" in the request scope.  This variable is
     * expected to contain a URL, and we'll return a redirect to that URL.  This is useful in
     * the case where we want to use this controller in the middle of a workflow.  A good example
     * of this is when we click the "Login" link on the main page.  We pass control to the
     * UserLogin controller, and when its done, it uses the "return" flag to indicate that we
     * should return to the URL where the login link was clicked.
     *
     * @param array the form values
     * @return array object GalleryStatus a status code
     *               return-array
     */
    function handleRequest($form) {
	return array(GalleryStatus::error(ERROR_UNIMPLEMENTED, __FILE__, __LINE__),
		     null);
    }

    /**
     * Load a controller
     *
     * Be very security conscious about checking the inputs for possible misuse
     *
     * @param string a controller name (eg 'core.Logout')
     * @return array object GalleryStatus a status code
     *               object GalleryController a controller
     * @static
     */
    function loadController($controllerName) {
	global $gallery;

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

	/* If the module is not active, only let site admins use the config controller */
	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 ($controllerName == $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);
	    }
	}

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

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

	    GalleryCoreApi::relativeRequireOnce($fileName);

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

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