/* @Perfect World Entertainment Global Javascript File
 * 
 * @version 1.0
 *
 * @class Page
 * @requires document
 *
 * @description
 *
 * Page handles page initialization as well as running functions onload.  It also stores URL data and login methods
 * To add a function to be run on page load use the queue method
*/

Page = {

	onLoadQueue: [], //queues functions to run on page load
	initQueue: [], //queues functions to run after the header has loaded
	delQueue: [], //objects queued for deletion
	userLoggedIn: false,
	doc: document,
	win: window,
	language: 'en',

	config: {

		LOCATION: location.href, 
		HOST: location.host, 
		MODULE: null, 
		SECTION: null, 
		SUB_SECTION: null, 
		QUERY_STRING: decodeURI(location.search).replace('?', ''), 
		GET: [] //used like PHP $_GET

	},
	
	//global functions that should load on Page load should be here
	
	init: function(){
		
		for(var i=0; i<Page.initQueue.length; i++) Page.initQueue[i]();		
	
	},

	//all functions that should be run on Page load should be added here

	onLoad: function(){
				
		for(var i=0; i<Page.onLoadQueue.length; i++) Page.onLoadQueue[i]();
		
		if(Page.delQueue.length > 0){ //removes objects that are not used from memory
					
			for(i=0; i<Page.delQueue.length; i++) delete Page.delQueue[i];
			
		}
	
	},

	//queue method to queue functions to be run later, if the second param is 'init' it will run after the header as loaded, else defaults to page load

	queue: function(fn, type){
		
			(type == 'init')? Page.initQueue.push(fn) : Page.onLoadQueue.push(fn);
	},

	//queues global objects for deletion 

	deleteQueue: function(obj){

			Page.delQueue.push(obj);

	},

	//login function (legacy)

	login: function(elem){
		
		 elem.action = 'https://account.perfectworld.com/login';
         elem.submit();

	},

	//checks if user hits enter on this site (legacy)

	checkEnter: function(e, elem){
	
		if (!e) var e = Page.win.event
		if (e && e.keyCode == 13) Page.login(elem);
        
	},

	removeFocus: function(){

		if(Page.doc.getElementsByTagName) {
           
			var a = Page.doc.getElementsByTagName("a");
           
			for(var i = 0; i < a.length; i++) a[i].onfocus = function(){this.blur();};
       
       }

	},

    rewriteAds: function(targetContainerID, adCode){

        if(GA_googleCreateDomIframe) GA_googleCreateDomIframe(targetContainerID, adCode);

    }

	
}

/* @class Tabs
 * @requires Page, document
 *
 * @description creates an easy to use tab system provided conventions are used
 * @conventions
 * 
 * <div id="a-container-that-holds-everything">
 * 		<ul><li class="tab" id="myTab"></li></ul>
 * 		<div id="myTab-tab" class="tab-content"></div>
 * </div>
 */ 

Tabs = {
	
	config: {CLASS: 'tab', SUFFIX: '-tab', CONTENT_CLASS: 'tab-content', HIDDEN_CLASS: 'hidden'},
	Tabs: null,
	
	
	init: function(){
			
		Tabs.tabs = $('.'+Tabs.config.CLASS);

		if(Tabs.tabs.length == 0){

			Page.deleteQueue(Tabs);
			return;
			
		}

		Tabs.bindEvents();		
		
	},
	
	bindEvents: function(){
		
		Tabs.tabs.bind('click', Tabs.switchTab);	
		
	},
	
	switchTab: function(){
		
		var parent = $(this).parent().parent(), id = $(this).attr('id'), container = $('#'+id+Tabs.config.SUFFIX);		
		
		$('.selected').removeClass('selected');	
	
		$(parent).find('.'+Tabs.config.CONTENT_CLASS).addClass(Tabs.config.HIDDEN_CLASS);
		$(container).removeClass(Tabs.config.HIDDEN_CLASS);
		$(this).addClass('selected');
	}

}

/* @class LB
 * @requires Page, document, jQuery
 *
 * @description Lightbox Framework to create easy lightboxes
 *
 * @conventions
 * <div id="lbbg"> This is the background, probably already in the mark up </div>
 * <div id="lbBtn" class="lb"></div>
 * <div id="lbBtn-lb">Light box content goes here. </div>
 *
*/

