/**
 * AJAX执行顺序:
 * $().ajaxStart
 * beforeSend
 * $().ajaxSend
 * success | error
 * $().ajaxSuccess | $().ajaxError
 * $().ajaxStop
 * complete
 */

jQuery.jcan = {
	version : 0.2,
	extVersion : 5
};

$.browser.ie6 = $.browser.msie && parseInt($.browser.version) < 7;
$.loadingPlugins = 0;

$.regexp = {
	email: /^[0-9a-z\-\_\.]{1,40}@([0-9a-z\-]{1,20}\.){1,4}[a-z]{2,5}$/i,
	image: /\.(gif|p?jpe?g|png|bmp)$/i
};


/**
 * 删除字符串前后所有全角与半角空格
 * @example str.trim()
 */
String.prototype.trim = function()
{
	return this.replace(/(^[\u3000\s]*)|([\u3000\s]*$)/g, "");
};

/**
 * 删除字符串前面所有全角与半角空格
 * @example str.ltrim()
 */
String.prototype.ltrim = function()
{
	return this.replace(/^[\u3000\s]*/g, "");
};

/**
 * 删除字符串后面部分所有全角与半角空格
 * @example str.rtrim()
 */
String.prototype.rtrim = function()
{
	return this.replace(/[\u3000\s]*$/g, "");
};

/**
 * 返回字符串的真实长度(一个全角字符的长度为2)
 * @example str.width()
 */
String.prototype.width = function()
{
	return this.replace(/[^\x00-\xff]/g, "**").length;
};

/**
 * 取得字符串左边指定宽度长的子串
 * @example '我是中国人'.left(5)
 */
String.prototype.left = function(num) {
	var str = this.replace(/[^\x00-\xff]/g, "%^");
	num = str.substr(0, num).replace(/\%\^/g, "^").replace(/\%$/, "").length;
	return this.substr(0, num);
};

/**
 * @exasmple
 * 	url = 'http://ouk.cn?id=3
 *	url.concatQuery('_ajax=1&amp;r=' + Math.random());
 */
String.prototype.concatQuery = function(q) {
	return this + (this.indexOf('?') == -1 ? '?' : '&') + q;
};

String.prototype.repeat = function(num){
	return new Array(num+1).join(this);
};

/**
 * 剔除掉数组中相同元素
 */
Array.prototype.unique = function(){
	var a={},b=[];
	for(var i=0;i<this.length;i++)
		a[this[i]]=this[i];
	for(var c in a)
		b[b.length]=a[c];
	return b;
};

/**
 * 重写setTimeout,使其可多参数传递
 */
var _st = window.setTimeout;
window.setTimeout = function(fRef, mDelay) {
	if(typeof fRef == 'function'){
		var argu = Array.prototype.slice.call(arguments,2);
		var f = (function(){ fRef.apply(null, argu); });
		return _st(f, mDelay);
	}
	return _st(fRef,mDelay);
};


