/**
* Base CG object
* 
* Provides a set of constants and utility functions in addition
* to a namespace for all shared CG libraries.
* 
* @requires jQuery
*/

if(typeof(jQuery) === 'undefined') {
	throw 'CG requires jQuery to be loaded';
}

//don't barf on console
if(typeof(console) === 'undefined') {
	console = {
		log: function() {}
	};
}

//prevent $ conflict
(function($) {

	//global CG Object
	CG = typeof(CG) === 'undefined' ? {} : CG;
	
	//global CG options
	CG.options = $.extend(true, {
		
	}, CG.options ? CG.options : {});
	
	//games
	CG.GAMES = {
		1: {name: 'Duels', link: 'http://www.duels.com', hasBulletins: true},
		2: {name: 'Baseball Boss', link: 'http://www.baseballboss.com', hasBulletins: true},
		3: {name: 'Warstorm', link: 'http://www.warstorm.com', hasBulletins: true},
		6: {name: 'MechDuels', link: 'http://www.mechduels.com', hasBulletins: true},
		7: {name: 'Planetstorm', link: 'http://www.planetstorm.com', hasBulletins: false},
		'dd': {name: 'Duels Defense', link: 'http://www.duelsdefense.com', hasBulletins: false}
	};
	
	//truncate content
	$.fn.truncate = function(length, elips) {
		var length = length || 20,
			elips = elips || '...';

		return this.each(function() {
			var obj = $(this),
				content = obj.text();
			
			if(content.length > length) {
				obj.text(content.substr(0, length) + elips);
			}
		});
	};

	/**
	 * Custom event object
	 */
	CG.Event = function(scope) {
		var _that = this,
			_scope = scope || window,
			_handlers = [],
			_firing = false,
			
			_init = function() {
				//public access
				$.extend(_that, {
					subscribe: _subscribe,
					unsubscribe: _unsubscribe,
					fire: _fire
				});
			},
			
			//add a handler
			_subscribe = function(handler, priority, scope) {

				//make sure the handler is not already subscribed
				if(_checkHandler(handler) === -1) {
					scope = scope || _scope;
					priority = priority || 0;
					
					var ind = _handlers.length;
					
					//find the correct spot to add the handler
					$.each(_handlers, function(index, h) {
						if(h.p > priority) {
							ind = index;
							return false;
						}
					});
					
					//add it
					_handlers.splice(ind, 0, {f: handler, p: priority, s: scope});
				}
				
				return _that;
			},
			
			//remove a handler
			_unsubscribe = function(handler) {
				var index = _checkHandler(handler);
				if(index !== -1) {
					_handlers.splice(index, 1);
				}
				
				return _that;
			},
			
			//trigger the event
			_fire = function(context) {
				if(!_firing) {
					_firing = true;
					var queue = _handlers.slice(), results = [], context = context || {};
					
					//recursive fn - grabs next handler, calls, sets timeout for next fn call if result !== false
					(function fire() {
						if(queue.length) {
							var h = queue.shift(), result = h.f.call(h.s, _that, context) || true;
							results.push(result);

							if(result === false) {
								queue = [];
							}
							
							setTimeout(fire, 10);
						} else {
							_firing = false;
						}
					})();
				} else {
					setTimeout(function() {
						_fire(context);
					}, 10);
				}
				
				return _that;
			},
						
			//check to see if the handler exists in the fn list
			_checkHandler = function(handler) {
				var ind;

				$.each(_handlers, function(index, h) {
					if(h.f && h.f === handler) {
						ind = index;
					}
				});

				return ind === undefined ? -1 : ind;
			};
			
			_init();
	};

	/**
	 * Base class for CG dropdown widgets
	 * @param string el The expression that identifies the widget container
	 */
	CG.TopBarDropdown = function(el) {
		
		/***** BEGIN PRIVATE PROPERTIES *****/
		
		var that = this,
			_el = $(el),
			_id = ++CG.TopBarDropdown.id_count,
			_topBar = _el.parents('#top_bar'),
			_title = _el.find('> a'),
			_container = _el.find('> .sub_content'),
			_overlay,
			_isOpen = false,
			_animating = CG.TopBarDropdown.animating,
			_openedOnce = false,
			
		/***** END PRIVATE PROPERTIES *****/
	
		/***** BEGIN PRIVATE METHODS *****/
	
		//constructor
		_init = function() {
			
			//set up handlers
			$(document.body).click(_onDocumentClick);
			_title.click(_onClick);
			
			//hide and show overlays
			CG.TopBarDropdown.events.beforeShow.subscribe(_onBeforeShow);
			CG.TopBarDropdown.events.afterShow.subscribe(_onAfterShow);
			CG.TopBarDropdown.events.beforeHide.subscribe(_onBeforeHide);
			CG.TopBarDropdown.events.afterHide.subscribe(_onAfterHide);
		},
		
		//return the id
		_getId = function() {
			return _id;
		},
		
		//helper function to check id
		_checkId = function(tempId) {
			return tempId === _id;
		},
		
		_setCSS = function() {
			_container.css('backgroundPosition', '-' + (_container.offset().left - ((_topBar.width() - 1194) / 2)) + 'px 1px');
		},
		
		//show the widget
		_show = function() {
			//make sure we're closed or no in the process of opening
			if(!_isOpen && !_animating) {
				_animating = true;

				//create the overlays if they don't exist
				if(!_overlay) {
					_overlay = CG.Overlay.getInstance();
				}
								
				//beforeShow custom event
				CG.TopBarDropdown.events.beforeShow.fire({id: _id});
				_container.slideDown(500, function() {
					_isOpen = true;
					_animating = false;
					
					//afterShow custom event
					CG.TopBarDropdown.events.afterShow.fire({id: _id});
				});
			}

			return that;
		},
	
		//hide the widget
		_hide = function() {
			//make sure we're open and not closing
			// also make sure, if this was a click event, that click did not originate in the widget
			if(_isOpen && !_animating) {
				_animating = true;
				
				//beforeHide custom event
				CG.TopBarDropdown.events.beforeHide.fire({id: _id});
				_container.slideUp(500, function() {
					_isOpen = false;
					_animating = false;

					//afterHide custom event
					CG.TopBarDropdown.events.afterHide.fire({id: _id});
				});	
			}

			return that;
		},
		
		_onBeforeShow = function(e, data) {
			if(_checkId(data.id)) {
				CG.TopBarDropdown.animating = true;
				if(CG.TopBarDropdown.open_count == 0) {
					_overlay.show();
				}
				CG.TopBarDropdown.open_count++;
			}
		},
		
		_onAfterShow = function(e, data) {
			if(_checkId(data.id)) {
				CG.TopBarDropdown.animating = false;
				if(!_openedOnce) {
					_setCSS();
				}
				_openedOnce = true;
			}
		},
		
		_onBeforeHide = function(e, data) {
			if(_checkId(data.id)) {
				CG.TopBarDropdown.animating = true;
			}
		},
		
		_onAfterHide = function(e, data) {
			if(_checkId(data.id)) {
				CG.TopBarDropdown.open_count--;
				if(CG.TopBarDropdown.open_count == 0) {
					_overlay.hide();
				}
			
				CG.TopBarDropdown.animating = false;
			}
		},

		_onClick = function(e) {
			_toggle();
		},
		
		_onDocumentClick = function(e) {
			//added extra get for older jquery support
			if(e == undefined || (e.type == 'click' && $(e.target).parents().index(_container.get(0)) == -1)) {
				_hide();
			}
			
			if($(e.target).get(0) == _title.get(0)) {
				return false;
			}
		},
	
		//hide if open, show if closed
		_toggle = function() {
			_isOpen ? _hide() : _show();
			return that;
		};

		/***** END PRIVATE METHODS *****/
	
		/***** BEGIN PUBLIC ACCESS *****/
		
		$.extend(this, {
			//properties
			_topBar: _topBar,
			_container: _container,
			_title: _title,

			//methods
			getId: _getId,
			show: _show,
			hide: _hide,
			toggle: _toggle,
			_checkId: _checkId
		});
	
		/***** END PUBLIC ACCESS *****/
		
		/***** BEGIN "CONSTRUCTOR" *****/

		_init();
		
		/***** END "CONSTRUCTOR" *****/
	};
	
	/***** BEGIN STATIC PROPERTIES *****/
	
	$.extend(CG.TopBarDropdown, {
		id_count: 0,
		open_count: 0,
		animating: false,
		
		events: {
			beforeShow: new CG.Event(),
			afterShow: new CG.Event(),
			beforeHide: new CG.Event(),
			afterHide: new CG.Event()
		}
	});
	
	/***** END STATIC PROPERTIES *****/
	
	/**
	 * Message window
	 * @param string content Message content
	 * @param string title Message title
	 */
	CG.MessageWindow = function(content, title, options) {
		var _that = this,
			_container, _topBar, _overlay, _actionContainer,
			_titleContainer, _contentContainer,
			_options = {
				id: '',
				'class': '',
				hideClose: false,
				actions: []
			},
		
			_init = function() {
				$.extend(_options, options || {});
				
				_topBar = $('#top_bar');
				_container = $('<div class="cg_message ' + _options['class'] + '" id="' + _options.id + '"><div class="cg_message_bottom"></div></div>').css({
					position: 'fixed',
					top: '-10000px',
					zIndex: _topBar.css('zIndex') - 1
				}).insertBefore(_topBar);
				
				if(!_options.hideClose) {
					_options.actions.push('<a href="#" onclick="return false;">X Close</a>');
				}
				
				_actionContainer = $('<ul class="cg_message_actioncontainer"></ul>').appendTo(_container);
				
				$.each(_options.actions, function(key, el) {
					_actionContainer.append($('<li></li>').append($(el).click(_hide)));
				});
				
				if(title) {
					_titleContainer = $('<h1 class="cg_message_title">' + title + '</h1>').appendTo(_container);
				}
				
				if(content) {
					_contentContainer = $('<div class="cg_message_content">' + content + '</div>').appendTo(_container);
				}
				
				$.extend(_that, {
					hide: _hide,
					show: _show
				});
			},
			
			_hide = function() {
				CG.MessageWindow.events.beforeHide.fire({messageWindow: _that});
				
				_container.animate({
					top: '-=' + _container.outerHeight(true) + 'px'
				}, 500, function() {
					CG.MessageWindow.events.afterHide.fire({messageWindow: _that});
					_overlay.hide();
				});
				
				return _that;
			},
			
			_show = function() {
				if(!_overlay) {
					_overlay = CG.Overlay.getInstance().show();
				}
				
				CG.MessageWindow.events.beforeShow.fire({messageWindow: _that});
				
				_container.css({
					top: '-' + (_container.outerHeight() - _topBar.outerHeight()) + 'px',
					left: Math.round((document.body.clientWidth - _container.outerWidth()) / 2) + 'px'
				}).animate({
						top: '+=' + _container.outerHeight() + 'px'
					}, 500, function() {
						CG.MessageWindow.events.afterShow.fire({messageWindow: _that});
					});
				
				return _that;
			};
			
		_init();
	};
	
	CG.MessageWindow.events = {
		beforeShow: new CG.Event(),
		afterShow: new CG.Event(),
		beforeHide: new CG.Event(),
		afterHide: new CG.Event()
	};
	
	/**
	 * Transparent overlay - singleton
	 */
	CG.Overlay = (function() {
		var _instance,
		
		_init = function() {
			var _that = this,
				_overlay,
				_iFrame,

				_init = function() {
					_iFrame = $('<iframe id="top_bar_shim" frameborder="0" src="javascript:void(0);"/>').css({
						position: 'absolute',
						filter:'progid:DXImageTransform.Microsoft.Alpha(opacity=0);',
						top: 0,
						left: 0,
						width: '100%',
						display: 'none'
					}).insertBefore('#top_bar');

					_overlay = $('<div id="top_bar_overlay"></div>').css({
						background: '#000',
						top: 0,
						left: 0,
						width: '100%',
						display: 'none'
					}).insertBefore(_iFrame);

					_iFrame.css('zIndex', _overlay.css('zIndex') - 1);
				},

				_visible = function() {
					return _overlay.is(':visible');
				},

				_hide = function() {
					_overlay.animate({
						opacity: 0
					}, 300).hide();

					_iFrame.hide();
					return _that;
				},

				_show = function() {
					var docHeight = $(document).height();

					if(_overlay.height() < docHeight) {
						_overlay.height(docHeight);
						_iFrame.height(docHeight);
					}

					_overlay.css('opacity', 0).show().animate({
						opacity: .75
					}, 300);

					_iFrame.show();
					return _that;
				};

			$.extend(this, {
				hide: _hide,
				show: _show,
				visible: _visible
			});

			_init();
		};
		
		return {
			getInstance: function() {
				if(!_instance) {
					_instance = new _init();
				}
				return _instance;
			}
		};
		
	})();

})(jQuery);