/**
 * AddOnManager.js
 *
 * Copyright 2009, Moxiecode Systems AB
 * Released under LGPL License.
 *
 * License: http://tinymce.moxiecode.com/license
 * Contributing: http://tinymce.moxiecode.com/contributing
 */

(function(tinymce) {
	var Dispatcher = tinymce.util.Dispatcher, each = tinymce.each;

	/**
	 * This class handles the loading of themes/plugins or other add-ons and their language packs.
	 *
	 * @class tinymce.AddOnManager
	 */
	tinymce.create('tinymce.AddOnManager', {
		AddOnManager : function() {
			var self = this;

			self.items = [];
			self.urls = {};
			self.lookup = {};
			self.onAdd = new Dispatcher(self);
		},

		/**
		 * Fires when a item is added.
		 *
		 * @event onAdd
		 */

		/**
		 * Returns the specified add on by the short name.
		 *
		 * @method get
		 * @param {String} n Add-on to look for.
		 * @return {tinymce.Theme/tinymce.Plugin} Theme or plugin add-on instance or undefined.
		 */
		get : function(n) {
			if (this.lookup[n]) {
				return this.lookup[n].instance;
			} else {
				return undefined;
			}
		},

		dependencies : function(n) {
			var result;
			if (this.lookup[n]) {
				result = this.lookup[n].dependencies;
			}
			return result || [];
		},

		/**
		 * Loads a language pack for the specified add-on.
		 *
		 * @method requireLangPack
		 * @param {String} n Short name of the add-on.
		 */
		requireLangPack : function(n) {
			var s = tinymce.settings;

			if (s && s.language && s.language_load !== false)
				tinymce.ScriptLoader.add(this.urls[n] + '/langs/' + s.language + '.js');
		},

		/**
		 * Adds a instance of the add-on by it's short name.
		 *
		 * @method add
		 * @param {String} id Short name/id for the add-on.
		 * @param {tinymce.Theme/tinymce.Plugin} o Theme or plugin to add.
		 * @return {tinymce.Theme/tinymce.Plugin} The same theme or plugin instance that got passed in.
		 * @example
		 * // Create a simple plugin
		 * tinymce.create('tinymce.plugins.TestPlugin', {
		 *     TestPlugin : function(ed, url) {
		 *         ed.onClick.add(function(ed, e) {
		 *             ed.windowManager.alert('Hello World!');
		 *         });
		 *     }
		 * });
		 * 
		 * // Register plugin using the add method
		 * tinymce.PluginManager.add('test', tinymce.plugins.TestPlugin);
		 * 
		 * // Initialize TinyMCE
		 * tinyMCE.init({
		 *    ...
		 *    plugins : '-test' // Init the plugin but don't try to load it
		 * });
		 */
		add : function(id, o, dependencies) {
			this.items.push(o);
			this.lookup[id] = {instance:o, dependencies:dependencies};
			this.onAdd.dispatch(this, id, o);

			return o;
		},
		createUrl: function(baseUrl, dep) {
			if (typeof dep === "object") {
				return dep
			} else {
				return {prefix: baseUrl.prefix, resource: dep, suffix: baseUrl.suffix};
			}
		},

		/**
	 	 * Add a set of components that will make up the add-on. Using the url of the add-on name as the base url.
		 * This should be used in development mode.  A new compressor/javascript munger process will ensure that the 
		 * components are put together into the editor_plugin.js file and compressed correctly.
		 * @param pluginName {String} name of the plugin to load scripts from (will be used to get the base url for the plugins).
		 * @param scripts {Array} Array containing the names of the scripts to load.
	 	 */
		addComponents: function(pluginName, scripts) {
			var pluginUrl = this.urls[pluginName];
			tinymce.each(scripts, function(script){
				tinymce.ScriptLoader.add(pluginUrl+"/"+script);	
			});
		},

		/**
		 * Loads an add-on from a specific url.
		 *
		 * @method load
		 * @param {String} n Short name of the add-on that gets loaded.
		 * @param {String} u URL to the add-on that will get loaded.
		 * @param {function} cb Optional callback to execute ones the add-on is loaded.
		 * @param {Object} s Optional scope to execute the callback in.
		 * @example
		 * // Loads a plugin from an external URL
		 * tinymce.PluginManager.load('myplugin', '/some/dir/someplugin/editor_plugin.js');
		 *
		 * // Initialize TinyMCE
		 * tinyMCE.init({
		 *    ...
		 *    plugins : '-myplugin' // Don't try to load it again
		 * });
		 */
		load : function(n, u, cb, s) {
			var t = this, url = u;

			function loadDependencies() {
				var dependencies = t.dependencies(n);
				tinymce.each(dependencies, function(dep) {
					var newUrl = t.createUrl(u, dep);
					t.load(newUrl.resource, newUrl, undefined, undefined);
				});
				if (cb) {
					if (s) {
						cb.call(s);
					} else {
						cb.call(tinymce.ScriptLoader);
					}
				}
			}

			if (t.urls[n])
				return;
			if (typeof u === "object")
				url = u.prefix + u.resource + u.suffix;

			if (url.indexOf('/') != 0 && url.indexOf('://') == -1)
				url = tinymce.baseURL + '/' + url;

			t.urls[n] = url.substring(0, url.lastIndexOf('/'));

			if (t.lookup[n]) {
				loadDependencies();
			} else {
				tinymce.ScriptLoader.add(url, loadDependencies, s);
			}
		}
	});

	// Create plugin and theme managers
	tinymce.PluginManager = new tinymce.AddOnManager();
	tinymce.ThemeManager = new tinymce.AddOnManager();
}(tinymce));

