/**
 * Aloha Editor User Interface API Semantics
 * =========================================
 *
 * Note
 * ===
 *    * This documentation is "thinking out loud," and very much "work in work
 *      in progress--as is the Aloha UI API itself.
 *
 *    * For flexibility and ease, it seems that it would be best that the Aloha
 *      UI API will not constrain the developer to these semantics, but will
 *      naively assume that these semantics are observed.
 *
 * Components (Buttons, Labels, Icons)
 * ---
 * Aloha Editor represents its user interface using objects called
 * `components`.  A uniform interface for these components allows them to be
 * agnostic to what container they are rendered on.
 *
 * Controls (Buttons)
 * ---
 * Interactive components like buttons, are called `controls`, to distinguish
 * them from non-interactive components like labels, and icons.
 *
 * Containers (Tabs, Panels)
 * ---
 * In rendering the UI, components are organized in visual groups, and these
 * groups are in turn bundled onto `containers`.  Containers can be tabs, as in
 * the case of the floating menu, or panels like in the sidebar.  Containers
 * allow a collection of controls that represent a feature set to be rendered
 * as a group and to be brought in and out of view together.
 *
 * Surfaces (Toolbar, Sidebar, Ribbon)
 * ---
 * `Surfaces` are areas on a web page in which containers can be placed.  The
 * sidebar, and the toolbar are examples of such surfaces.  The possibility
 * exists for other surfaces to be defined--such as a ribbon, or a footer menu.
 *
 *
 * Class structure
 * ===
 *
 *         Surface
 *	          |
 *	     ,----+----.
 *       |         |
 *	  Toolbar   Sidebar
 *
 *
 *        Container
 *	          |
 *	     ,----+----.
 *       |         |
 *	   Panel      Tab
 *
 *
 *        Component
 *            |
 *	     ,----+----.
 *       |         |
 *	   Label    Control
 *
 *
 * Enforcing good dependencies
 * ===
 * In order to void subtle errors that arise from erroneous dependency
 * declarations, we will have ill-defined or missing dependencies fail early
 * and noisily.  We achieve this by never exposing individual modules through
 * the Aloha.ui hash unless absolutely necessary. Modules are accessibly only
 * through require.
 *
 * How this works:
 * For example, a ui module "uiModule" would not be exposed through
 * `Aloha.ui.uiModule` but from require's `define` call:
 *
 *		define([ 'ui/uiModule' ], function( uiModule ) {});
 *
 * or
 *
 *		var uiModule = Aloha.require( 'ui/uiModule' );
 * 
 * This will force more deliberate and precise usage of dependencies.  The
 * developer will have to know exactly which direct dependencies they are using;
 * any missing or unsuccessfully require dependency will not inadvertantly be
 * provided from another require somewhere else in Aloha thereby silencing an
 * error that will emerge unexpectedly if that require is ever removed.
 */

define('ui/ui', [
	'jquery',
	'ui/ui-plugin'
],
function(
	$,
	UiPlugin
) {
	'use strict';

	/**
	 * A hash map of components mapped against the slots into which they have
	 * been adopted.
	 *
	 * @type {Object<string, Component>}
	 */
	var components = {};

	/**
	 * Adopts a component into the UI.
	 *
	 * Only adopted components will become part of the UI.
	 *
	 * Where the component is placed is decided by looking the name up
	 * in the configuration.
	 * 
	 * If adoption is successful, the component will have its
	 * adoptParent() method invoked by the container the component ends
	 * up in.
	 *
	 * @param {string?} name
	 *        Names the component to be adopted.
	 *        The name is used by the UI to identify the component,
	 *        and place the component.
	 *        Making multiple calles with different components but
	 *        the same name is valid.
	 *        If not given, settings must be given and contain a
	 *        name property.
	 * @param {Object?} SuperTypeOrInstance
	 *        Either a component type that will be instantiated, or an
	 *        already instantiated component instance.
	 * @param {Object?} settings
	 *        An optional map of component settings which will be used
	 *        to extend the SuperType.
	 *        Ignored if an component instance is given.
	 *        Must contain a name property if no name is given.
	 * @return
	 *        If a SuperTypeOrInstance is a SuperType, the new component
	 *        instantiated from SuperType, or the given component
	 *        instance.
	 * @api
	 */
	function adopt(name, SuperTypeOrInstance, settings) {
		var Type,
		    component;

		if ('string' !== $.type(name)) {
			settings = SuperTypeOrInstance;
			SuperTypeOrInstance = name;
			name = settings.name;
		} else {
			settings = $.extend({name: name}, settings);
		}

		if (!SuperTypeOrInstance.isInstance) {
			Type = settings ? SuperTypeOrInstance.extend(settings) : SuperTypeOrInstance;
			component = new Type();
		} else {
			component = SuperTypeOrInstance;
		}

		components[name] = component;
		UiPlugin.adoptInto(name, component);

		return component;
	}

	/**
	 * Retreives the component that was adopted at the given UI slot.
	 *
	 * @param {string} slot The name of the slot.
	 * @return {Component?} A component, or null if no slot was adopted
	 *                      into the slot.
	 */
	function getComponentAtSlot(slot) {
		return components[slot] || null;
	}

	return {
		adopt: adopt,
		getAdoptedComponent: getComponentAtSlot
	};
});