//常用扩展函数
$.extend({

	/**
	 * 返回JS文件(包含路径)
	 */
	getJsFile : function(js)
	{
		//js不带路径信息
		if (!/\//.test(js)) {
			var src = $('script[@src]').attr('src');
			js = src.replace(/(\/?)([^\/]+)$/, '$1') + js + '?v=' + $.jcan.extVersion;
		}

		return js;
	},

	/**
	 * 动态加载JS
	 * @example
	 *	$.includeJs('jquery.menu.js')
	 *	$.includeJs(['jquery.menu.js', 'jquery.ajaxupload.js'])
	 *	$.includeJs('jquery.ajaxAuto.js', function(){
	 *		$('form').ajaxAuto();
	 *	});
	 *	$.includeJs(['jquery.ajaxAuto.js', 'jquery.ajaxUpload.js'], function(){ ... });
	 */
	includeJs : function(jsArr, cb)
	{
		if (typeof jsArr == 'string') {
			jsArr = [jsArr];
		}
		var jsLen = jsArr.length;

		//异步请求
		if (cb) {
			var countVar = '$._' + $.uid();
			eval(countVar + '=' + jsLen);

			for (var i=0; i<jsLen; i++) {
				var js = jsArr[i];
				js = $.getJsFile(js);
				$.ajax({
					url: js,
					cache: true,
					dataType: 'script',
					global: false,
					success: function(){
						eval(countVar + '--');
					}
				});
			}

			var run = function(cb) {
				if (eval(countVar) == 0) {
					cb.call();
					return;
				}
				setTimeout(run, 40, cb);
			};
			run(cb);
			return;
		}

		//同步请求
		for (var i=0; i<jsLen; i++) {
			var js = jsArr[i];
			js = $.getJsFile(js);
			try {
				var text = $.ajax({
					url : js,
					global : false,
					async : false,
					cache : true
				}).responseText;
			}
			catch(e) {
				var text = false;
			}

			if (!text || /^</.test(text)) {
				return false;
			}

			var script = document.createElement('script');
			script.type = 'text/javascript';
			script.text = text;
//			script.defer = true;
			$('head script:last').after(script);
//			var head = document.getElementsByTagName('head')[0];
//			head.appendChild(script); //IE下会出现: 非法操作,终止
		}
	},

	/**
	 * @example 见注释
	 */
	requirePlugin : function(fn, jsfile, cb)
	{
		/**
		 * 请求函数fn,如果不存在则从jsfile里异步获取
		 * $.requirePlugin($.ajaxAuto, 'jquery.ajaxAuto.js', function(){ $('form').ajaxAuto(); });
		 */
		if (cb) {
			if (fn) {
				cb.call();
			} else {
				$.includeJs(jsfile, cb);
			}
			return;
		}

		/**
		 * $.requirePlugin(['jquery.ajaxAuto.js', 'jquery.fixIe.js', 'jquery.border.js']);
		 * if (!$.loadingPlugins) { ... }
		 */
		var plugins = fn;
		if (typeof plugins == 'string') {
			plugins = [plugins];
		}

		var len = plugins.length;
		$.loadingPlugins += len;

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

			$.includeJs(plugins[i], function(){
				$.loadingPlugins--;
			});
		}
	},

	/**
	 * $.run(function(){
	 *	 alert('All plugins had be loaded');
	 * });
	 */
	run : function(cb) {
		if (!$.loadingPlugins) {
			cb.call();
			return;
		}
		setTimeout($.run, 50, cb);
	},

	/**
	 * 相当于:
	 * $(function(){
	 *	$.run(function(){
	 *		alert('Page and all plugins had be loaded');
	 *	});
	 * });
	 */
	loadRun : function(cb) {
		$(function(){
			$.run(cb);
		});
	},

	/**
	 * 产生unique id
	 * 一个可能值: ad87dk1cghc (11位)
	 */
	uid : function()
	{
		return (new Date().getTime()*10000+Math.random(1)*10000).toString(32);
	},

	/////// 以上为扩展的核心函数 ///////////////////////////////

	/**
	 * 加入书签(收藏夹)
	 * @example $('#addMark').click( function(){$.bookmark('http://ouk.cn', 'ouk');} );
	 */
	bookmark : function(url, title)
	{
		if (window.sidebar) window.sidebar.addPanel(title, url, "");
		else if (window.opera && window.print) {
			var mbm = document.createElement('a');
			mbm.setAttribute('rel','sidebar');
			mbm.setAttribute('href',url);
			mbm.setAttribute('title',title);
			mbm.click();
		}
		else if (document.all) window.external.AddFavorite(url, title);
	},

	/**
	 * 把4343214.4321以4,343,214.4321的形式显示
	 * @param number num
	 * @param int bit [optional]
	 * @param string chr [optional]
	 * @example formatNumber(100000, 4, ',')
	 */
	formatNumber: function(num, bit, chr) {
		num = num.toString();
		if (bit == null) bit = 3;
		if (chr == null) chr = ",";
		var re = new RegExp("(\\d+)(\\d{" + bit + "})");
		while (num.match(re)) {
			num = num.replace(re, "$1" + chr + "$2");
		}
		return num;
	},

	/**
	 * 与parseInt(str)的不同之处在于: 当str不能被解释成整数时, parseInt返回NaN, 而此处返回0
	 */
	intval: function(str) {
		var num = parseInt(str);
		if (isNaN(num)) num = 0;
		return num;
	},

	/**
	 * 转向某个URL, 这样做的好处是:服务器端可以得到HTTP_REFERER
	 * @param string url 要转身的URL
	 * @param string verify 是否加入_POST['__confirm']
	 */
	redirect: function(url, verify) {
		if (verify) {
			$("<form action=\"" + url + "\" method=\"post\" style=\"display:none\"><input type=\"hidden\" name=\"__confirm\" value=\"1\"/></form>").appendTo('body').submit().remove();
		} else {
			$("<form action=\"" + url + "\" method=\"get\" style=\"display:none\"></form>").appendTo('body').submit().remove();
		}
	},

	_ajaxLight: function(options, successFn, failureFn, errorFn)
	{
		var _this = this;

		//options
		if (!options || $.isFunction(options)) {
			errorFn = failureFn;
			failureFn = successFn;
			successFn = options;
		}
		if (typeof options == 'string') {
			options = {url: options};
		}

		//AJAX settings
		var s = {
			url: this.href,
			global: false,
			type: 'post',
			data: '__confirm=1',
			cache: false
		};
		$.extend(s, options || {});

		//无参数failureFn(用自定义函数处理)
		if (failureFn === undefined) {
			s.success = successFn;
		}
		//有参数failureFn
		else {
			s.success = function(data) {
				switch (data) {
					case '1':
						successFn && successFn.call(_this, data);
						break;
					case '0':
						failureFn && failureFn.call(_this, data);
						break;
					case '-1':
					default:
						errorFn && errorFn.call(_this, data);
						break;
				}
			};
		}

		$.ajax(s);
		return false;
	},

	check: function(e, expr, msg, focus) {

		if (typeof e != 'object') {
			focus = msg;
			msg = expr;
			expr = e;
			e = null;
		}
		if (expr) {
			if (msg) {
				if ($.isFunction(msg)) {
					msg.call();
				} else {
					$.tip(msg);
				}
			}

			if (focus) {
				if ($.isFunction(focus)) {
					focus.call();
				} else {
					focus.focus();
				}
			}
			e && e.preventDefault();
		}
		return !expr;
	},

	dump: function(variable, options, count) {
		var s = {
			separator: "\t",
			iteration: 10
		};
		$.extend(s, options || {});

		if (count == undefined) count = 0;

		if (typeof variable == 'object') {
			var indent = s.separator.repeat(count);

			for (var i in variable) {
				console.log(indent, i, s.separator, variable[i]);
				if (typeof variable[i] == "object" && count+1 < s.iteration) {
					arguments.callee(variable[i], s, count+1);
				}
			}
		} else {
			console.log(variable);
		}
	}
});