LB = {

    config: {CLASS: 'lb', BG_ID: 'lbbg', SUFFIX: '-lb', LB_VISIBLE: 'lb-visible', LB_CLOSE: 'close', FADE_TIME: 300},
    isActive: false,
    to: null, //used with IE window resize
    sc: null, //used on window scroll
	curLightBox: null,

	//runs on Page load

	init: function(){

		if($('.'+LB.config.CLASS).length == 0){ //deletes LB from memory if not used

			 Page.deleteQueue(LB);
			 return;

		}

		$('.'+LB.config.CLASS).bind('click', LB.show);

    	$('#'+LB.config.BG_ID).bind('click', LB.hide);

    	(Page.doc.all)? $(Page.doc).bind('keydown', LB.testEscape) : $(Page.win).bind('keydown', LB.testEscape);
    	(Page.doc.all)? $(Page.win).bind('resize', LB.set) : $(Page.win).bind('resize', LB.reposition);
    	$(Page.win).bind('scroll', LB.setScroll);

	},

    show: function(t){
		
		if(Page.config.MODULE == 'dqrewards'){

			var server = $('#server_id').val(), char = $('#char_id').val();

			if(server == -1 || char == -1)  return;	

		}


        LB.isActive = true;
		var id ='';

        ($(t).attr('id'))? id = $(t).attr('id') : id = $(this).attr('id');
        var LBox = $('#'+id+LB.config.SUFFIX);

		LB.curLightBox = LBox;	

        if(LBox.length == 0) return;

        $('#'+LB.config.BG_ID).width(Utils.calculateScreenWidth()).height(Utils.calculateScreenHeight());
        $('#'+LB.config.BG_ID).fadeIn(LB.config.FADE_TIME);

        LBox.css('left', Utils.calculateCenterX(LBox)).css('top', Utils.calculateCenterY(LBox));

        LBox.fadeIn(LB.config.fadeTime).addClass(LB.config.LB_VISIBLE);

        LBox.find('.'+LB.config.LB_CLOSE).bind('click', LB.hide);

		var isFocused = false;

        LBox.find('input, a').each(function(){

            if(this.nodeName == 'INPUT' && !isFocused){

                $(this).focus();
                isFocused = true;
                return;
            }

        });

    },

    hide: function(){

        $('.'+LB.config.LB_VISIBLE).fadeOut(LB.config.FADE_TIME).removeClass(LB.config.LB_VISIBLE);
        $('#'+LB.config.BG_ID).fadeOut(LB.config.FADE_TIME);
		$(LB.curLightBox).fadeOut(LB.config.FADE_TIME);

        LB.isActive = false;

    },

	//runs when window is resized

	reposition: function(){

        if(!LB.isActive) return;

        $('.'+LB.config.LB_VISIBLE).each(function(){

            $(this).animate({

                left: Utils.calculateCenterX($(this)),
                top: Utils.calculateCenterY($(this))

            }, LB.config.FADE_TIME).dequeue();


        })

        $('#'+LB.config.BG_ID).width(Utils.calculateScreenWidth()).height(Utils.calculateScreenHeight());


    },

	//sets timeout on window resize

    set: function(){

        clearTimeout(LB.to);
        LB.to = setTimeout("LB.reposition()", 100);

    },
	
	//when window is scrolled

    setScroll: function(){

        if(!LB.isActive) return;

        clearTimeout(LB.sc);
        LB.sc = setTimeout("LB.reposition()", 100);

    },

	//if user hits escape while lightbox is active

    testEscape: function(e){

        if(!LB.isActive) return;

        var kc = e.keyCode;

        if(kc == 27) LB.hide();

    }

}

/* @class Checkbox
 * @requires document, Page, jQuery
 * @ description controls custom checkbox functionality
 *
 * @conventions
 *
 * <div id="myCB-cb" class="cb"></div>
 * <input id="myCB" type="checkbox" />
 *
 */

Checkbox = {

	config: {CHECKED_CLASS: 'checked', SUFFIX: '-cb', CB_CLASS: 'cb'},

	init: function(){

		if($('.'+Checkbox.config.CB_CLASS).length == 0){ //deletes Checkbox if not used

			Page.deleteQueue(Checkbox);
			return;

		}

		Checkbox.bindEvents();

	},

	bindEvents: function(){

		var checked = $('.'+Checkbox.config.CB_CLASS);

		if(checked.length > 0) checked.bind(Checkbox.config.CHECKED_CLASS, Checkbox.toggleChecked);

	},

	toggleChecked: function(){

		var id = $(this).attr('id').replace(Checkbox.config.SUFFIX, '');
		
		if($(this).hasClass(Checkbox.config.CHECKED_CLASS)){

			$(this).removeClass(Checkbox.config.CHECKED_CLASS);
			$('#'+id).removeAttr('checked');
		
		}else{

			$(this).addClass(Checkbox.config.CHECKED_CLASS);
			$('#'+id).attr('checked', 'true');

		}		

	}

}

