(function($) {
	String.prototype.ky=function(){
		return this.toLowerCase().split(' ').join('_');
	}
	var el=function(i){return $(document.createElement(i))};
		$.fn.simple_gui= function(opt) {
			return this.each(function(){
			var t=$(this),
				b=$.extend({}, opt.buttons||{}),
				c=$.extend({},$.fn.simple_gui.defaults.classes, opt.classes||{}),
				e=$.extend({}, $.fn.simple_gui.defaults.events, opt.events||{}),
				f=$.extend({}, $.fn.simple_gui.defaults.callbacks, opt.callbacks||{}),
				g={},//gui object
				h=$.extend({}, $.fn.simple_gui.defaults.html, opt.html||{}),
				o=$.extend({}, $.fn.simple_gui.defaults.options, opt.options ||{}),
				d={},//html element objects
				m={},//memorized vars. This holds key value pairs to pass between functions.
				s={},//states - a collection of d objects, for restoring to a particular point by name. NOT IMPLEMENTED YET
				local={made: false,bound:false};
			function _make() {
				var classes=(arguments[0] && typeof arguments[0]==='object' ? $.extend({},c,arguments[0]) : c);
				var obj={container: el('div').addClass(classes.container).css({position: 'absolute'}).appendTo(document.body).hide()};
				if (o.close_link) {
					obj.close_link=el('a').addClass(classes.close_link).attr({href: '#'}).appendTo(obj.container);
				}
				if (o.title) {
					obj.title=el(h.title_tag).text(h.title_text).addClass(classes.title).appendTo(obj.container);
				}
				if (o.content) {
					obj.content=el('div').addClass(classes.content).appendTo(obj.container).html(h.content);
				}
				if (o.button_bar) {
					obj.button_bar=el('div').addClass(c.button_bar).appendTo(obj.container);
					$.each(b, function(k,v) {
						var key=k.ky();
						if (key !=='all') {
							b[key]=el('button').data('callback', v).text(k).appendTo(obj.button_bar);
						}
					});
				}
				return obj;
			}
			function _attach(obj) {//attach objects to the gui object
				obj.hide=_hide;
				obj.show=_show;
				obj.position=_position;
				obj.enable_buttons=_bind_buttons;
				obj.disable_buttons=_unbind_buttons;
				obj.prevent=_prevent_ob;
				obj.css=_css;
				obj.fadeIn=_fadeIn;
				obj.fadeOut=_fadeOut;
				obj.buttons=b;
				obj.classes=c;
				obj.events=e;
				obj.callbacks=f;
				obj.html=h;
				obj.link=t;
				obj.options=o;
				obj.vars=m;
				return obj;
				
			}
			
			function _addvar() {//add variables to the m object for passing around between callback functions.
				if (arguments.length && typeof arguments[0]==='object') {//key value assignment
					$.each(arguments[0], function(k,v) {
						var key=k.toLowerCase().split(' ').join('_');
						m[key]=($.isFunction(v) ? function() { v.call(t,g)}: v);
					});
				}
				else if(typeof arguments[0]==='string' && arguments.length>1) {
					var v=arguments[1];
					m[arguments[0]]=($.isFunction(v) ? function() {v.call(t,g)} : v);
				}
					return m;
			}
			function _css(o) {//shortcut for styling/moving the container 
				if (typeof o==='object') g.container.css(o);
			}
			function _fadeIn(){
				g.container.fadeIn(arguments);
			}
			function _fadeOut(){
				g.container.fadeOut(arguments);
			}
			function _do_make() {
				if (opt.hasOwnProperty('maker') && typeof opt.maker==='object') {
					d=$.fn.simple_gui.GUI(opt.maker);
				}
				else {
					d=(f.hasOwnProperty('make') ? ($.isFunction(f.make) ? f.make.call(t,_make) : (typeof f.make==='object' ? f.make : _make())): _make());
				}
				g=$.extend({},d);
				_attach(g);//attach other methods and objects
				if (f.hasOwnProperty('bind') && $.isFunction(f.bind)) f.bind.call(t,g);//call the bind method once
				g.css({position: 'absolute'});
				if ($.fn.draggable && o.draggable) {//add dragging functionality
					var handle=(g.hasOwnProperty('title') ? g.title : g.container);
					g.container.draggable($.extend({},{containment: 'document', handle: handle}, o.draggable_options ||{}));
					if (g.hasOwnProperty('title')) {
						g.title.css({cursor: 'move'});
					}
				}
				g.container.data('g', g).data('s',s);
			}
			function _position(event) {
				if (!g || !g.hasOwnProperty('container')) {//the object has yet to be created
					_do_make();
				}
				if (f.hasOwnProperty('position') && $.isFunction(f.position)) f.position.call(t,g,event);//call the overriding position method
				else {//default positioning
					var left=(o.position_by==='target' ? t.offset().left : event.pageX), top=(o.position_by==='target' ? t.offset().top : event.pageY) - g.container.outerHeight();
					if (o.position==='below') top+= (t.outerHeight() + g.container.outerHeight());
					g.container.css({left: left, top: top});
				}
				if (o.prevent) _prevent_ob();//prevent off window placement
			}
			function _show(event) {
				_position(event);
				if (!local.bound) {//bind the buttons once
					_bind_buttons();
					if (g.hasOwnProperty('close_link')) g.close_link.unbind('click',_hide).bind('click',_hide);//allow for two types of close
					if (g.hasOwnProperty('close')) g.close.unbind('click',_hide).bind('click',_hide);//close type 2
					local.bound=true;
				}
				//showing the simple_gui
				if (f.show && $.isFunction(f.show)) f.show.call(t,g);//call the overriding show method
				else g.container.show();
				
				return false;
			}
			function _hide(event) {
			//	_unbind();
				 setTimeout(function(){
					if (f.hasOwnProperty('hide') && $.isFunction(f.hide)) f.hide.call(t,g,event);//call the overriding hide method
					else g.container.hide();//default hide
					},100);
					return false;
			}
			function _prevent_ob() {//prevent out of bounds - off the window/page placement
				var w=$(window).width(),
					h=$(window).height(),
					cw=parseInt(g.container.outerWidth(),10),
					ch=parseInt(g.container.outerHeight(),10),
					left=parseInt(g.container.css('left'),10),
					top=parseInt(g.container.css('top'),10),
					st=$(window).scrollTop();
					if (top<st) top=st + o.offset+'px';//off the top of the window place at window top + options.offset
					else if (ch + top > h) top=st + (h-ch-o.offset)+'px';//off the bottom window place at window bottom - options.offset
					if (left<=o.offset) left=o.offset;//off left of window place at window left + options.offset
					else if (cw + left > w) left=(w-cw-o.offset)+'px';//off right of window place at window right -options.offset
					//need to add a method for preventing tooltips from being placed within the cursor
					g.container.css({left: left, top: top});
			}
			function _bind_buttons() {
				$.each(b, function(k,v) {
					var key=k.ky();
					if (key==='all') {
						_bind_all(function(){v(g)});
					}
					else {
						b[key].unbind('click').removeAttr('disabled').click(function() {
							var callback=$(this).data('callback');
							if (callback && $.isFunction(callback)) callback.call(t,g);
							else if ($.isFunction(v)) v.call(t,g);
							return false;
						});			
					}
				});
			}
			function _unbind_buttons() {
				$.each(b, function(k,v) {
					var key=k.ky();
					b[key].attr({disabled:'disabled'}).unbind('click', b[key].data('callback')||v);
				});
			}
			function _bind_all(func) {
				$.each(b, function(k,v) {
					var key=k.ky();
					if (key !=='all') {
						b[key].unbind('mouseup', func).bind('mouseup', func);
					}
				});
			}
			if (e.show==='hover') {
				t.unbind('hover', _show, _hide).bind('hover', _show, _hide);
			}
			else {
				t.unbind(e.show, _show).bind(e.show, _show);
				if (e.hide!=='auto') {
					t.unbind(e.hide, _hide).bind(e.hide, _hide);
				}
			}
			if (o.make_now) {//create the simple_gui on page load
				_do_make();
				g.container.hide();
			}
		});
		}
		$.fn.simple_gui.defaults={
			classes: {//class names for html parts
				//	container
				//~ -------------------------------------------
				//~ |  title     		  [closelink]	|
				//~ |  	 -----------------------------	  	|
				//~ |		content						|
				//~ |											|
				//~ |		------------------------------		|
				//~ | buttons							|
				//~ -------------------------------------------
				container: 'simple_gui',
				close_link: 'close',
				title_bar: 'title',
				content: 'content',
				button_bar: 'button_bar'
			},
			buttons:{
				//'this' scopes to the target element
				//{'Button Text': function(g){}},
			},
			events: {//the events that trigger the action
				show: 'click',
				hide: 'auto'//manual
			},
			callbacks: {
				//show,hide,position,make,bind
			},
			html: {
				title_tag: 'h3',
				title_text: 'Simple Gui Demo',
				close_text: '',
				content: '<p>A basic gui.</p>'
			},
			options: {
				close_link: true,
				title: true,
				content: true,
				button_bar: true,
				prevent: true,//prevent off window placement
				position: 'above',// by default the simple_gui is placed above the target
				position_by: 'target',// or event
				offset: 5,//the offset when preventing off window placement
				make_now: false,//make the object on page load (default : first show:event action)
				draggable: true
				//draggable_options: {} // set draggable options
				//hoverIntent_options: {}
			}
		
		}
		$.fn.simple_gui.GUI=function(opt) {
			var ret={};
			if (!opt.hasOwnProperty('container')) {
				ret.container=el('div').addClass($.fn.simple_gui.defaults.classes.container);
			}
			if (!opt.hasOwnProperty('content')) {
				ret.content=el('div').addClass($.fn.simple_gui.defaults.classes.content);
			}
			$.each(opt, function(k,v) {
				var key=$.trim(k).split(' ').join('_');
				v=(typeof v==='string' ? $(v) : v);
				ret[key]=v;
			});
			return ret;
		}
		$.fn.extend({
			center: function(){
				return this.each(function(){
					var t=$(this),w=$(window),left=w.scrollLeft() + (w.width()/2 - t.outerWidth()/2), top=w.scrollTop() + (w.height()/2 - t.outerHeight()/2);
					$(this).css({left: left, top: top});
				});
			}
		});
})(jQuery);

