/*
 *	To use the event handler:
 *	1. define a behavior name and its corresponding function in HANDLERS
 *	2. in HTML, for elements that should have that behavior applied to them when an event occurs, add these attributes:
 *		1. class="bf_dom" (required)
 *		2. rel:bf_bucket="event_handler"
 *		3. rel:actions="[event]:[behavior name]" (required)
 *		4. rel:data="{[behavior name]:{parameters}}" (optional)
 *	NOTES:
 *	Functions defined in HANDLERS should accept two parameters, the event object and the optional parameters
 *	You may specify multiple events; just separate them by spaces. For example:
 *		rel:actions="[event 1]:[behavior 1 name] [event 2]:[behavior 2 name]"
 *	The events are associated with elements when the dom is loaded. If you add content to the page after that,
 *	you must call universal_dom.update(element) where element contains the new content
**/
var bf_event_handler = function() {
	this.CLASS = '.behavior';
	this.ACTION_ATTRIBUTE = 'rel:actions';
	this.DATA_ATTRIBUTE = 'rel:data';
	this.HANDLERS = {
		// behavior_name : function_definition
		call: function(e,data) {var fn = eval(data.fn); fn(data.data?data.data:data);},
		vote: function(e,data) {badge_vote_manager.flow_vote(e, data)},
		share_email: function(e,data) {BF_ShareEmail.locate_form_and_share_email(data.buzz_id+'-email-form',data.buzz_id)},
		register: function(e,data) {
			var user = new BF_User();
			if ( user.isLoggedIn() ) {bf_register.register_alias(data);}
			else {bf_register.new_register(data)}
		},
		// map value of e.target into data.target's rel:data attribute
		map_into: function(e,data) {
			var target = e.target;
			var update_el = $(data.target);
			var value = target.value;
			if ( data.value ) value = data.value(target);
			if ( update_el ) {
				var json = eval('('+update_el.getAttribute('rel:data')+')');
				var field = data.field.split('.');
				var obj = json;
				var end_field = field.pop();
				while ( field.length ) {
					var f = field.shift();
					if ( typeof obj[f] != 'undefined' ) obj = obj[f];
					else obj[f] = {};
				}
				if ( data.append ) obj[end_field] = (typeof obj[end_field] == 'undefined' ? '' : obj[end_field] + data.append) + value;
				else obj[end_field] = value;
				update_el.setAttribute('rel:data',Object.toJSON(json));
				if ( data.hide && $(data.hide) ) $(data.hide).hide();
			}
		},

		/*
		 * If e.target has class 'initial-field-state', remove class and clear value of e.target
		 *
		 * @param e 		event object
		 * @param data 	data dictionary defined in element template
		 */
		clear_default_field: function(e,data){
			var target = e.target;
			var remove_class = (typeof data != 'undefined' && typeof data.remove_class != 'undefined') ? data.remove_class : 'initial-field-state';
			var set_value = (typeof data != 'undefined' && typeof data.set_value != 'undefined' ) ? data.set_value : '';
			
			// Store default value for restoration in restore_default_field()
			var default_value = target.getAttribute( "defaultValue" ) || "";
			if( default_value.length == 0 )
				target.setAttribute( "defaultValue", target.value );

			if (target.className.match(new RegExp(remove_class))){
				target.removeClassName(remove_class);
				target.value = set_value;
				if ( typeof data != 'undefined' && data.set_type ) {
					try {
						target.setAttribute('type', data.set_type);
					} catch(e){
						// For IE
						var new_field = target.cloneNode(true);
						new_field.setAttribute('type', data.set_type);
						target.parentNode.replaceChild(new_field,target);
					}
				}
			}
		},

		/*
		 * Restore default value to empty input box from cache stored in clear_default_field()
		 *
		 * @param ev 	event object
		 */
		restore_default_field: function( ev ) {
			var el = ev.target;
		
			// Restore only if empty
			if( el.value.length > 0 )
				return;

			// Purpose of default value is to display in text
			el.type = "text";
			el.value = el.getAttribute( "defaultValue" );
			el.addClassName( "initial-field-state" );
		},

		// filter out from e.target.value any chars in data.disallow
		filter_chars : function(e,data) {
			if ( e.keyCode == 37 || e.keyCode == 39 ) return;
			var regex = data.disallow;
			var target = e.target;
			var newValue = target.value.replace(regex,'');
			if ( target.value != newValue ) target.value = newValue;
		},
		upload_image : function(e,data) {
			$('user-image-edit-iframe').src="/static/images/public/backgrounds/bluestripe.png";
			$('user-image-edit-iframe').src=data.iframe_src;
			this.upload_image_type = data.upload_image_type;
			BF_UI.showDialog('user-image-edit');
			event_handler.get_image_settings = function(){
				return data;
			}
		},
		show: function(e,data) {
			if ($(data.id)) $(data.id).removeClassName('hidden');
		},
		hide: function(e,data) {
			if ($(data.id)) $(data.id).addClassName('hidden');
		}
	};
	
	this.init_called = 0;
	
	// For each element with appropriate behavior and for each event specified
	// in that element's actions attribute, remove the generic handler if it was there, and reassign it.
	this.generic_handler = function(e){event_handler._event_handler(e)}
	this.init = function() {
		if ( ++event_handler.init_called > 1 ) {
			console.error('event_handler.init should not be called explicitly; use universal_dom.update(element) instead: ' + console.trace());
		}
		else {
			universal_dom.assign_handler({bucket:'event_handler',handler:event_handler._assign_handlers});
		}
	}
	
	this._assign_handlers = function(el) {
		var ACTION = 0;
		var HANDLER = 1;
		var actions = el.getAttribute(event_handler.ACTION_ATTRIBUTE);
		if ( actions ) {
			var action_list = actions.split(' ');
			// for each event specified in that element's actions attribute ...
			action_list.each( function(action){
				var pieces = action.split(':');
				// ... remove the generic handler if it was there, and reassign it
				el.stopObserving(pieces[ACTION], event_handler.generic_handler);
				el.observe(pieces[ACTION], event_handler.generic_handler);
			});
		}
	}
	
	// Look for a behavior name for the event that just occurred. If you found one, look for
	// optional data for that behavior and call its definition, passing the event object and optional data.
	this._event_handler = function(e){
		e.stop();
		var ACTION = 0;
		var HANDLER = 1;
		var event_type = e.type;
		var target = e.target;
		var actions = target.getAttribute(event_handler.ACTION_ATTRIBUTE);
		var action_list = actions.split(' ');
		// Look for a behavior name for the event that just occurred 
		action_list.each( function(action){
			var pieces = action.split(':');
			if ( pieces[ACTION] == event_type ) target.handler = pieces[HANDLER];
		});
		// If you found a behavior name, look for optional data for that behavior
		// and call its definition, passing the event object and optional data
		if ( typeof target.handler != 'undefined' ) {
			var data = {};
			var json = target.getAttribute( event_handler.DATA_ATTRIBUTE );
			if ( json ) data = eval('('+json+')');
			data = typeof data[target.handler] != 'undefined' ? data[target.handler] : data;
			if ( typeof event_handler.HANDLERS[target.handler] != 'undefined' ) {
				var fn = event_handler.HANDLERS[target.handler];
				if (fn) fn( e, data );
			}
			else {
				var fn = eval(target.handler);
				data.event = e;
				fn(data);
			}
		}
	}
}

var event_handler = new bf_event_handler();
BuzzLoader.register( event_handler.init, 1 );