/* @ Perfect World Entertainment
 * @ class DD
 * @ requires document, Page, jQuery
 * @ description Creates custom dropdowns with numerous accessibility features
 *
 * @conventions
 *
 * Mark up must be in this format
 *
 * <div id="someID" class="dd" target="myFormInputId">
 *		<a href="/">Some Value </a>
 *		<div class="outer-dd">
 *			<div class="scroller><div></div></div>
 *			<div class="inner-dd">
 *				<ul>
 *					<li></li>
 *				</ul>
 *			</div>
 *		</div>
 *	</div>	
 *	<input type="hidden" id="myFormInputId-input" />
 */

DD = {

	config: {DD_CLASS: "dd", LI_VALUE_ATTR: "val", INPUT_LOCATION_ATTR: "target", INPUT_SUFFIX: '-input', SCROLLBAR_CLASS: 'scrollbar', OUTER_CLASS: 'outer-dd', INNER_CLASS: 'inner-dd', SELECTED_LI_CLASS: 'selectedOption'},
	listIndex: [], //used when reading keydowns
	scrollbars: [], //will hold ScrollBar Objects
	dispError: false, //this is true when the UL is hidden at the start (meaning we can't get it's height to calculate the ratio)
	mozillaScrollReference: null, //used with middle mouse button scrolling

	init: function(){

		if($('.'+DD.config.DD_CLASS).length > 0){	

			DD.bindEvents();
			
			$('.'+DD.config.DD_CLASS).find('div.'+DD.config.OUTER_CLASS).each(function(){

				var w = $(this).parent().outerWidth();
				$(this).width(w);
				var h1 = $(this).height();
				var h2 = $(this).find('ul').eq(0).height();
				if(h2 > h1 && h1 != 0){ //if the inner list is taller than the outer add a scrollbar
					DD.scrollbars.push(new ScrollBar($(this))); //creates scrollbars 
				
				}else{
					
					if(h2 == 0) DD.dispError = true; //the UL is hidden, will calculate later

					$(this).find('.'+DD.config.SCROLLBAR_CLASS).hide();

				}

				$(this).hide().css('left', 'auto');
	
			});

		}else{

			Page.deleteQueue(DD);
			Page.deleteQueue(ScrollBar);
			return;

		}

	},

	bindEvents: function(){
		
		 	$('.'+DD.config.DD_CLASS).find('a').bind('click', DD.toggleDD);
			$('.'+DD.config.DD_CLASS).find('li').bind('click', DD.setValue);
			$('.'+DD.config.DD_CLASS).find('a').bind('keydown', DD.cycleValuesInit);
			$('.'+DD.config.DD_CLASS).find('a').click(function(){ return false;});
	},

	createScrollbars: function(t){ //called at a later date if dispError is true, creates the scrollbar, this usually gets called due to ajax calls
		
				t = t.parent();
                var w = t.width();
                t.width(w);
                var h1 = t.find('div.'+DD.config.OUTER_CLASS).height();
                
				var h2 = 0;
				
				var lis = t.find('ul').eq(0).find('li');
					
				for(var i = 0; i<lis.length; i++) h2 += Math.abs(lis.eq(i).outerHeight());
 					
				t.find('ul').eq(0).height(h2);
				
				if(h2 > h1){
					
                     DD.scrollbars.push(new ScrollBar(t.find('div.'+DD.config.OUTER_CLASS)));
					 t.find('.'+DD.config.SCROLLBAR_CLASS).show();
                
				}else{

                    t.find('.'+DD.config.SCROLLBAR_CLASS).hide();

                }

	},

	toggleDD: function(){	//toggles the menu

		if($(this).parent().hasClass('disabled') || $(this).hasClass('disabled')) return;

		var cont = $(this).parent().find('div.'+DD.config.OUTER_CLASS).eq(0);
		
		var sb = DD.getMatchingScrollbar(cont);
		
		if(cont.is(":visible")){

			$('body').unbind('click', DD.checkBodyClick); //if you click outside the dropdown it hides it
			 cont.hide();
			
			if($.browser.mozilla){

				try{
				 	Page.win.removeEventListener('DOMMouseScroll', sb.onWheel, false);
				}catch(e){}

			}else{

				Page.doc.onmousewheel = null;

			}

		}else{

			if($('div.'+DD.config.OUTER_CLASS).is(":visible")) $('div.'+DD.config.OUTER_CLASS).hide(); //hides other dropdowns
			cont.show();
			$('body').bind('click', DD.checkBodyClick);
			if(DD.dispError) DD.createScrollbars($(this)); //if the UL is hidden
		
			if(sb){

				if($.browser.mozilla){

					Page.win.addEventListener('DOMMouseScroll', sb.onWheel, false);
					DD.mozillaScrollReference = sb;
	
				}else{

					 Page.doc.onmousewheel = sb.onWheel;
				
				}

				sb.innerContWrap.scrollTop(sb.curScrollTop);
	
				if($.browser.mozilla){	
					
					if(sb.scroller.position().top > sb.outerHeight - sb.scroller.height()) sb.scroller.css('top', sb.outerHeight - sb.scroller.height());
		
				}

			}
		}

	},

	//checks if the user clicks outside the dropdown
	checkBodyClick: function(e){ 

		if($(e.target).hasClass(DD.config.DD_CLASS)) return;

		var par = $(e.target), ddClicked = false, i = 0;

		while(true){

			if(i > 7) break;
			par = par.parent();
			i++;
			if(par.hasClass(DD.config.DD_CLASS)){
				
				ddClicked = true;
				break;
			}
			 

		}	
				
		if(!ddClicked){

			if($.browser.mozilla){
				try{
				 	Page.win.removeEventListener('DOMMouseScroll', DD.mozillaScrollReference.onWheel, false);
				}catch(e){}

			}else{

				 Page.doc.onmousewheel = null;
			
			}

			$('div.'+DD.config.OUTER_CLASS).hide();
			$('body').unbind('click', DD.checkBodyClick);
	
		}
	},
	//writes value to the input
	setValue: function(){

		var list = $(this).parent().parent().parent().parent();
		var val = $(this).attr(DD.config.LI_VALUE_ATTR);
		var target = list.attr(DD.config.INPUT_LOCATION_ATTR);
		$('#'+target + DD.config.INPUT_SUFFIX).val(val);
		list.children().eq(0).text($(this).text());

		$(this).parent().parent().parent().hide();

	},
	//called when user keydowns while the input (a) is focused
	//potential flow for keydowns is cycleValuesInit => cycleValues => searchValues
	cycleValuesInit: function(e){
		
		if(e.which == 9){ //if tab is hit
			
			$(this).parent().find('div.'+DD.config.OUTER_CLASS).hide(); 
			return;

		}else{

			var listIndexKey = $(this).parent().attr('id');
		
			if(DD.listIndex[listIndexKey] == null){ //if the array key for the index does not exist create it

				DD.listIndex[listIndexKey] = 0;
				DD.cycleValues(e.which, -1, $(this).parent().find('ul').eq(0), $(this), listIndexKey);		

			}else{

			DD.cycleValues(e.which, DD.listIndex[listIndexKey], $(this).parent().find('ul').eq(0), $(this), listIndexKey);

			}

			e.preventDefault();

		}

	},

	//cycles through the values of the dropdown

	cycleValues: function(key, index, list, srcElement, listIndexKey){
		
		switch(key){

        	case 38: //up
            	index--;
				DD.listIndex[listIndexKey]--;
				break;

        	case 40: //down
            	index++;
				DD.listIndex[listIndexKey]++;
            	break;

			case 13: //enter
				DD.toggleDD();
				return;

			default:
				DD.searchValues(key, index, list, srcElement, listIndexKey);
				return;

    	}
		
    	if(index < 0){

			index = DD.listIndex[listIndexKey] = list.find('li').length - 1;

    	}else if(index >= list.find('li').length){

			index = DD.listIndex[listIndexKey] = 0;
    	}

		//this part controls the scrolltop and scrollbar, only runs if up or down key is hit
	
		$('li.'+DD.config.SELECTED_LI_CLASS).removeClass(DD.config.SELECTED_LI_CLASS);
		srcElement.parent().find('li').eq(index).addClass(DD.config.SELECTED_LI_CLASS);	
		srcElement.text(srcElement.parent().find('li').eq(index).text());
		$('#'+listIndexKey+DD.config.INPUT_SUFFIX).val(srcElement.parent().find('li').eq(index).attr(DD.config.LI_VALUE_ATTR));
		
		var sbObj = DD.getMatchingScrollbar(srcElement);
		var liHeight = srcElement.parent().find('li').eq(0).outerHeight()		
		var scHeight = sbObj.scroller.height();
		var posY = index * liHeight;

		sbObj.innerContWrap.scrollTop(posY);
		
		if(posY > scHeight && parseInt(sbObj.scroller.css('top')) < (sbObj.outerHeight-scHeight)){

			if(posY/sbObj.ratio > sbObj.outerHeight - scHeight){

				sbObj.scroller.css('top', sbObj.outerHeight - scHeight);

			}else{

				sbObj.scroller.css('top', posY/sbObj.ratio);

			}

		}else if(parseInt(sbObj.scroller.css('top')) >= (sbObj.outerHeight-scHeight) && index != 0){

			if(key == 38){

				if(posY/sbObj.ratio < sbObj.outerHeight - scHeight){

					sbObj.scroller.css('top', posY/sbObj.ratio);

				}else{

					sbObj.scroller.css('top', sbObj.outerHeight - scHeight);

				}

			}else{

				sbObj.scroller.css('top', sbObj.outerHeight - scHeight);

			}
		
		}else if(index == 0){

			sbObj.scroller.css('top', 0);

		}else{
			
			sbObj.scroller.css('top', 0);

		}

	},
	//returns the scrollbar obj based on the dropdown that's clicked
	getMatchingScrollbar: function(el){

		var id = el.parent().attr('id');
		var sb = null;		
			
		for(var i = 0; i<DD.scrollbars.length; i++){
				
			if(DD.scrollbars[i].outerCont.parent().attr('id') == id){

				sb = DD.scrollbars[i];
				break;
			};

		}
		
		return sb;

	},
	//runs if letter key is keydowned
	searchValues: function(key, index, list, srcElement, listIndexKey){
		
		var items = $.makeArray(srcElement.parent().find('li'));
		var text = [];

		for(var i = 0; i<items.length; i++) text.push(items[i].innerHTML);

		text.sort();
		
		if(key >47 && key<91){ //a - z

			var value = String.fromCharCode(key);
			var r1 = 0;
			var r2 = 0;			
			
			for(var i=0; i<text.length; i++){
		
				var l = text[i][0];		
				
				if(l < value){

					r1 = i;

				}else if( l > value){

					break;

				}

			}
			
			var selectedText = '';
			(r1 != 0)? selectedText = text[r1 + 1] : selectedText = text[r1];
			
			var selectedValue = '';

			srcElement.parent().find('li').each(function(){

				if($(this).text() == selectedText) selectedValue = $(this).attr(DD.config.LI_VALUE_ATTR);

			});

			for(i = 0; i<items.length; i++){

				 DD.listIndex[listIndexKey] = i;
				 if($(items).eq(i).text() == selectedText) break;
			
			}

			srcElement.text(selectedText);
			$('#'+srcElement.parent().attr(DD.config.INPUT_LOCATION_ATTR)+DD.config.INPUT_SUFFIX).val(selectedValue);
		}
	}

}

