﻿// ****************************************************************************
// ** Core Functions & Basic API for <passport.mx>
// ****************************************************************************
// @file    : base.js
// @codex   : Javascript v1.2
// @version : 1.0.0
// @author  : Jinjiang
// @update  : 2009-06-15 03:28 PM
// @note    : Has 2 parts.
// ****************************************************************************


//============================================================================
// ** Core functions
//============================================================================


//----------------------------------------------------------------------------
// ** Get element by id
//----------------------------------------------------------------------------
// @param <string> id : The id of the element
// @return <element> : an element with this id
//----------------------------------------------------------------------------
function $(id){
	return document.getElementById(id);
}

//----------------------------------------------------------------------------
// ** Create a new element
//----------------------------------------------------------------------------
// @param <string> tagName : the tag name of element to create
// @return <element> : an new element with this tag name
//----------------------------------------------------------------------------
function $new(tagName) {
	return document.createElement(tagName);
}

//----------------------------------------------------------------------------
// ** Do nothing. Often used to instead a existed function for removing it
//----------------------------------------------------------------------------
function $null() {
}

//----------------------------------------------------------------------------
// ** Create a random string with the certain length
//----------------------------------------------------------------------------
// @param <int> l : the length of random string
// @return <string> : random string with the certain length
//----------------------------------------------------------------------------
function $anychar(l)	{
	var x='0123456789qwertyuioplkjhgfdsazxcvbnm';
	var tmp='';
	for(var i=0; i < l; i++)	{
		tmp += x.charAt(Math.ceil(Math.random()*100000000)%x.length);
	}
	return tmp;
}

//----------------------------------------------------------------------------
// ** Clear the space characters in a String
//----------------------------------------------------------------------------
// @return <string> : result string without spaces
//----------------------------------------------------------------------------
String.prototype.trim = function(){
	return this.replace(/^\s+|\s+$/g,'');
}


//============================================================================
// ** Lite interfaces (by SiC)
//============================================================================
if(!Lite) {
	var Lite = {};
}


//============================================================================
// ** IO Lite interfaces
//============================================================================
Lite.IO = {
	// create ajax request object
	XMLHttpRequest: function(){
		if (window.XMLHttpRequest) return new XMLHttpRequest;
		else if (window.ActiveXObject) {
			var req;
			try { req = new ActiveXObject('Msxml2.XMLHTTP'); }
			catch (e) { try { req = new ActiveXObject('Microsoft.XMLHTTP'); }
				catch (e) { return null; }}
			return req;
		} else return null;
	},
	// do a GET request
	ajaxGet: function(url,args,cb,sync){ // async by default
		var req = this.XMLHttpRequest();
		if (args != '') args = '?' + args;
		req.open('GET', url + args, !sync);
		req.onreadystatechange = function(){ Lite.IO.__ORSC__(req,cb);};
		req.send('');
	},
	// do a POST request
	ajaxPost: function(url,args,cb,sync){
		var req = this.XMLHttpRequest();
		req.open('POST', url, !sync);
		req.setRequestHeader('Method', 'POST ' + url + ' HTTP/1.1');
		req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
		req.onreadystatechange = function(){ Lite.IO.__ORSC__(req,cb);};
		req.send(args);
	},
	// alert error
	error: function(errcode){
		alert('Ajax error'+errcode);
	},
	// request process
	__ORSC__: function(req,cb){
		if (req.readyState != 4) return;
		try {var s = req.status;} 
		catch (ex) {this.error('HTTP status code not find!');}
		if(cb){
			if(cb.success){ // cb = {object}
				if (s == 200) cb.success(req);
				else cb.error?cb.error(s):this.error(s);
				if (cb.timeout) { // request overtime
					setTimeout(function() {
						if (req.readyState == 4) return;
						req.abort();
						req.onreadystatechange = DUMMY;
						this.error(408);
					}, cb.timeout);
				}
			}else{ // cb = {function}
				if (s == 200) cb(req);
				else this.error(s);
			}
		}
	}
};