/**
 * TinyMCE theme class.
 *
 * @class tinymce.Theme
 */

/**
 * Initializes the theme.
 *
 * @method init
 * @param {tinymce.Editor} editor Editor instance that created the theme instance.
 * @param {String} url Absolute URL where the theme is located. 
 */

/**
 * Meta info method, this method gets executed when TinyMCE wants to present information about the theme for example in the about/help dialog.
 *
 * @method getInfo
 * @return {Object} Returns an object with meta information about the theme the current items are longname, author, authorurl, infourl and version.
 */

/**
 * This method is responsible for rendering/generating the overall user interface with toolbars, buttons, iframe containers etc.
 *
 * @method renderUI
 * @param {Object} obj Object parameter containing the targetNode DOM node that will be replaced visually with an editor instance. 
 * @return {Object} an object with items like iframeContainer, editorContainer, sizeContainer, deltaWidth, deltaHeight. 
 */

/**
 * Plugin base class, this is a pseudo class that describes how a plugin is to be created for TinyMCE. The methods below are all optional.
 *
 * @class tinymce.Plugin
 * @example
 * // Create a new plugin class
 * tinymce.create('tinymce.plugins.ExamplePlugin', {
 *     init : function(ed, url) {
 *         // Register an example button
 *         ed.addButton('example', {
 *             title : 'example.desc',
 *             onclick : function() {
 *                  // Display an alert when the user clicks the button
 *                  ed.windowManager.alert('Hello world!');
 *             },
 *             'class' : 'bold' // Use the bold icon from the theme
 *         });
 *     }
 * });
 * 
 * // Register plugin with a short name
 * tinymce.PluginManager.add('example', tinymce.plugins.ExamplePlugin);
 * 
 * // Initialize TinyMCE with the new plugin and button
 * tinyMCE.init({
 *    ...
 *    plugins : '-example', // - means TinyMCE will not try to load it
 *    theme_advanced_buttons1 : 'example' // Add the new example button to the toolbar
 * });
 */