//常用扩展函数
$.fn.extend({
	/**
	 * $('#btn').hoverClass('btnHover');
	 */
	hoverClass : function(c)
	{
		this.each(function(){
			$(this).hover(
				function() { $(this).addClass(c); },
				function() { $(this).removeClass(c); }
			);
		});
		return this;
	},

	/**
	 * $('div').cutInner()
	 * before: <div><p><span>aa</span><span>cc</span>ddd</p></div>
	 * after: <div><span>aa</span><span>cc</span></div>
	 */
	cutInner : function()
	{
		return this.each(function(){
			while (this.firstChild.firstChild) {
				this.appendChild(this.firstChild.firstChild);
			}
			this.removeChild(this.firstChild);
		});
	},

	/**
	 * 遍历父辈元素, 直至找到满足表达式的父辈并返回 (如果没有返回false)
	 *
	 * before: <div id="a"><div id="b"><div id="c"><div id="d"><p><span>aa</span></p></div></div></div></div>
	 *
	 * $('span').elder('div#c')
	 * after: <div id="c"><div id="d"><p><span>aa</span></p></div></div>
	 *
	 * $('span').elder(':hidden')
	 * after: false
	 */
	elder : function(exp)
	{
		var dom = this[0];
		while (dom.parentNode) {
			dom = dom.parentNode;
			o = $(dom);
			if (o.is(exp)) {
				return o;
			}
		}

		return false;
	},

	/**
	 * 与$.fn.val(str)的区别在于: $.fn.intval最终会转换为整型去赋值或者返回
	 */
	intval : function(str)
	{
		if (str != undefined) {
			this.val($.intval(str));
			return this;
		}
		return $.intval(this.val());
	},

	/**
	 * $('input.tip').toggleVal('lightColor');
	 */
	toggleVal : function(nullClass, submitChk, title)
	{
		if (submitChk == undefined) submitChk = true;

		this.each(function(){
			if (title) {
				var _title = title;
			} else {
				var _title = this.title;
				$(this).removeAttr('title');
			}

			if (this.defaultValue == '') {
				this.value = _title;
				nullClass && $(this).addClass(nullClass);
			}

			if (submitChk) {
				var _this = this;
				$(this).parents('form').submit(function(){
					if (_this.value == _title) {
						_this.focus();
					}
				});
			}

			$(this).focus(function(){
				if (this.value == _title) {
					this.value = '';
					nullClass && $(this).removeClass(nullClass);
				}
			}).blur(function(){
				if (this.value == '') {
					this.value = _title;
					nullClass && $(this).addClass(nullClass);
				}
			});
		});
	},

	/**
	 * 生成安全E-mail, 不容易被抓取
	 * @example
	 *	$('#email').mail('jcan', 'gmail', 'com', 'concat me', 'subject=Hello&amp;body=good')
	 *	$('#email').mail('jcan', 'gmail', 'com')
	 */
	mail : function(user, domain, ext, text, q) {
		var link = user + '&#64;' + domain + '&#46;' + ext;
		if (!text) text = link;
		if (q) link += '?' + q;
		if (this.hasClass('nolink')) {
			return this.html(text);
		}
		var mail = '<a href="mai' + 'lto:' + link + '">' + text + '<\/a>';
		return this.html(mail);
	},

	hideFocus : function() {
		return this.each(function(){
			if ($.browser.msie) {
				this.hidefocus = true;
			} else {
				this.style.outline = 0;
			}
		});
	},

	clearFileValue: function() {
		var This = this.clone(true).val('').hide();
		this.after(This).fadeOut('fast', function(){
			$(this).next().fadeIn().end().remove();
		});
		return This;
	},

	ajaxLight: function(options, successFn, failureFn, errorFn)
	{
		return this.each(function(){
			$(this).click(function(){
				$._ajaxLight.call(this, options, successFn, failureFn, errorFn);
				return false;
			});
		});
	},

	/**
	 * 参数可以为函数
	 * example
	 * $('a.delete').click(function(){
	 * 	return this.href;
	 * });
	 */
	confirmLink: function(msg, successFn, failureFn, errorFn) {
		if (failureFn && !errorFn) {
			errorFn = failureFn;
			failureFn = null;
		}

		return this.each(function(){
			$(this).click(function(){
				var _this = this, confirmFn;

				//msg
				if ($.isFunction(msg)) {
					msg = msg.call(this);
				}

				//只有一个msg参数(不用ajax处理)
				if (successFn === undefined) {
					confirmFn = function(){
						$.redirect(_this.href, true);
					};
				}

				//有两个或三个参数(用ajax处理)
				else {
					//ajax request
					confirmFn = function(){
						$._ajaxLight.call(_this, successFn, failureFn, errorFn);
					};
				}

				$.confirm(msg, confirmFn);
				return false;
			});
		});
	}
});