//============================================================================
// ** UTIL Lite interfaces
//============================================================================
Lite.UTIL = {
	// get document size
	docSize:function(){
		var xScroll, yScroll;
		if (window.innerHeight && window.scrollMaxY) {
			xScroll = document.body.scrollWidth;
			yScroll = window.innerHeight + window.scrollMaxY;
		} else if (
			document.body.scrollHeight > document.body.offsetHeight
		){ // all but Explorer Mac
			xScroll = document.body.scrollWidth;
			yScroll = document.body.scrollHeight;
		} else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
			xScroll = document.body.offsetWidth;
			yScroll = document.body.offsetHeight;
		}

		var winS = Lite.UTIL.winSize();
		var windowWidth = winS.w, windowHeight = winS.h;
		// for small pages with total height less then height of the viewport
		if(yScroll < windowHeight){
			pageHeight = windowHeight;
		} else {
			pageHeight = yScroll;
		}

		// for small pages with total width less then width of the viewport
		pageWidth = xScroll;

		return {w: pageWidth, h: pageHeight};
	},
	// get window size
	winSize:function(){
		var windowWidth, windowHeight;
		if (self.innerHeight) { // all except Explorer
			windowWidth = self.innerWidth;
			windowHeight = self.innerHeight;
		} else if (
			document.documentElement &&
			document.documentElement.clientHeight
		) { // Explorer 6 Strict Mode
			windowWidth = document.documentElement.clientWidth;
			windowHeight = document.documentElement.clientHeight;
		} else if (document.body) { // other Explorers
			windowWidth = document.body.clientWidth;
			windowHeight = document.body.clientHeight;
		}
		return {w:windowWidth,h:windowHeight};
	},
	// get element position
	dimensions: function(obj) {
		if (!obj)
			return {'x': 0, 'y': 0};
		var left = 0;
		var top = 0;
		while(obj) {
			left += obj.offsetLeft;
			top += obj.offsetTop;
			obj = obj.offsetParent;
		}
		return {'x': left, 'y': top};
	},
	// copy string to clipboard
	copy: function(strCode) {
		if(window.clipboardData) {
			window.clipboardData.clearData();
			window.clipboardData.setData('Text', strCode);
		}
		else if(navigator.userAgent.indexOf('Opera') != -1) {
			window.location = strCode;
		}
		else if (window.netscape) {
			try {
				netscape.security.PrivilegeManager
					.enablePrivilege('UniversalXPConnect');
			}
			catch (e) {
				alert('something was not allowed. you should set ' +
					'"signed.applets.codebase_principal_support" to "true"' +
					' value through "about:config" for your firefox');
				return false;
			}
			var clip = Components.classes['@mozilla.org/widget/clipboard;1']
				.createInstance(Components.interfaces.nsIClipboard);
			if (!clip)
				return;
			var trans = Components.classes['@mozilla.org/widget/transferable;1']
				.createInstance(Components.interfaces.nsITransferable);
			if (!trans)
				return;
			trans.addDataFlavor('text/unicode');
			var str = new Object();
			var len = new Object();
			var str = Components.classes['@mozilla.org/supports-string;1']
				.createInstance(Components.interfaces.nsISupportsString);
			var copytext = strCode;
			str.data = copytext;
			trans.setTransferData('text/unicode',str,copytext.length*2);
			var clipid = Components.interfaces.nsIClipboard;
			if (!clip)
				return false;
			clip.setData(trans,null,clipid.kGlobalClipboard);
		}
	},
	// add as a bookmark to browser
	bookmark:function (url,title) {
		if (window.sidebar) {
			window.sidebar.addPanel(title, url,'');
		} else if( document.all ) {
			window.external.AddFavorite( url, title);
		} else if( window.opera && window.print ) {
			alert('no method support this action [addBookMark]');
			return true;
		}
	},
	// set url to browser homepage
	homepage:function(url){
		 if (document.all){
			document.body.style.behavior='url(#default#homepage)';
			document.body.setHomePage(url);
		}else if (window.sidebar){
			if(window.netscape){
				try{
					netscape.security.PrivilegeManager
						.enablePrivilege('UniversalXPConnect');
					var prefs = Components
						.classes['@mozilla.org/preferences-service;1']
						.getService(Components. interfaces.nsIPrefBranch);
					prefs.setCharPref('browser.startup.homepage',url);
				}catch (e){
					alert('该操作被浏览器拒绝，如果想启用该功能，请在地址栏内输入' +
						' about:config,然后将项' +
						' signed.applets.codebase_principal_support 值该为true');
				}
			}
		}
	}
};


//============================================================================
// ** Basic API for <passport.mx>
//============================================================================