/* @class ScrollBar
 * @requires document, Page, jQuery
 * @param el - > div.outer-dd
 * 
 * @description
 *
 * This is an object representation of the scrollbar and controls it's functionality
 * each scrollbar has it's own ScrollBar object
 */

function ScrollBar(el){
	
	this.outerCont = el;
	this.innerContWrap = el.find('div.'+DD.config.INNER_CLASS);
	this.innerCont = el.find('ul').eq(0);
	this.bar = el.find('.'+DD.config.SCROLLBAR_CLASS);
	this.scroller = this.bar.find('div').eq(0);
	this.outerHeight = this.outerCont.height();
	this.outerWidth = this.outerCont.width();
	this.innerHeight = this.innerCont.height();
	this.ratio = this.innerHeight/this.outerHeight; 
	this.offsetY = el.position().top;
	this.cursorY = null;
	this.maxTop = 0;	
	this.isIE = false;	
	this.curScrollTop = 0;

	var sb = this; //closure reference 
	
	this.outerCont.scrollTop(0); 

	this.bar.css('margin-left', this.outerWidth - this.scroller.width()).height(this.outerHeight); //positions scrollbar
	this.scroller.height(this.outerHeight/this.ratio).css('left', 0); //resizes scroller
	this.scroller.attr('draggable', 'false'); //so when you mousedown it doesn't treat the element as draggable
	this.maxTop = this.outerHeight - this.scroller.height(); //the maximum the scroller can scroll down

	if($.browser.msie) this.isIE = true;
	//runs on mousedown
	this.scrollInit = function(e){
		
		if($.browser.msie && $.browser.version == '7.0' || $.browser.msie && $.browser.version == '8.0'){
			$(Page.doc).bind('mousemove', sb.scroll);
            $(Page.doc).bind('mouseup', sb.stopScroll);
		}else{
			
			$(Page.win).bind('mousemove', sb.scroll);
			$(Page.win).bind('mouseup', sb.stopScroll);
		}
		
		if(isNaN(parseInt(sb.scroller.css('top')))) sb.scroller.css('top', 0); 

		sb.cursorY = e.clientY - parseInt(sb.scroller.css('top')); //records the original mousedown	
		return false;
	}
	//runs on mousemove
	this.scroll = function(e){

		var y = e.clientY - sb.cursorY, r = y * sb.ratio;	
	
		if(y < 2) y = 0;
		if(y > sb.maxTop) y = sb.maxTop;
			
		sb.scroller.css('top', y);
		
		sb.innerContWrap.scrollTop(r);
		sb.curScrollTop = r;
	}

	//runs on mouseup
	this.stopScroll = function(e){

		if($.browser.msie && $.browser.version == '7.0' || $.browser.msie && $.browser.version == '8.0'){
            $(Page.doc).unbind('mousemove', sb.scroll);
            $(Page.doc).unbind('mouseup', sb.stopScroll);

        }else{

            $(Page.win).unbind('mousemove', sb.scroll);
            $(Page.win).unbind('mouseup', sb.stopScroll);

        }

	}
	//runs when the user clicks on a part of the bar outside of the scroller
	this.scrollTo = function(e){
		
		if($(e.target).attr('class') != DD.config.SCROLLBAR_CLASS) return;
		
		var Y = 0, regx = /Chrome|Safari/;

		(Page.doc.all || regx.test(navigator.userAgent))? Y = e.offsetY : Y = e.layerY;
	  	
		var targetY = Y - sb.scroller.height()/2;
		var maxY = sb.outerHeight - sb.scroller.height();
	
		if(targetY < 0) targetY = 0;
		if(targetY > maxY) targetY = maxY; 	
			
		sb.scroller.css('top', targetY);
		sb.innerContWrap.scrollTop(targetY * sb.ratio);
		sb.curScrollTop = targetY * sb.ratio;
	}
	//runs on middle mouse wheel
	this.onWheel = function(e){
		
		if(!e) e = window.event;

		if(e.preventDefault) e.preventDefault();
		
		var sPos = sb.scroller.position().top;
		var sPos2 = sPos + sb.scroller.height();
	
		if(e.wheelDelta < 0 || e.detail > 0){
			
			if(sPos2 <= sb.outerHeight){
	
				if(sPos + 4 >= sb.outerHeight){

					sb.scroller.css('top', sb.outerHeight);
					sb.innerContWrap.scrollTop(sb.outerHeight * sb.ratio);
					sb.curScrollTop = sb.outerHeight * sb.ratio;
				}else{

					sb.scroller.css('top', sPos + 4);
					sb.innerContWrap.scrollTop((sPos + 4) * sb.ratio);
					sb.curScrollTop = (sPos + 4) * sb.ratio;
				}
			
			}			

		}else{

			if(sPos >= 0){

				if(sPos - 4 < 0){

					sb.scroller.css('top', 0);
					sb.innerContWrap.scrollTop(0);			
					sb.curScrollTop = 0;
				}else{

					sb.scroller.css('top', sPos - 4);
					sb.innerContWrap.scrollTop((sPos - 4) * sb.ratio);
					sb.curScrollTop = (sPos - 4) * sb.ratio;
				}
			}	

		}	

		return false;

	}

	this.scroller.bind('mousedown', this.scrollInit);
	this.bar.bind('click', this.scrollTo);	

}

