/*
 * HC staar bag det her - prik til ham hvis du har spoergsmaal eller ideer.
 */

if (!window.Prototype) {
	throw "You need Prototype to use the ID classes";
}

// Extending Element.Methods

Element.Methods.addClassNames = function(element, classNames)
{
	if (!(element = $(element))) return;
	classNames.split(' ').each(function(className) { element.addClassName(className); });
	return element;
}

Element.Methods.removeClassNames = function(element, classNames)
{
	if (!(element = $(element))) return;
	classNames.split(' ').each(function(className) { element.removeClassName(className); });
	return element;
}

// Hack to keep logger static - please do not address this variable
var _IDLogger;

ID = Class.create({
	_identity: 'ID',

	toString: function() { return this._identity; },
	_getLogger: function() {
		// Already got one?
		if (this._logger !== undefined) {
			return this._logger;
		}

		// Got a "static" logger?
		if (_IDLogger !== undefined) {
			return (this._logger = _IDLogger);
		}

		// Firebug?
		if ((typeof console != 'undefined') &&
			Object.isFunction(console.log) &&
			Object.isFunction(console.info) &&
			Object.isFunction(console.debug) &&
			Object.isFunction(console.warn) &&
			Object.isFunction(console.error)) {
			return (this._logger = new ID.Logger.Firebug());
		}

		// Simple console.log() ?
		if ((typeof(console) !== 'undefined') && (typeof(console.log !== 'undefined'))) {
			return (this._logger = new ID.Logger.SimpleConsole());
		}

		// TODO: Logbook window?
		
		// Default dummy null logger
		return (this._logger = new ID.Logger.Null());
	},
	_log: function(str) { this._getLogger().log(this.toString(), str); },
	_debug: function(str) { this._getLogger().debug(this.toString(), str); },
	_info: function(str) { this._getLogger().info(this.toString(), str); },
	_warn: function(str) { this._getLogger().warn(this.toString(), str); },
	_error: function(str) { this._getLogger().error(this.toString(), str); },
	
	stringIsNullOrEmpty: function(str)
	{
		return ( str === undefined || str === null ) ? true : str.empty();
	}
});


//-----------------------------------------------------------------------------------------------------------------------------
// Loggers
//-----------------------------------------------------------------------------------------------------------------------------

ID.Logger = Class.create({
	log: function() {},
	debug: function() {},
	info: function() {},
	warn: function() {},
	error: function() {}
});	

ID.Logger.SimpleConsole = Class.create(ID.Logger,{
	_log: function(severity, context, str) {
		var output = '['+severity+'] ['+context+'] '+str;
		console.log(output);
	},
	log: function(context, str) { this._log('LOG', context, str); },
	debug: function(context, str) { this._log('DEBUG', context, str); },
	info: function(context, str) { this._log('INFO', context, str); },
	warn: function(context, str) { this._log('WARN', context, str); },
	error: function(context, str) { this._log('ERROR', context, str); }
});

ID.Logger.Firebug = Class.create(ID.Logger,{
	log: function(context, str) { console.log('['+context+'] '+str); },
	debug: function(context, str) { console.debug('['+context+'] '+str); },
	info: function(context, str) { console.info('['+context+'] '+str); },
	warn: function(context, str) { console.warn('['+context+'] '+str); },
	error: function(context, str) { console.error('['+context+'] '+str); }
});

ID.Logger.Null = Class.create(ID.Logger,{
	log: function() {},
	debug: function() {},
	info: function() {},
	warn: function() {},
	error: function() {}
});


/*
ID.Logger.Logbook = Class.create(ID.Logger,{
	initialize: function($super, element) {
		$super();
		this._element = $(element);
		if (!this._element) {
			throw 'Unable to locate logbook element: '+element;
		}
	},
	log: function(level, context, str) {
		this._element.insert(new Element('div')
			.addClassName('logentry')
			.insert(new Element('span')
				.addClassName('logentry_context')
				.update(this.toString())
			)
			.insert(new Element('span')
				.addClassName('logentry_content')
				.update(str)
			)
		);
		(function(){ logbook.scrollTop = logbook.scrollHeight; }).defer();
	}
});
*/