//============================================================================
// ** Form API
//============================================================================
var formAssister = {
	// check password length and matched
	checkPassword: function() {
		if (!window['passwordObj']) {
			window['passwordObj'] = $('password');
			passwordObj['confirm'] = $('password-confirm');
			passwordObj['lengthWarning'] = $('password-length-warning');
			passwordObj['matchedWarning'] = $('password-matched-warning');
		}
		if (
			passwordObj.value.length == 0 || 
			passwordObj.confirm.value.length == 0
		) {
			passwordObj.lengthWarning.style['display'] = 'inline';
			passwordObj.matchedWarning.style['display'] = 'none';
		}
		else if ( 
			passwordObj.value != passwordObj.confirm.value
		) {
			passwordObj.lengthWarning.style['display'] = 'none';
			passwordObj.matchedWarning.style['display'] = 'inline';
		}
		else {
			passwordObj.lengthWarning.style['display'] = 'none';
			passwordObj.matchedWarning.style['display'] = 'none';
		}
	},
	// get password strength
	getPasswordStrength: function(str) {
		if (!window['passwordStrengthObj']) {
			window['passwordStrengthObj'] = $('password-strength');
			var list = passwordStrengthObj.getElementsByTagName('span');
			passwordStrengthObj['list'] = [list[0],list[1],list[2]];
			passwordStrengthObj['current'] = passwordStrengthObj.list[0];
		}
		var strength = 0;
		if (str.length<6) {
			strength = 1;
		}
		else {
			var strength1 = (str.search(/[a-zA-Z]/)!=-1) ? 1 : 0;
			var strength2 = (str.search(/[0-9]/)!=-1) ? 1 : 0;
			var strength3 = (str.search(/[^A-Za-z0-9_]/)!=-1) ? 1 : 0;
			var strength = strength1 + strength2 + strength3;
		}
		var current = passwordStrengthObj.list[strength - 1];
		current.className = 'current';
		if (current != passwordStrengthObj.current) {
			passwordStrengthObj.current.className = '';
			passwordStrengthObj.current = current;
		}
	},
	// refresh verify image
	getVerifyImage: function(objImage) {
		objImage.src = '/new/vimage.html?' + $anychar(3);
	},
	// set values for each select in data
	initAllSelect: function(data) {
		for (var i in data)
			this.setSelectValue($(i), data[i]);
	},
	// set value for select
	setSelectValue: function(objSelect, strValue) {
		var list = objSelect.options;
		for (var i = 0; i < list.length; i++) {
			var item = list[i];
			if (item && item.value == strValue)
				objSelect['selectedIndex'] = i;
		}
	},
	// rebuild options and set value for select
	initSelectOptions: function(objSelect, data, value) {
		objSelect.innerHTML = '';
		for (var i in data) {
			var temp = data[i];
			var objOption = document.createElement('option');
			objSelect.appendChild(objOption);
			objOption.value = i;
			objOption.innerHTML = temp;
		}
		this.setSelectValue(objSelect, value);
	},
	// check account is an email and not signed
	checkAccountStyle: function(obj) {
		if (!obj['styleWarning']) {
			obj['styleWarning'] = $('account-style-warning');
			obj['signedWarning'] = $('account-signed-warning');
		}
		var strEmail = obj.value;
		var regEmail = /^[0-9a-zA-Z\-\+_\.]+@([a-zA-Z0-9-]+[.])+([a-zA-Z]{2}|net|NET|com|COM|gov|GOV|mil|MIL|org|ORG|edu|EDU|int|INT)$/;
		var styleWarning = (
			strEmail.length > 100 ||
			strEmail.search(regEmail) == -1
		);
		obj.styleWarning.style['display'] = styleWarning ? 'inline' : 'none';
		if (!styleWarning) this.checkAccountSigned(obj);
		else obj.signedWarning.style['display'] = 'none';

	},
	// request email signed or not
	checkAccountSigned: function(obj) {
		var strEmail = obj.value;
		var url = '/new/submit/register_email_submit.html'
		var args = 'email=' + strEmail;
		Lite.IO.ajaxGet(url,args,function(req) {
			obj.signedWarning.style['display'] =
				(req.responseText == 2) ? 'inline' : 'none';
		});
	}
};


//============================================================================
// ** User's Location API
//============================================================================
var locationAssister = {
	// set location info for the selects
	initLocation: function(strCountry, needDetail, numProvince, numCity) {
		if (!window['locationInfo']) {
			window['locationInfo'] = {
				country: $('country'),
				province: $('province'),
				city: $('city')
			};
		}
		formAssister.setSelectValue(window.locationInfo.country, strCountry);
		this.buildProvinceSelection(null, strCountry);
		window.locationInfo.country.onchange = this.buildProvinceSelection;
		window.locationInfo.province.onchange = this.buildCitySelection;
		if (needDetail) {
			formAssister.setSelectValue(window.locationInfo.province, numProvince);
			this.buildCitySelection(null, numProvince);
			formAssister.setSelectValue(window.locationInfo.city, numCity);
		}
	},
	// build province select by country info
	buildProvinceSelection: function(evt, strCountry) {
		strCountry = strCountry || window.locationInfo.country.value;
		if(strCountry == 'cn')
			window.locationInfo.province.style['display'] =
				window.locationInfo.city.style['display'] = '';
		else {
			window.locationInfo.province.style['display'] =
				window.locationInfo.city.style['display'] = 'none';
			window.locationInfo.province.selectedIndex = 0;	 
			window.locationInfo.city.selectedIndex = 0;
		}
	},
	// build city select by province info
	buildCitySelection: function(evt, numProvince) {
		numProvince = numProvince || window.locationInfo.province.value;
		window.locationInfo.country.selectedIndex = 1; // choose china
		window.locationInfo.city.options.length = 0;
		window.locationInfo.city.options.add(new Option('',0));
		for (var i = 0; i < subcat.length; i++)
			if(subcat[i][2] == numProvince)
				window.locationInfo.city.options
					.add(new Option(subcat[i][0],subcat[i][1]));
	}
};


