(function() {
var L = YAHOO.lang, Dom = YAHOO.util.Dom, Evt = YAHOO.util.Event, U = ZC.Util, _GT = U.GetText, JSManager = ZC.JSManager;
var oEL;

/**
 * Core CMS components
 * @module Core
 */

/**
 * Opens up an alert box. Expects the contents to be in the 'Message' attribute.
 * @namespace ZC.Core.EventListener
 * @class Alert
 * @extends ZC.Core.EventListener
 */
oEL = ZC.Core.EventListener.Create('Alert');
oEL.prototype.HandleEvent = function(oWidget, oEvent, oSrcEvent)
{
	if (this.AttribIsset('Message'))
		JSManager.Alert(this.GetAttrib('Message'));
}


/**
 * Enables or disables a widget.
 *
 * @namespace ZC.Core.EventListener
 * @class EnableDisable
 * @extends ZC.Core.EventListener
 */
oEL = ZC.Core.EventListener.Create('EnableDisable');
oEL.prototype.HandleEvent = function(oWidget, oEvent, oSrcEvent)
{
	var bEnable, sEnabledClass, sDisabledClass, sPopulateWhenDisabledFrom, mValueWhenDisabled, oPopulateFromWidget;

	bEnable = this._SearchLists(
		this._GetWidgetValue(oWidget),
		'EnableWhenSrcEquals',
		'EnableWhenSrcNotEquals',
		'EnableWhenSrcContains',
		'EnableWhenSrcNotContains'
	);

	sEnabledClass = this.GetAttribDefault('EnabledClass', '');
	sDisabledClass = this.GetAttribDefault('DisabledClass', 'disabled');

	this.oDestWidget.Enable(bEnable, sEnabledClass, sDisabledClass);
	if (bEnable)
	{
		if (!L.isUndefined(this.ValueWhenEnabled))
		{
			this.oDestWidget.SetValue(this.ValueWhenEnabled);
			delete this.ValueWhenEnabled;
		}
		return;
	}

	if (this.AttribIsset('ValueWhenDisabled'))
	{
		mValueWhenDisabled = this.GetAttrib('ValueWhenDisabled');
	}
	else if (sPopulateWhenDisabledFrom = this.GetAttribDefault('PopulateWhenDisabledFrom')) // assignment
	{
		oPopulateFromWidget = JSManager.GetWidget(sPopulateWhenDisabledFrom);
		if (oPopulateFromWidget)
			mValueWhenDisabled = oPopulateFromWidget.GetValue();
	}	

	if (!L.isUndefined(mValueWhenDisabled))
	{
		// save old value, restore if we enable again
		this.ValueWhenEnabled = this.oDestWidget.GetValue();
		this.oDestWidget.SetValue(mValueWhenDisabled);
	}	
}

/**
 * Enables or disables a tab in a Tabview block.
 *
 * @namespace ZC.Core.EventListener
 * @class EnableDisableTab
 * @extends ZC.Core.EventListener
 */
oEL = ZC.Core.EventListener.Create('EnableDisableTab');
oEL.prototype.HandleEvent = function(oWidget, oEvent, oSrcEvent)
{
	var oTabView = JSManager.GetWidget(this.GetAttrib('TabViewName')), bEnable;
	if (!L.isUndefined(oTabView))
	{
		bEnable = this._SearchLists(
			this._GetWidgetValue(oWidget), 
			'EnableWhenSrcEquals',
			'EnableWhenSrcNotEquals',
			'EnableWhenSrcContains',
			'EnableWhenSrcNotContains'
		);
		oTabView.EnableTab(this.GetAttrib('TabID'), bEnable);
	}
}

/**
 * EventListener used by the Core_Widget_Image_SelectOrUpload widget
 *
 * TODO: the whole SelectOrUpload widget possibly wants replacing
 * it could probably be done with a ShowHide eventlistener
 *
 * @namespace ZC.Core.EventListener
 * @class SelectOrUpload
 * @extends ZC.Core.EventListener
 */
oEL = ZC.Core.EventListener.Create('SelectOrUpload');
oEL.prototype.HandleEvent = function(oWidget, oEvent, oSrcEvent)
{
	var sDestId = this.oDestWidget._elInput.id,
	    eSelectDiv = Dom.get('div.' + sDestId + '.select'),
	    eUploadDiv = Dom.get('div.' + sDestId + '.upload');

	if (oWidget.GetValue() == 1)
	{
		eSelectDiv.style.display='block';
		eUploadDiv.style.display='none';
	}
	else
	{
		eSelectDiv.style.display='none';
		eUploadDiv.style.display='block';
	}
}

/**
 * Sets the options on a select widget to the contents of a Javascript array.
 * @namespace ZC.Core.EventListener
 * @class SetOptionsFromJSArray
 * @extends ZC.Core.EventListener
 */
oEL = ZC.Core.EventListener.Create('SetOptionsFromJSArray');
oEL.prototype.HandleEvent = function(oWidget, oEvent, oSrcEvent)
{
	if (!L.isUndefined(window[this.aDef.ArrayName]))
	{
		var aNewOptions = window[this.aDef.ArrayName][this._GetWidgetValue(oWidget)];
		this.oDestWidget.SetAttrib('Options', aNewOptions);
	}
}

/**
 * Makes an AJAX request to get the options for a select.
 * @namespace ZC.Core.EventListener
 * @class SetOptionsFromAjax
 * @extends ZC.Core.EventListener
 */
oEL = ZC.Core.EventListener.Create('SetOptionsFromAjax');
oEL.prototype.Setup = function()
{
	this.oSendFields = {};

	JSManager.GetEvent('ManagerInit').subscribe(function() {
		U.ForEach(this.GetAttribDefault('SendFields', {}), function(sWidgetName, sQueryParam)
		{
			var oWidget = this.oDestWidget.oForm.GetWidget(sWidgetName) || JSManager.GetWidget(sWidgetName);

			if (L.isNumber(sQueryParam))
				sQueryParam = sWidgetName;

			if (oWidget)
				this.oSendFields[sQueryParam] = oWidget;
		}, this);
	}, this, true);

	return true;
}

oEL.prototype.Destruct = function()
{
	oEL.superclass.Destruct.apply(this, arguments);

	this.oSendFields = {};
}

oEL.prototype.HandleEvent = function(oWidget, oEvent, oSrcEvent)
{
	var oCallback = {
			customevents: {
				onFailure: 	function()
				{
					JSManager.Alert(_GT("The server was unable to retrieve the data"));
				},
				onSuccess: 	function(sEventType, aArgs)
				{
					var oResponse = YAHOO.lang.JSON.parse(aArgs[0].responseText);
					this.oDestWidget.SetAttrib('Options', oResponse);
				}
			},
			scope: this
		},
		sURL = JSManager.URL(this.oSendFields, this.GetAttrib('AjaxURL'));

	YAHOO.util.Connect.asyncRequest('GET', sURL, oCallback);
}

/**
 * Copies the value of one widget to another
 * @namespace ZC.Core.EventListener
 * @class SetValue_FromSource
 * @extends ZC.Core.EventListener
 */
oEL = ZC.Core.EventListener.Create('SetValue_FromSource');
oEL.prototype.HandleEvent = function(oWidget, oEvent, oSrcEvent)
{
	oDestWidget.SetValue(this._GetWidgetValue(oWidget));
}

/**
 * Show or hide some elements
 *
 * @namespace ZC.Core.EventListener
 * @class ShowHideElements
 * @extends ZC.Core.EventListener
 */
oEL = ZC.Core.EventListener.Create('ShowHideElements');
oEL.prototype.HandleEvent = function(oWidget, oEvent, oSrcEvent)
{
   	var Elements, 
		bShow = this._SearchLists(
			this._GetWidgetValue(oWidget), 
			'ShowWhenSrcEquals', 
			'ShowWhenSrcNotEquals',
			'ShowWhenSrcContains',
			'ShowWhenSrcNotContains'
		);

	if (this.AttribIsset('ElementClass'))
	{
		Elements = Dom.getElementsByClassName(this.GetAttrib('ElementClass'), this.GetAttribDefault('ElementType', undefined));
	}
	else if (this.AttribIsset('ElementID'))
	{
		Elements = this.GetAttrib('ElementID');
	}
	else
	{
		// ElementType + ElementClass, or ElementID not specified. Default to the destination widget.
		this.oDestWidget.Show(bShow);
		return;
	}

	if (bShow)
	{
		Dom.removeClass(Elements, 'hide');
	}
	else
	{
		Dom.batch(Elements, function(el)
		{
			el.blur();
			Dom.addClass(el, 'hide');
		});
	}
}

/**
 * Calls a javascript function
 *
 * @namespace ZC.Core.EventListener
 * @class CallJSFunction
 * @extends ZC.Core.EventListener
 */
oEL = ZC.Core.EventListener.Create('CallJSFunction');
oEL.prototype.HandleEvent = function(oWidget, oEvent, oSrcEvent)
{
	if (this.aDef.JSArgs)
	{
		eval(this.aDef.JSFunction + '(' + this.aDef.JSArgs + ');');
	}
	else
	{
		// Check with CB
		// before JSFunction could not be a function like ZC.Util.DefaultLoadingIndicator.Show
		// as window['ZC.Util.DefaultLoadingIndicator.Show'] did not exist, 
		// rather the proper path would have been window['ZC']['Util']['DefaultLoadingIndicator']['Show']
		// Supplying a null JSArg would have worked as that just evals the function
		//var fn = window[this.aDef.JSFunction];
		var fn = eval(this.aDef.JSFunction);
		if (L.isFunction(fn))
			fn();
	}
}

/**
 * Calls a method on an object
 *
 * @namespace ZC.Core.EventListener
 * @class CallObjectMethod
 * @extends ZC.Core.EventListener
 */
oEL = ZC.Core.EventListener.Create('CallObjectMethod');
oEL.prototype.HandleEvent = function(oWidget, oEvent, oSrcEvent)
{
	var oObject = this.oDestination,
		sWidget = this.GetAttribDefault('Widget'),
		sBlockUID = this.GetAttribDefault('Block'),
		sMethod = this.GetAttrib('Method'),
		aArguments = this.GetAttribDefault('Arguments', []);

	if (sWidget)
		oObject = JSManager.GetWidget(sWidget);
	else if (sBlockUID)
		oObject = JSManager.GetBlockByUniqueID(sBlockUID);

	if (oObject && oObject[sMethod])
	{
		oObject[sMethod].apply(oObject, aArguments);
		if (this.GetAttribDefault('StopEvent'))
		{
			Evt.stopEvent(oSrcEvent);
		}
	}
}


/**
 * Sets options for linked select widgets
 *
 * @namespace ZC.Core.EventListener
 * @class SetRelatedOptions_FromSource
 * @extends ZC.Core.EventListener
 */
oEL = ZC.Core.EventListener.Create('SetRelatedOptions_FromSource');
oEL.prototype.HandleEvent = function(oWidget, oEvent, oSrcEvent)
{
	var elDest = Dom.get(this.aDef.ID + ".1");
	if (elDest)
		setOptionsRelatedTo(elDest, this._GetWidgetValue(oWidget));
}

/**
 * Sets options for linked select widgets
 *
 * @namespace ZC.Core.EventListener
 * @class SetRelatedOptions_FromInitialValue
 * @extends ZC.Core.EventListener
 */
oEL = ZC.Core.EventListener.Create('SetRelatedOptions_FromInitialValue');
oEL.prototype.HandleEvent = function(oWidget, oEvent, oSrcEvent)
{
	var sID = this.aDef.ID,
	    elDest = Dom.get(sID + '.1'),
	    elInitial = Dom.get(sID + '.initial'),
		opt = this._GetWidgetValue(oWidget) + '-' + elInitial.value;

	for (var i = 0, iMax = elDest.length; i < iMax; i++)
	{
		if (elDest.options[i].value == opt)
		{
			elDest.value=(opt);
			return;
		}
	}
}

/**
 * Makes an AJAX request, populating widgets on the form with the result.
 *
 * @namespace ZC.Core.EventListener
 * @class AutoPopulate
 * @extends ZC.Core.EventListener
 */
oEL = ZC.Core.EventListener.Create('AutoPopulate');
oEL.prototype.Setup = function()
{
	this.aCache = {};
	this.oLookupFields = {};

	if (this.oDestWidget.oParent != this.oDestWidget.oForm)
		this.oParent = this.oDestWidget.oParent;
	this.oForm = this.oDestWidget.oForm;

	JSManager.GetEvent('ManagerInit').subscribe(function()
	{
		U.ForEach(this.GetAttrib('LookupFields'), function(sField)
		{
			var oWidget = 
				(this.oParent && this.oParent.GetWidget(sField)) 
				|| this.oForm.GetWidget(sField)
				|| JSManager.GetWidget(sField);

			if (oWidget)
				this.oLookupFields[sField] = oWidget;
		}, this);
	}, this, true);

	var sLoadingElementID = this.GetAttribDefault('LoadingElement'), elLoading;
	if (sLoadingElementID && (elLoading = Dom.get(sLoadingElementID))) // assignment
	{
		this.elLoading = elLoading;
	}

	return true;
}
oEL.prototype.Destruct = function()
{
	oEL.superclass.Destruct.apply(this, arguments);
	this.oForm = null;
	this.aCache = {};
	this.oLookupFields = {};
	this.oParent = null;
}

oEL.prototype.HandleEvent = function(oWidget, oEvent, oSrcEvent)
{
	var oCallback = {
		customevents: {
			onStart: 	function() { Dom.addClass(this.elLoading, 'ap-loading'); },
			onComplete: function() { Dom.removeClass(this.elLoading, 'ap-loading'); },
			onFailure: 	function()
			{
				JSManager.Alert(_GT("The server was unable to retrieve the data"));
			},
			onSuccess: 	function(sEventType, aArgs)
			{
				var oResponse;
			   	if (sEventType == 'fromcache')
				{
					oResponse = aArgs;
				}
				else
				{
					oResponse = YAHOO.lang.JSON.parse(aArgs[0].responseText);
					this.aCache[sURL] = oResponse;
				}

				U.ForEach(oResponse, function(sValue, sKey)
				{
					var sFromColour = this.GetAttribDefault('AnimateFromColour', '#0cf'),
						oWidget, oAnim, sBG;

					oWidget = 
						(this.oParent && this.oParent.GetWidget(sKey)) 
						|| this.oForm.GetWidget(sKey)
						|| JSManager.GetWidget(sKey);

					if (sValue && oWidget)
					{
						oWidget.SetValue(sValue);

						if (this.GetAttribDefault('AnimateWhenLoaded', true))
						{
							oAnim = new YAHOO.util.ColorAnim(oWidget._elInput);
							sBG = oAnim.getAttribute('backgroundColor');

							oAnim.attributes = { backgroundColor: { from: sFromColour, to: sBG } };
							oAnim.duration = 0.5;
							oAnim.animate();
						}
					}
				}, this);
			}
		},
		scope: this
	},
		sURL = JSManager.URL(this.oLookupFields, this.GetAttrib('AjaxURL'));

	// this assumes we get the same value each time for the same query
	if (!L.isUndefined(this.aCache[sURL]))
	{
		oCallback.customevents.onSuccess.call(this, 'fromcache', this.aCache[sURL]);
	}
	else
	{
		YAHOO.util.Connect.asyncRequest('GET', sURL, oCallback);
	}
}

/**
 * Sets the value of a widget to a fixed value
 *
 * @namespace ZC.Core.EventListener
 * @class SetValue_ToValue
 * @extends ZC.Core.EventListener
 */
oEL = ZC.Core.EventListener.Create('SetValue_ToValue');
oEL.prototype.HandleEvent = function(oWidget, oEvent, oSrcEvent)
{
	if (!this._SearchLists(
		this._GetWidgetValue(oWidget), 
		'SetWhenSrcEquals', 
		'SetWhenSrcNotEquals',
		'SetWhenSrcContains', 
		'SetWhenSrcNotContains'
	))
		return;

	this.oDestWidget.SetValue(this.GetAttrib('Value'));
}

/**
 * Adds a value to the Group Matrix widget
 *
 * @namespace ZC.Core.EventListener
 * @class AddToGroupMatrix
 * @extends ZC.Core.EventListener
 */
oEL = ZC.Core.EventListener.Create('AddToGroupMatrix');
oEL.prototype.Setup = function()
{
	var aSrc = this.GetAttribDefault('SourceFields', []);
	if (!L.isArray(aSrc))
		aSrc = [aSrc];
	this.SetAttrib('SourceFields', aSrc);

	return true;
}
oEL.prototype.HandleEvent = function(oWidget, oEvent, oSrcEvent)
{
	var oParams = {}, bFoundValue = false,
	   	sURL, 
		oCallback = {
		customevents: {
			onFailure: 	function()
			{
				JSManager.Alert(_GT("The server was unable to retrieve the data"));
			},
			onSuccess: 	function(sEventType, aArgs)
			{
				var oResponse = YAHOO.lang.JSON.parse(aArgs[0].responseText),
				    sTarget = oResponse.Target,
					oTargetWidget = this.oDestWidget,
					oConfig = oResponse.JSConfig,
					sWidgetName;

				if (sTarget && sTarget != oTargetWidget.sName)
				{
					oTargetWidget = 
						(this.oParent && this.oParent.GetWidget(sTarget))
						|| (this.oDestWidget.oForm && this.oDestWidget.oForm.GetWidget(sTarget))
						|| JSManager.GetWidget(sTarget);
				}

				if (oTargetWidget)
				{
					oTargetWidget.AddRow(oResponse.RowID, oResponse.Caption, oResponse.Widgets, oResponse.JSConfig);
				}
			}
		},
		scope: this
	};
   	
	U.ForEach(this.GetAttrib('SourceFields'), function(sWidgetName, sKey)
	{
		var oSrcWidget = 
			(this.oParent && this.oParent.GetWidget(sWidgetName))
			|| (this.oDestWidget.oForm && this.oDestWidget.oForm.GetWidget(sWidgetName))
			|| JSManager.GetWidget(sWidgetName);

		if (oSrcWidget)
		{
			if (!L.isString(sKey))
				sKey = oSrcWidget.sName;
				
			if (oSrcWidget.GetValue())
			{
				bFoundValue = true;
				oParams[sKey] = oSrcWidget.GetValue();
				oSrcWidget.Clear();
			}
		}
	}, this);

	if (!bFoundValue)
	{
		U.Alert("Please select something to add to the table.");
	}
	else
	{
		sURL = JSManager.URL(oParams, this.GetAttrib('AjaxURL'));

		YAHOO.util.Connect.asyncRequest('GET', sURL, oCallback);
	}
}

/**
 * Removes a value from the Group Matrix widget
 *
 * @namespace ZC.Core.EventListener
 * @class RemoveFromGroupMatrix
 * @extends ZC.Core.EventListener
 */
oEL = ZC.Core.EventListener.Create('RemoveFromGroupMatrix');
oEL.prototype.Setup = function()
{
	var sMatrixID = this.GetAttribDefault('MatrixID'),
		sRowID = this.GetAttribDefault('RowID'),
		oWidget = this.oDestWidget;

	if (!sMatrixID)
	{
		while (oWidget && !(oWidget instanceof ZC.Core.Widget.Group_Matrix))
		{
			oWidget = oWidget.oParent;
		}
	}
	else
	{
		oWidget = oWidget.GetWidget(sMatrixID) 
			|| oWidget.oForm.GetWidget(sMatrixID)
			|| JSManager.GetWidget(sMatrixID);
	}
	if (L.isUndefined(oWidget))
		return false;

	if (!sRowID)
	{
		sRowID = oWidget.FindRowIDWithElement(this.oDestWidget._elInput);
		if (sRowID)
			this.SetAttrib('RowID', sRowID);
	}

	this.oMatrix = oWidget;
	return this.AttribIsset('RowID');
}
oEL.prototype.Destruct  = function()
{
	oEL.superclass.Destruct.apply(this, arguments);
	this.oMatrix = null;
}
oEL.prototype.HandleEvent = function(oWidget, oEvent, oSrcEvent)
{
	U.Confirm('Are you sure you want to remove ' + this.oMatrix.GetRowCaption(this.GetAttrib('RowID')) + '?', this, function() 
	{
		this.oMatrix.RemoveRow(this.GetAttrib('RowID'));		
	});
}

/**
 * Sets attribs on a widget to the value of another widget on the form
 *
 * @namespace ZC.Core.EventListener
 * @class SetAttribFromField
 * @extends ZC.Core.EventListener
 */
oEL = ZC.Core.EventListener.Create('SetAttribFromField');
oEL.prototype.HandleEvent = function(oWidget, oEvent, oSrcEvent)
{
	U.ForEach(this.GetAttrib('AttribsToSet'), function(mField, sAttrib)
	{
		if (!L.isArray(mField))
			mField = [mField];

		for (var i = 0, iMax = mField.length; i < iMax; i++)
		{
			var oWidget = this.oDestWidget.oForm.GetWidget(mField[i]) || JSManager.GetWidget(mField[i]);
			
			if (oWidget && oWidget.HasValue())
			{
				this.oDestWidget.SetAttrib(sAttrib, oWidget.GetValue());
				return;
			}
		}
	}, this);
}

/**
 * Makes an Ajax request on a block.
 *
 * @namespace ZC.Core.EventListener
 * @extends ZC.Core.EventListener
 * @class MakeAjaxRequest
 */
oEL = ZC.Core.EventListener.Create('MakeAjaxRequest');
oEL.prototype.HandleEvent = function(oWidget, oEvent, oSrcEvent)
{
	var sBlockUID = this.GetAttribDefault('Block'), oBlock,
		aIncludeWidgetValues = this.GetAttribDefault('IncludeWidgetValues', {}), oGetPostVars = {},
		oExtraRequestParams = this.GetAttribDefault('ExtraRequestParams', {}),
		sTransaction = this.GetAttrib('Transaction'),
		oParams;

	// has event been cancelled by a previous handler? if so, cancel the AJAX request
	if ((oSrcEvent.getPreventDefault && oSrcEvent.getPreventDefault()) || oSrcEvent.returnValue === false)
		return;

	if (this.oDestination instanceof ZC.Core.Block)
	{
		oBlock = this.oDestination;
	}
	else if (sBlockUID)
	{
		oBlock = JSManager.GetBlockByUniqueID(sBlockUID);

		if (!oBlock)
			oBlock = JSManager.GetWidget(sBlockUID);
	}
	else 
	{
		oBlock = this.oDestination.FindContainingBlock();
	}

	if (!oBlock)
	{
		YAHOO.log('Unable to find block' + (sBlockUID ? (' with UniqueID ' + sBlockUID) : ''), 'warn', 'MakeAjaxRequest');
		return;
	}

	Evt.stopEvent(oSrcEvent);
	U.ForEach(aIncludeWidgetValues, function(sWidgetName, sKey)
	{
		var oWidget = this.oDestWidget.oForm.GetWidget(sWidgetName) || JSManager.GetWidget(sWidgetName);
		if (oWidget)
		{
			if (L.isString(sKey))
				oGetPostVars[sKey] = oWidget;
			else
				oGetPostVars[sWidgetName] = oWidget;
		}
	}, this);

	if (!L.isUndefined(oExtraRequestParams.GetPostVars))
	{
		oGetPostVars = L.merge(oExtraRequestParams.GetPostVars, oGetPostVars);
	}

	oParams = L.merge(
		oExtraRequestParams,
		{ Transaction: sTransaction, GetPostVars: oGetPostVars }
	);
	oBlock.AjaxRequest(oParams);
	return false;
}

})();