/*  @class RequireLogin
 *	@requires document, Page, jQuery
 *  @description forces lightbox for login required pages
 *
 *	@conventions
 *
 *  <div id="myLink" class="check-login"></div>
 */

RequireLogin = {

	config: {PARSE_CLASS: 'check-login', REQUIRED_CLASS: 'require-login'},

	init: function(){

		var els = $('.'+RequireLogin.config.PARSE_CLASS);

		if(els.length > 0 && !Page.userLoggedIn){

			 els.addClass('require-login');

			$('.'+RequireLogin.config.REQUIRED_CLASS).bind('click', RequireLogin.proxyLBOpen);

		}else{ //deletes from memory if not used

			Page.deleteQueue(RequireLogin);
			return;

		}

	},

	proxyLBOpen: function(e){

		LB.show(Page.doc.getElementById('login'));
		e.preventDefault();

	}

}

/* @class LangCheck
 * @requires document, Page, jQuery
 * @description 
 *
 * Shows the languages selection lightbox for sites that are marked enabled
 * for the functionality, this is a rewrite of the original langcheck.js, this is
 * called for European users visiting our english sites for the first time
 */

LangCheck = {

	config: {SELECTED_CLASS: 'selected'},
	content: null,
	timeout: null,

	init: function(){
	
		if($('#langpref').length == 0){

			Page.deleteQueue(LangCheck);
			return;
	
		}

		LangCheck.content = $('#langpref');
		LangCheck.bindEvents();
		LangCheck.positionLB();

	},

	bindEvents: function(){

		$('.radio, .langFlag').bind('click', LangCheck.chooseLang);
		$('#lbbg').bind('click', LangCheck.saveLang);		
		$('#langsave').bind('click', LangCheck.saveLang);
		LangCheck.content.find('.close').bind('click', LangCheck.saveLang);
		$(Page.win).bind('resize', LangCheck.resizeInit);
		$(Page.win).bind('scroll', LangCheck.resizeInit);
	},

	positionLB: function(){

		$('#lbbg').fadeIn(350).width(Utils.calculateScreenWidth()).height(Utils.calculateScreenHeight());

		LangCheck.content.css('left', Utils.calculateCenterX(LangCheck.content)).css('top', Utils.calculateCenterY(LangCheck.content)).fadeIn(350);
	},

	chooseLang: function(){

		$('.radio').removeClass(LangCheck.config.SELECTED_CLASS).attr(LangCheck.config.SELECTED_CLASS, 'false');

		var radio = null;

		($(this).hasClass('radio'))? radio = $(this) : radio = $(this).prev('.radio');

		radio.addClass(LangCheck.config.SELECTED_CLASS).attr(LangCheck.config.SELECTED_CLASS, 'true');
	},

	resizeInit: function(){

		clearTimeout(LangCheck.timeout);

		setTimeout("LangCheck.resize()", 20);

	},

	resize: function(){

		LangCheck.content.animate({

			left: Utils.calculateCenterX(LangCheck.content),
			top: Utils.calculateCenterY(LangCheck.content)

		}, 300).dequeue();	

		$('#lbbg').width(Utils.calculateScreenWidth()).height(Utils.calculateScreenHeight());
	
	},

	saveLang: function(){

		var redirectLang = 'en';

		$('.radio').each(function(){

			if($(this).hasClass(LangCheck.config.SELECTED_CLASS)) redirectLang = $(this).attr('lang');

		});

		$.ajax({

			url: '/home/langcheck',
			type: 'post',
			data: 'lang=',
			success: function(data){

				if(redirectLang == 'en'){ 

					LangCheck.content.fadeOut(350);
					$('#lbbg').fadeOut(500).unbind('click', LangCheck.chooseNone);					
	
				}else{ 

					LangCheck.redirect(redirectLang);

				}

			}
		});


		$(Page.win).unbind('resize', LangCheck.resizeInit);
        $(Page.win).unbind('scroll', LangCheck.resizeInit);

	},


	redirect: function(redirectLang){

		var loc = Page.config.LOCATION;		
		
		switch(redirectLang){

				case 'de':
					
					loc = loc.replace('www', '');
					loc = loc.replace('perfectworld', 'de.perfectworld');
					loc = loc.replace('.com', '.eu');

					break;

				case 'fr':

					loc = loc.replace('www', '');
					loc = loc.replace('perfectworld', 'fr.perfectworld');
					loc = loc.replace('.com', '.eu');

					break;

		}			

		location.replace(loc);	

	}

}

