/**
 * @projectDescription
 * Класс для формирования запроса к флэшке-коннектору.
 *
 * @author Vlad Yakovlev (scorpix@design.ru)
 * @copyright Art.Lebedev Studio (http://www.artlebedev.ru)
 * @version 0.1
 * @requires SWFObject 2
 *
 * @example
 * var sc = new SWFConnector('SWFConnector.swf', 'connector', { version: '8.0.0' });
 *
 * sc.addCommand(1, 'play', [1, 2]).addCommand(2, 'stop', ']]>').sendCommands();
 *
 * sc.sendCommand(2, 'stop');
 *
 * sc.addCommand(1, 'play', [1, 2]).addCommand(2, 'stop', ']]>').sendAndSave();
 * // Очистка команд не произошла.
 * alert(sc.toString());
 * // Добавляем еще одну команду и отправляем в итоге 3 команды коннектору.
 * sc.addCommand(3, 'hide').sendCommands();
 */

/**
 * Класс для формирования запроса к флэшке-коннектору.
 * @param {String} connectorPath Путь к swf-файлу коннектора.
 * @param {String} htmlId Идентификатор html-элемента, который будет замещен флэшкой.
 * @param {Object} options Настройки:
 * <ul>
 *  <li><code>version</code> - версия Flash (по умолчанию - 9.0.0).
 * </ul>
 * @constructor
 * @type {Object}
 * @return {SWFConnector}
 */
function SWFConnector(connectorPath, htmlId, options) {
	/**
	 * Массив объектов с данными о команде.
	 * @private
	 */
	this.commands = [];

	/**
	 * Путь к swf-файлу коннектора.
	 * @type {String}
	 * @private
	 */
	this.connectorPath = connectorPath;

	/**
	 * Идентификатор родительского html-элемента.
	 * @type {String}
	 * @private
	 */
	this.htmlId = htmlId;

	/**
	 * Настройки
	 * @type Object
	 * @private
	 */
	this.options = {
		version: options && options.version ? options.version : '9.0.0'
	};
}

SWFConnector.prototype = {

	/**
	 * Добавляет команду для пакетной отправки коннектору.
	 * @param {Number} connectionId Идентификатор соединения.
	 * @param {String} methodName Название команды.
	 * @param {Array, String} params Параметры команды (необязательный параметр).
	 * @return {SWFConnector}
	 */
	addCommand: function(connectionId, methodName, params) {
		this.commands.push({
			connectionId: connectionId,
			methodName: methodName,
			params: this._formatParams(params)
		});

		return this;
	},

	/**
	 * Очищает список команд.
	 * @return {SWFConnector}
	 */
	clearCommands: function() {
		this.commands = [];

		return this;
	},

	/**
	 * Отправляет коннектору одиночную команду. Очистка списка команд не происходит.
	 * @param {Number} connectionId Идентификатор соединения.
	 * @param {String} methodName Название команды.
	 * @param {Array, String} params Параметры команды (необязательный параметр).
	 * @return {SWFConnector}
	 */
	sendCommand: function(connectionId, methodName, params) {
		this._send(this._command2String(connectionId, methodName, this._formatParams(params)));

		return this;
	},

	/**
	 * Отправляет пакет команд коннектору.
	 * @return {SWFConnector}
	 */
	sendCommands: function() {
		this._send(this.toString());
		this.clearCommands();

		return this;
	},

	/**
	 * Отправляет пакет команд коннектору. Очистка списка команд не происходит.
	 * @return {SWFConnector}
	 */
	sendAndSave: function() {
		this._send(this.toString());

		return this;
	},

	/**
	 * Преобразует данные в XML строку (все параметры заключены в CDATA).
	 * @return {String} Строка, содержащая валидный XML.
	 */
	toString: function() {
		var result = '';

		for (i = 0; i < this.commands.length; i++) {
			result += this._command2String(this.commands[i].connectionId, this.commands[i].methodName, this.commands[i].params);
		}

		return result;
	},

	/**
	 * Преобразует команду в строку.
	 * @param {Number} connectionId Идентификатор соединения.
	 * @param {String} methodName Название команды.
	 * @param {Array} params Параметры команды (необязательный параметр).
	 * @return {String} Строка, содержащая валидный XML.
	 * @private
	 */
	_command2String: function(connectionId, methodName, params) {
		var plainParams = '';

		if (params) {
			for (ii = 0; ii < params.length; ii++) {
				/** Экранированный параметр */
				var param = params[ii].toString().replace(/]]>/g, ']]]]><![CDATA[>');

				plainParams += '<param><![CDATA[' + param + ']]></param>';
			}
		}

		var result = '<command targetConnectionID="' + connectionId + '" methodName="' + methodName + '">' + plainParams + '</command>';

		// Для IE преобразуем кавычки в "&quot;".
		return (/MSIE/.test(navigator.userAgent)) ? result.replace(/"/g, '&quot;') : result;
	},

	/**
	 * Преобразует параметры в массив.
	 * @param {Array, String} params Параметр(ы).
	 * @return {Array} Параметры в массиве.
	 * @private
	 */
	_formatParams: function(params) {
		if ('object' == typeof params) {
			return params;
		}

		return params ? [params] : null;
	},

	/**
	 * Отправляет запрос коннектору.
	 * @param {String} plainCommands Строка, содержащая валидный XML.
	 * @private
	 */
	_send: function(plainCommands) {
		swfobject.embedSWF(this.connectorPath, this.htmlId, '1', '1', this.options.version, '', {'xml_commands': plainCommands}, {allowScriptAccess: 'always'});
	}
};