/**
 * @example
 * $('.banner').flash({width:255,height:10})
 * $('.banner').flash('img/banner.swf', {width:255,height:10})
 */
$.fn.flash = function(f, vars) {
	if (typeof f == 'object') {
		vars = f;
	}
	return this.each(function(){
		if (typeof f != 'string') {
			f = $.trim(this.innerHTML);
		}
		var fstr = '<embed src="' + f + '" width="' + vars.width + '" height="' + vars.height + '"><\/embed>';
		this.innerHTML = fstr;
	});
};

$.fn.fastSerialize = function() {
    var a = [];
    $('input,textarea,select,button', this).each(function() {
        var n = this.name;
        var t = this.type;
        if ( !n || this.disabled || t == 'reset' ||
            (t == 'checkbox' || t == 'radio') && !this.checked ||
            (t == 'submit' || t == 'image' || t == 'button') && this.form.clicked != this ||
            this.tagName.toLowerCase() == 'select' && this.selectedIndex == -1)
            return;
        if (t == 'image' && this.form.clicked_x)
            return a.push(
                {name: n+'_x', value: this.form.clicked_x},
                {name: n+'_y', value: this.form.clicked_y}
            );
        if (t == 'select-multiple') {
            $('option:selected', this).each( function() {
                a.push({name: n, value: this.value});
            });
            return;
        }
        a.push({name: n, value: this.value});
    });
    return a;
};

//require plugins
$.includeJs('jquery.border.js');
$.requirePlugin(['jquery.overlay.js', 'jquery.fixIe.js', 'jquery.ajaxAuto.js']);