/* @class RecentActivity
 * @requires document, Page, jQuery
 * @description 
 *
 * fetches activities, splits and queues results, rotates them marquee-style 
 * Used with our recent activity module.
 */

RecentActivity = {

    config: {NUM_ACTIVITIES: null, URL: '/home/recent_activity'},
    queuedActivities: [],
    curIndex: 0,
    ulContainer: null,
    interval: null,

    init: function(){

		if($('.bg-recent').length == 0){

			Page.deleteQueue(RecentActivity);					
			return;			

		}
	
        RecentActivity.getActivities();
        RecentActivity.ulContainer = $('.bg-recent').find('ul').eq(0);

    },

    getActivities: function(){

        $.ajax({

            url: RecentActivity.config.URL,
            type: 'post',
            data: null,
            success: function(data){

                if(data.indexOf('<html') != -1 || data.indexOf('Fatal Error') != -1){

                    $('.bg-recent').removeClass('ra-loading').append('<h3> Error loading recent activity. </h3>');
                    return;

                }

                RecentActivity.formatData(data);

            },

            error: function(xhr, err){

                $('.bg-recent').removeClass('ra-loading').append('<h3> Error loading recent activity. </h3>');

            }

        });

    },

	formatData: function(data){

        RecentActivity.queuedActivities = data.split('</li>');
        RecentActivity.queuedActivities.pop();

        RecentActivity.config.NUM_ACTIVITIES = RecentActivity.queuedActivities.length

        for(var i = 0; i<RecentActivity.config.NUM_ACTIVITIES; i++) RecentActivity.queuedActivities[i] += '</li>';

        RecentActivity.initContainer();

        $('.bg-recent').removeClass('ra-loading');

    },

    initContainer: function(){

        for(var i = 0; i<4; i ++){

            setTimeout("RecentActivity.ulContainer.append(RecentActivity.queuedActivities["+i+"])", 200 * i);
            RecentActivity.curIndex++;
        }

        if(RecentActivity.config.NUM_ACTIVITIES < 4) return;

        RecentActivity.interval = setInterval("RecentActivity.rotate()", 3000);

    },

    addActivity: function(){

        RecentActivity.ulContainer.append(RecentActivity.queuedActivities[RecentActivity.curIndex]);

    },

	removeActivity: function(){

        RecentActivity.ulContainer.find('li').eq(0).remove();

    },

    rotate: function(){

        (RecentActivity.curIndex == RecentActivity.config.NUM_ACTIVITIES - 1)? RecentActivity.curIndex = 0 : RecentActivity.curIndex++;

        RecentActivity.addActivity();

        RecentActivity.ulContainer.find('li').eq(0).animate({

            marginTop: -58

        }, 350, RecentActivity.removeActivity);

    }
}

