var Hive = {
	displayMessage: function(input) {
		if (Object.isUndefined(window.flashObject)) {
			var displayFunc = alert;
		}
		else {
			var displayFunc = window.flashObject.displayMessage.bind(window.flashObject);
		}
		
		
		if (typeof(input) == 'string') {
			displayFunc(input);
		}
		else {
			// this is an xmlhttp object
			displayFunc(input.responseText);
		}
	}
};



/*
  Flash is an adaptation of the "Humanized Messages" code available at http://code.google.com/p/humanmsg/ under the Apache 2.0 license (http://www.apache.org/licenses/LICENSE-2.0)

	HUMANIZED MESSAGES 1.0
	idea - http://www.humanized.com/weblog/2006/09/11/monolog_boxes_and_transparent_messages
	home - http://humanmsg.googlecode.com
	
	Adapted for use with Prototype / Moo.fx by Brendan Clougherty
*/
var Flash = Class.create();
Flash.prototype = {
	movementTimeout:   null,
	defaultTimeout:    null,
	removeMessageFunc: null,
	toggleLogFunc:     null,
	messageLogEffects: null,
	
	/**
	 * Set up the options, create effects objects, and add the message and log containers to the document
	 */
	initialize: function(options) {
		this.options = {
			messageElement:    'flashMessage',    // The id for the message container
			messageLogElement: 'flashMessageLog', // The id for the message log container
			appendTo:          'body',            // The element (in selector format) to append the message container to
			logName:           'Message log',     // The text that appears on the log tab
			opacity:           0.8                // The opacity of the message
		};
		Object.extend(this.options, options || {});
		
		// Make sure the opacity is specified as a float
		this.options.opacity = parseFloat(this.options.opacity);
		
		
		
		// Add the message container and log container to the document
		var messageContainer = new Element('div', {
			id:        this.options.messageElement,
			className: 'message flashMessage',
			style:     'display: none;'
		});
		
		messageContainer.insert({ bottom: new Element('div', { className: 'round' })   });
		messageContainer.insert({ bottom: new Element('p') });
		messageContainer.insert({ bottom: new Element('div', { className: 'round' })   });
		
		var messageLog = new Element('div', {
			id:    this.options.messageLogElement,
			style: 'display: none;'
		});
		
		messageLog.insert({ bottom: new Element('p').update(this.options.logName) });
		messageLog.insert({ bottom: new Element('ul', { style: 'display: none;' }) });
		
		var container = $$(this.options.appendTo)[0];
		
		container.insert({ bottom: messageContainer });
		container.insert({ bottom: messageLog });
		
		
		
		// We need to store the bound reference to the function so that we can refer back to this exact instance later
		this.toggleLogFunc = this.toggleMessageLog.bind(this);
		Event.observe($(this.options.messageLogElement).down('p'), 'click', this.toggleLogFunc);
	},
	
	/**
	 * Show a message to the user and file it in the log
	 */
	displayMessage: function(messageText) {
		if (messageText.length == 0) {
			return;
		}
		
		var messageElement    = $(this.options.messageElement);
		var messageLogElement = $(this.options.messageLogElement);
		
		if (messageElement.visible()) {
			window.setTimeout(this.displayMessage.bind(this, messageText), 50)
			return;
		}
		
		window.clearTimeout(this.defaultTimeout);

		// Inject message
		messageElement.update(messageText);
		
		// Show message
		$(this.options.messageElement).fadeIn({ to: this.options.opacity });
		
		messageElement.style.opacity = this.options.opacity;
		
		// Prepend message to the log
		messageLogElement.down('ul').insert({ top: "<li>"+messageText+"</li>" });
		
		messageLogElement.show();
		
		// We need to store the bound reference to the function so that we can refer back to this exact instance later
		this.removeMessageFunc = this.removeMessage.bind(this);
		
		// Watch for mouse & keyboard movements in .7s
		this.movementTimeout = setTimeout(this.bindEvents.bind(this), 700);
		
		// Remove message after 5s
		this.defaultTimeout  = setTimeout(this.removeMessage.bind(this), 5000);
	},
	
	/**
	 * Display or hide the message log
	 */
	toggleMessageLog: function() {
		$(this.options.messageLogElement).down('ul').toggle();
	},
	
	/**
	 * Set up event handling for the message
	 */
	bindEvents: function() {
		Event.observe(window, 'mousemove', this.removeMessageFunc);
		Event.observe(window, 'click',     this.removeMessageFunc);
		Event.observe(window, 'keypress',  this.removeMessageFunc);
	},
	
	/**
	 * Hide the message and remove event handlers
	 */
	removeMessage: function() {
		Event.stopObserving(window, 'mousemove', this.removeMessageFunc);
		Event.stopObserving(window, 'click',     this.removeMessageFunc);
		Event.stopObserving(window, 'keypress',  this.removeMessageFunc);
		
		window.clearTimeout(this.defaultTimeout);
		window.clearTimeout(this.movementTimeout);
		
		$(this.options.messageElement).fadeOut();
	}
};



/**
 * The Big Spinner provides status notification to the user about asynchronous updates.
 */
BigSpinner = {
	/**
	 * Add the spinner element to the page
	 */
	start: function() {
		// make sure we remove an existing spinner, if one exists
		BigSpinner.stop();
		
		var spinnerStyle = {};
		
		if (!(window.XMLHttpRequest)) {
			/*
				Since IE < 7 doesn't support position: fixed, we need to fake it.
				For our purposes here, we don't care if the spinner follows the viewport,
				we only care that it gets placed at the middle of the viewport initially.
			*/
			var offset = document.documentElement.scrollTop + (document.documentElement.clientHeight / 2) - 64;
			
			spinnerStyle.position = 'absolute';
			spinnerStyle.top      = offset.pixelize();
		}
		
		var spinner = new Element('div', { id: 'big_spinner', className: 'big_spinner_waiting' });
		spinner.setStyle(spinnerStyle);
		
		$$('body')[0].insert({ bottom: spinner });
	},
	
	/**
	 * Remove the spinner from the page
	 */
	stop: function() {
		if ($('big_spinner')) {
			$('big_spinner').remove();
		}
	}
};



var hiveElementExtensions = {
	toggleContent: function(element, first, second) {
		element = $(element);
		
		element.cleanWhitespace();
		
		if (element.innerHTML == first) {
			element.update(second);
		} else if (element.innerHTML == second) {
			element.update(first);
		}
	}
};
 
Element.addMethods(hiveElementExtensions);