/**
 * EasyKat Framework
 * 
 * ported from Zend Framework 0.1.4 
 * Copyright (c) 2006 Zend Technologies USA Inc. (http://www.zend.com)
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.plansoft.de/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to info@plansoft.de so we can send you a copy immediately.
 *
 * @category   EasyKat
 * @package    EasyKat.Controller
 * @subpackage Dispatcher
 * @copyright  Copyright (c) 2007 Plan Software GmbH (http://www.plansoft.de)
 * @license    http://www.plansoft.de/license/new-bsd     New BSD License
 * @version	   $Id$
 */
EasyKat.Controller.Dispatcher = function()
{}

EasyKat.Controller.Dispatcher.prototype = {
	/**
     * Directory where EasyKat.Controller.Action files are stored.
     * @var string
     */
    _directory : null,


    /**
     * Formats a string into a controller name.  This is used to take a raw
     * controller name, such as one that would be packaged inside a EasyKat.Controller.Dispatcher.Token
     * object, and reformat it to a proper class name that a class extending
     * EasyKat.Controller.Action would use.
     *
     * @param string unformatted
     * @return string
     */
    formatControllerName : function(unformatted)
    {
        if (!unformatted)
            return "IndexController";
	    return this._formatName(unformatted.ucfirst()) + 'Controller';
    },


    /**
     * Formats a string into an action name.  This is used to take a raw
     * action name, such as one that would be packaged inside a EasyKat.Controller.Dispatcher.Token
     * object, and reformat into a proper method name that would be found
     * inside a class extending EasyKat.Controller.Action.
     *
     * @param string unformatted
     * @return string
     */
	formatActionName : function(unformatted)
	{
	    var formatted = this._formatName(unformatted);
		return formatted.charAt(0).toLowerCase() + formatted.substring(1) + 'Action';
	},


    /**
     * Formats a string from a URI into a PHP-friendly name.  Replaces words
     * separated by "-", "_", or "." with camelCaps and removes any characters
     * that are not alphanumeric.
     *
     * @param string unformatted
     * @return string
     */
    _formatName : function(unformatted)
    {
		if ( unformatted.match(/[-_\.]/g) ) {
			var unformatted = unformatted.replace(['-', '_', '.'], ' ').toLowerCase();
			unformatted = unformatted.replace( /[^a-z0-9 ]/, '' );
			return unformatted.ucwords().replace(' ', '' );
		}
		
		return unformatted;
    },


    /**
     * Sets the directory where the EasyKat.Controller.Action class files are stored.
     *
     * @param string dir
     */
    setControllerDirectory : function(dir)
    {
		/*
        if (!is_dir(dir) or !is_readable(dir)) {
            throw new EasyKat.Controller.Dispatcher.Exception("Directory \"dir\" not found or not readable.");
        }
		*/

        this._directory = dir.trimRight('/\\');
    },


    /**
     * Returns TRUE if the EasyKat.Controller.Dispatcher.Token object can be dispatched to a controller.
     * This only verifies that the EasyKat.Controller.Action can be dispatched and does not
     * guarantee that the action will be accepted by the EasyKat.Controller.Action.
     *
     * @param EasyKat_Controller_Dispatcher_Token action
     * @return unknown
     */
	isDispatchable : function(action)
	{
        return this._dispatch(action, false);
	},


	/**
	 * Dispatch to a controller/action
	 *
	 * @param EasyKat.Controller.Dispatcher.Token action
	 * @return boolean|EasyKat.Controller.Dispatcher.Token
	 */
	dispatch : function(action)
	{
	    return this._dispatch(action, true);
	},


	/**
	 * If performDispatch is FALSE, this method will check if a controller
	 * file exists.  This still doesn't necessarily mean that it can be dispatched
	 * in the stricted sense, as file may not contain the controller class or the
	 * controller may reject the action.
	 *
	 * If performDispatch is TRUE, then this method will actually
	 * instantiate the controller and call its action.  Calling the action
	 * is done by passing a EasyKat.Controller.Dispatcher.Token to the controller's constructor.
	 *
	 * @param EasyKat.Controller.Dispatcher.Token action
	 * @param boolean performDispatch
	 * @return boolean|EasyKat.Controller.Dispatcher.Token
	 */
	_dispatch : function(action, performDispatch)
	{
	    if (this._directory == null) {
	        throw new EasyKat.Controller.Dispatcher.Exception('Controller directory never set.  Use setControllerDirectory() first.');
	    }

	    var className  = this.formatControllerName(action.getControllerName());
		
	    /**
	     * If performDispatch is FALSE, only determine if the controller file
	     * can be accessed.
	     */
	    if (!performDispatch) {
	        return true;
	    }

		var controller = eval(className);
		
        if (!controller || typeof controller == "undefined") {
           throw new EasyKat.Controller.Dispatcher.Exception("Controller \"" + className + "\" is not an instance of EasyKat.Controller.Action.");
        }
            
		controller = new controller();
		
        /**
         * Dispatch
         *
         * Call the action of the EasyKat.Controller.Action.  It will return either null or a
         * new EasyKat.Controller.Dispatcher.Token object.  If a EasyKat.Controller.Dispatcher.Token object is returned, this will be returned
         * back to EasyKat.Controller.Front, which will call this again to forward to
         * another action.
         */
        var nextAction = controller.initialize(this, action);

        // Destroy the page controller instance
        controller = null;

        // Return either null (finished) or a EasyKat.Controller.Dispatcher.Token object (forward to another action).
        return nextAction;
	}
}