/* @class OffersPU
 * @requires document, Page, Utils
 * 
 * @description Controls the zen offer popup
 *
 */

OffersPU = {

    bg: null,
    popup: null,
    btns: {cont: null, canc: null},
    trigger: false,

    init: function(){

        if(!OffersPU.trigger){

            Page.deleteQueue(OffersPU);
			return;
        }

        OffersPU.setElements();
        OffersPU.bindEvents();
        OffersPU.callLightBox();

    },

    bindEvents: function(){

        OffersPU.btns.cont.bind('click', OffersPU.viewOffer);
        OffersPU.btns.canc.bind('click', OffersPU.cancelOffer);

    },

    setElements: function(){

        OffersPU.bg = $('#offerslbbg');
        OffersPU.popup = $('#offers-popup');
        OffersPU.btns.cont = $('#btn-continue');
        OffersPU.btns.canc = $('#btn-cancel');

    },

    callLightBox: function(){

        OffersPU.bg.hide().width(Utils.calculateScreenWidth()).height(Utils.calculateScreenHeight()).fadeIn(300);
        OffersPU.popup.hide().css('left', Utils.calculateCenterX(OffersPU.popup)).css('top', Utils.calculateCenterY(OffersPU.popup)).fadeIn(300);

    },

    viewOffer: function(){

        $.getJSON('http://www.perfectworld.com/home/continuepopup?ajax=1&callback=?', null, function(data){});

        location.href = 'http://offers.perfectworld.com';

    },

    cancelOffer: function(){

        $.getJSON('http://www.perfectworld.com/home/cancelpopup?ajax=1&callback=?', null, function(data){});

        OffersPU.bg.fadeOut(300);
        OffersPU.popup.fadeOut(300);

    }
}

//------------- end global.js objects ----------------------------//

Page.queue(Tabs.init);
Page.queue(LB.init);
Page.queue(Utils.getURLComponents, 'init');
Page.queue(Checkbox.init);
Page.queue(DD.init);
Page.queue(RequireLogin.init);
Page.queue(RecentActivity.init);

$(document).ready(Page.onLoad);	