//============================================================================
// ** Security Questions API
//============================================================================
var securityAssister = {
	// init for security questions
	initQuestions: function() {
		if (!window['questions']) {
			window['questions'] = [
				$('security-question-1'),
				$('security-question-2'),
				$('security-question-3')
			];
		}
		var length = questions.length;
		for (var i = 0; i < length; i++) {
			var objSelect = questions[i];
			objSelect.onchange = securityAssister.resetSelectOptions;
		}
		securityAssister.resetSelectOptions();
	},
	// reset options for each select when value of one of them changed
	resetSelectOptions: function() {
		if (!window['questions']) return;
		var selectedValues = {};
		var length = questions.length;
		for (var i = 0; i < length; i++) {
			var value = questions[i].value;
			if (value == 0) continue;
			selectedValues[questions[i].value] = i;
		}
		for (var i = 0; i < length; i++) {
			var objSelect = questions[i];
			var options = {};
			for (var j in questionOptions) {
				var tempOption = questionOptions[j];
				if (
					!isNaN(selectedValues[j]) && 
					selectedValues[j] != i
				) {
					continue;
				}
				options[j] = tempOption;
			}
			formAssister.initSelectOptions(objSelect, options, objSelect.value);
		}
	}
};


//============================================================================
// ** Account API
//============================================================================
var accountAssister = {
	// init for account preview
	initPreview: function() {
		if (!window['account']) {
			window['account'] = {};
			account['buttons'] = $('passport');
			account['preview'] = $('account-preview');
		}
		account.buttons.onmousemove = this.showPreview;
	},
	// show account preview when mouse move onto the buttons
	showPreview: function() {
		if (!window['account']) return;
		if (account.preview.style['display'] == 'block') return;
		var dimensions = Lite.UTIL.dimensions(account.buttons);
		account.preview.style['right'] =
			document.body.offsetWidth -
			dimensions.x - (account.buttons.offsetWidth) + 'px';
		account.preview.style['top'] =
			dimensions.y - (-account.buttons.offsetHeight - 1) + 'px';
		account.preview.style['display'] = 'block';
		avatarDisplayAssister.adjustDisplay($('my-avatar-preview'));
		document.body.onmousemove = accountAssister.hidePreview;
	},
	// hide account preview when mouse move out of the buttons
	hidePreview: function(evt) {
		if (!window['account']) return;
		evt = evt || window.event;
		var target = evt.target || evt.srcElement;
		while (target) {
			if (target == account.buttons) return;
			target = target.parentNode;
		}
		account.preview.style['display'] = 'none';
		document.body.onmousemove = $null;
	}
};


//============================================================================
// ** Rank Page API
//============================================================================
var rankAssister = {
	// init for rank table
	initPreview: function() {
		if (!window['rank']) {
			for ( var i = 1, item; item = $('top10-button-'+i); i++) {
				item.onmouseover = rankAssister.showPreview;
				item.onmouseout = rankAssister.hidePreview;
				item.detailId = 'top10-preview-' + i;
				item.avatarId = 'top10-avatar-' + i;
			}
			window['rank'] = true;
		}
	},
	// show account preview when mouse move onto the nickname table cell
	showPreview: function() {
		var item = $(this.detailId);
		if (item.style['display'] == 'block') return;
		item.style['display'] = 'block';
		var dimensions = Lite.UTIL.dimensions(this);
		item.style['top'] = dimensions.y + 'px';
		item.style['right'] = document.documentElement.clientWidth -
			dimensions.x - this.offsetWidth - item.offsetWidth + 'px';
		var avatar = $(this.avatarId);
		if (avatar)
			avatarDisplayAssister.adjustDisplay(avatar);
	},
	// hide account preview when mouse move out of the certain nickname table cell
	hidePreview: function() {
		var item = $(this.detailId);
		item.style['display'] = 'none';
	}
};


//============================================================================
// ** Rank Page API
//============================================================================
var avatarDisplayAssister = {
	// adjust avatar size
	adjustDisplay: function(img) {
		img.removeAttribute('width');
		img.removeAttribute('height');
		img.style.marginTop = img.style.marginLeft = '';
		var width = img.offsetWidth;
		var height = img.offsetHeight;
		var isTall = height > width;
		var size = (isTall ? height : width);
		if (size > 96) (isTall ? (img.height = 96) : (img.width = 96));
		img.style.marginTop = ((96 - img.offsetHeight) / 2 + 'px');
		img.style.marginLeft = ((96 - img.offsetWidth) / 2 + 'px');
		img.onload = null;
	}
};

// debug only
var debug = [];