//-----------------------------------------------------------------------------------------------------------------------------
// ActionClickHandler
//-----------------------------------------------------------------------------------------------------------------------------

ID.ActionClickHandler = Class.create(ID,{
	_identity: 'ID.ActionClickHandler',

	initialize: function(options) {
		this._options = Object.extend({
			'actionClassName':				'action',
			'actionNameClassNamePrefix':	'action',
			'stripActionNamePrefix':		true,
			'actionDataClassNamePrefix':	'actiondata',
			'eventNameSpace':				'action',
			'disabledClassName':			'disabled'
		},options || {});

		//var observeElement = Prototype.Browser.IE ? $$('body').first() : document;
		//observeElement.observe('click', this._onClick.bindAsEventListener(this));

		Event.observe(document.body, 'click', this._onClick.bindAsEventListener(this));
	},
	_onClick: function(evt) {
		// Check keys/buttons
		if (evt.ctrlKey || evt.altKey || evt.metaKey || evt.shiftKey) {
			this._log('Ignoring click+key');
			return;
		}

		// Find click element
		var clickElement = Event.element(evt);

		// Find action element
		var actionElement = clickElement;
		if (!actionElement.hasClassName(this._options.actionClassName)) {
			actionElement = actionElement.up('.'+this._options.actionClassName);
			if (!actionElement) {
				//this._log('Ignoring click on non-action element');
				return;
			}
		}

		// Stop event
		Event.stop(evt);

		// Bail out if action element contains any of the disabled classes
		if (actionElement.hasClassName(this._options.disabledClassName)) {
			this._log('Ignoring click on disabled element');
			return;
		}

		// Gather data by iterating through class names
		var data = {};
		actionElement.classNames().each(function(className){
			var match = className.match('^'+this._options.actionDataClassNamePrefix+'_(.*?)_(.*)$');
			if (match === null) { return; }

			data[match[1]] = match[2];
		},this);

		// Find action events to fire by iterating through class names
		// (having more than one action class would be weird, but we'll humor you)
		actionElement.classNames().each(function(className){
			var match = className.match('^'+this._options.actionNameClassNamePrefix+'_(.*)');
			if (match == null) { return; }

			var eventName = (this._options.stripActionNamePrefix ? match[1] : match[0]);
			this._fireEvent(eventName,{
				'eventName': eventName,
				'clickEvent': evt,
				'clickElement': clickElement,
				'actionElement': actionElement,
				'data': data
			});
		},this);
	},
	_fireEvent: function(name, memo) {
		var eventName = this._options.eventNameSpace+':'+name;
		this._log('Firing event: '+eventName+' ('+Object.toJSON(memo.data)+')');
		document.fire(this._options.eventNameSpace+':'+name, memo);
	}
});

//new ID.ActionClickHandler();

//-----------------------------------------------------------------------------------------------------------------------------
// StateMachine
//-----------------------------------------------------------------------------------------------------------------------------

ID.AbstractStateMachine = Class.create(ID, {
	initialize: function() {
		this._state = undefined;
	},
	setState: function(state) {
		this._log('Switching to state '+state.toString());
		if (this._state !== undefined) {
			try {
				this._state.teardown();
			} catch(ex) {
				this._log('Method teardown() threw exception: '+ex);
			}
		}
		this._state = state;
		this._state.setContext(this);

		try {
			this._state.update();
		} catch(ex) {
			this._log('Method update() threw exception: '+ex);
		}
	}
});

ID.AbstractState = Class.create(ID, {
	/*
	initialize: function() {
	},
	*/
	setContext: function(context) {
		this._context = context;
	},
	update: function() {
	},
	teardown: function() {
	},
	setState: function(state) {
		this._context.setState(state);
	}
});