/**
 * Initialization function for the plugin. This will be called when the plugin is created. 
 *
 * @method init
 * @param {tinymce.Editor} editor Editor instance that created the plugin instance. 
 * @param {String} url Absolute URL where the plugin is located. 
 * @example
 * // Creates a new plugin class
 * tinymce.create('tinymce.plugins.ExamplePlugin', {
 *     init : function(ed, url) {
 *         // Register the command so that it can be invoked by using tinyMCE.activeEditor.execCommand('mceExample');
 *         ed.addCommand('mceExample', function() {
 *             ed.windowManager.open({
 *                 file : url + '/dialog.htm',
 *                 width : 320 + ed.getLang('example.delta_width', 0),
 *                 height : 120 + ed.getLang('example.delta_height', 0),
 *                 inline : 1
 *             }, {
 *                 plugin_url : url, // Plugin absolute URL
 *                 some_custom_arg : 'custom arg' // Custom argument
 *             });
 *         });
 * 
 *         // Register example button
 *         ed.addButton('example', {
 *             title : 'example.desc',
 *             cmd : 'mceExample',
 *             image : url + '/img/example.gif'
 *         });
 * 
 *         // Add a node change handler, selects the button in the UI when a image is selected
 *         ed.onNodeChange.add(function(ed, cm, n) {
 *             cm.setActive('example', n.nodeName == 'IMG');
 *         });
 *     }
 * });
 * 
 * // Register plugin
 * tinymce.PluginManager.add('example', tinymce.plugins.ExamplePlugin);
 */

/**
 * Meta info method, this method gets executed when TinyMCE wants to present information about the plugin for example in the about/help dialog.
 *
 * @method getInfo
 * @return {Object} Returns an object with meta information about the plugin the current items are longname, author, authorurl, infourl and version.
 * @example 
 * // Creates a new plugin class
 * tinymce.create('tinymce.plugins.ExamplePlugin', {
 *     // Meta info method
 *     getInfo : function() {
 *         return {
 *             longname : 'Example plugin',
 *             author : 'Some author',
 *             authorurl : 'http://tinymce.moxiecode.com',
 *             infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/example',
 *             version : "1.0"
 *         };
 *     }
 * });
 * 
 * // Register plugin
 * tinymce.PluginManager.add('example', tinymce.plugins.ExamplePlugin);
 * 
 * // Initialize TinyMCE with the new plugin
 * tinyMCE.init({
 *    ...
 *    plugins : '-example' // - means TinyMCE will not try to load it
 * });
 */

/**
 * Gets called when a new control instance is created.
 *
 * @method createControl
 * @param {String} name Control name to create for example "mylistbox" 
 * @param {tinymce.ControlManager} controlman Control manager/factory to use to create the control. 
 * @return {tinymce.ui.Control} Returns a new control instance or null.
 * @example 
 * // Creates a new plugin class
 * tinymce.create('tinymce.plugins.ExamplePlugin', {
 *     createControl: function(n, cm) {
 *         switch (n) {
 *             case 'mylistbox':
 *                 var mlb = cm.createListBox('mylistbox', {
 *                      title : 'My list box',
 *                      onselect : function(v) {
 *                          tinyMCE.activeEditor.windowManager.alert('Value selected:' + v);
 *                      }
 *                 });
 * 
 *                 // Add some values to the list box
 *                 mlb.add('Some item 1', 'val1');
 *                 mlb.add('some item 2', 'val2');
 *                 mlb.add('some item 3', 'val3');
 * 
 *                 // Return the new listbox instance
 *                 return mlb;
 *         }
 * 
 *         return null;
 *     }
 * });
 * 
 * // Register plugin
 * tinymce.PluginManager.add('example', tinymce.plugins.ExamplePlugin);
 * 
 * // Initialize TinyMCE with the new plugin and button
 * tinyMCE.init({
 *    ...
 *    plugins : '-example', // - means TinyMCE will not try to load it
 *    theme_advanced_buttons1 : 'mylistbox' // Add the new mylistbox control to the toolbar
 * });
 */