/**
 * Created by QQ互联.
 * User: jinjingcao
 * Date: 11-8-3
 * Time: 下午4:56
 * To change this template use File | Settings | File Templates.
 */

var QC = function() {
//	var windowId = +new Date();
	var EMPTY_FUN = function() {};
	var $ = function(_){return typeof(_)=="string" ? document.getElementById(_) : _};

	var ieVer = window.ActiveXObject && navigator.userAgent.match(/MSIE\s+(\d+)/)[1];

	var resDomain = "qzonestyle.gtimg.cn",
		mainDomain = "qzs.qq.com";

	var $Toolkit = function() {
		
		var str2dom = function(_str) {
			var _ret = [],
				_cot = arguments.callee._temp = arguments.callee._temp || document.createElement("div");;

			_cot.innerHTML = _str;

			while(_cot.firstChild) {
				_ret.push(_cot.removeChild(_cot.firstChild));
			}

			return _ret.length > 1 ? function(){
				var tmp = document.createDocumentFragment();
				for(var i=0;i<_ret.length;i++) {
					tmp.appendChild(_ret[i]);
				}
				return tmp;
			}() : _ret[0];
		};

		var format = function(str, obj) {
			return str.replace(arguments.callee._reg, function(_i, _1){
				return obj[_1]!==null?obj[_1]:_1;
			});
		}
		format._reg = /\{(\w+)\}/g;

		return {
			str2dom : str2dom,
			format : format,

			/**
			 * 类继承
			 * @param _Cld
			 * @param _Prt
			 */
			extend : function(_Cld, _Prt) {
				var fn = EMPTY_FUN;
				fn.prototype = _Prt.prototype;

				_Cld.prototype = new fn();//_Prt();
				_Cld.constructor = _Cld;
//				_Cld.prototype.constructor = _Cld;
				return _Cld;
			}
		}
	}();

	var $JSON = function() {

		var
			escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
			meta = {    // table of character substitutions
				'\b': '\\b',
				'\t': '\\t',
				'\n': '\\n',
				'\f': '\\f',
				'\r': '\\r',
				'"' : '\\"',
				'\\': '\\\\'
			};

		function quote(string) {
		// If the string contains no control characters, no quote characters, and no
		// backslash characters, then we can safely slap some quotes around it.
		// Otherwise we must also replace the offending characters with safe escape
		// sequences.

			escapable.lastIndex = 0;
			return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
				var c = meta[a];
				return typeof c === 'string' ? c :
					'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
			}) + '"' : '"' + string + '"';
		}


		function stringify(obj) {//只用于简单object对象
			var ret = [], v="";
			for(var i in obj) {
				v = obj[i]||"";
//				if(Object.prototype.hasOwnProperty.call(v, i)){
//debugger
					switch(typeof v) {
						case 'string':
							v=quote(v);
							break;
						case 'object':
							v=stringify(v);
							break;
						case 'function':
							continue;
					}
					
//					ret.push($Toolkit.format('"{key}":"{val}"', {
//						key:i,
//						val :v
//					}));

					ret.push('"'+i+'":' + v);

//				}
			}

			return '{'+ret+'}';
		}

		return {
			stringify : function() {
				return window.JSON&&JSON.stringify ? JSON.stringify : stringify
			}(),
			parse : function(str) {
				str=str||"{}";
				var ret={};
				try {
					ret = (new Function("return (" + str + ")"))()
				}catch(e){
					$Console.error("JSON.parse => parse数据格式错误:" + str);
				}
				return ret;
			}
		}
	}();

	var $XML = function() {
		 // check for XPath implementation
		if (document.implementation.hasFeature("XPath", "3.0")) {
			// prototying the XMLDocument
			XMLDocument.prototype.selectNodes = function(cXPathString, xNode) {
				if (!xNode) {
					xNode = this;
				}
				var oNSResolver = this.createNSResolver(this.documentElement)
				var aItems = this.evaluate(cXPathString, xNode, oNSResolver,
						XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)
				var aResult = [];
				for (var i = 0; i < aItems.snapshotLength; i++) {
					aResult[i] = aItems.snapshotItem(i);
				}
				return aResult;
			}

			// prototying the Element
			Element.prototype.selectNodes = function(cXPathString) {
				if (this.ownerDocument.selectNodes) {
					return this.ownerDocument.selectNodes(cXPathString, this);
				}
				else {
					throw "For XML Elements Only";
				}
			}
		}

		var loadXML = function(xmlString) {
			var XMLDoc = ieVer ? new ActiveXObject("Microsoft.XMLDOM") : document.implementation.createDocument("text/xml", "", null);
			
			if (ieVer) {
				if (XMLDoc.loadXML(xmlString)) {
					return XMLDoc;
				}else {
					return null;
				}
			} else {
				try {
					var childNodes = XMLDoc.childNodes;
					for (var i = childNodes.length - 1; i >= 0; i--)
						XMLDoc.removeChild(childNodes[i]);

					var dp = new DOMParser();
					var newDOM = dp.parseFromString(xmlString, "text/xml");
					var newElt = XMLDoc.importNode(newDOM.documentElement, true);
					XMLDoc.appendChild(newElt);
					return XMLDoc;
				}
				catch (ex) {
					return null;
				}
			}

		}

		return {
			stringify:function(doc){
				return doc.xml || new XMLSerializer().serializeToString(doc);
			},
			parse:loadXML
		}
	}();

	var $Object = function(){
		return {
			extend : function() {
				var args = arguments,
					len = arguments.length,
					deep = false,
					i = 1,
					target = args[0],
					opts,
					src,
					clone,
					copy;

				if ( typeof target === "boolean" ) {
					deep = target;
					target = arguments[1] || {};
					i = 2;
				}

				if ( typeof target !== "object" && typeof target !== "function" ) {
					target = {};
				}

				if ( len === i ) {
					target = {};
					--i;
				}

				for ( ; i < len; i++ ) {
					if ( (opts = arguments[ i ]) != null ) {
						for (var name in opts ) {
							src = target[ name ];
							copy = opts[ name ];

							if ( target === copy ) {
								continue;
							}

							if ( deep && copy && typeof copy === "object" && !copy.nodeType ) {

								if ( src ) {
									clone = src;
								} else if ( copy instanceof Array ) {
									clone = [];
								} else if ( typeof copy === 'object' ) {
									clone = {};
								} else {
									clone = copy;
								}

								target[ name ] = object.extend( deep, clone, copy );

							} else if ( copy !== undefined ) {
								target[ name ] = copy;
							}
						}
					}
				}

				return target;
			}
		}
	}();

	var $QueryString = function() {
		var re=/"/g;//JSON.parse时候，双引号值会引发异常
		var tool = {
			/**
			 * http参数表对象变为HTTP协议数据串，如：param1=123&amp;param2=456
			 * @param {object} o 用来表示参数列表的hashTable
			 * @returns {string} 结果串
			 * @example QZFL.util.genHttpParamString({"param1":123, "param2":456});
			 */
			genHttpParamString : function(o) {
				return this.commonDictionaryJoin(o, null, null, null, window.encodeURIComponent);
			},

			/**
			 * 将一个http参数序列字符串变为表映射对象
			 * @param {string} s 源字符串
			 * @returns {object} 结果
			 * @example QZFL.util.splitHttpParamString("param1=123&param2=456");
			 */
			splitHttpParamString : function(s) {
				return this.commonDictionarySplit(s, null, null, null, window.decodeURIComponent);
			},

			/**
			 * 将一个字典型序列字符串变为映射表对象
			 * @param {string} [s=''] 源字符串
			 * @param {string} [esp='&'] 项分隔符
			 * @param {string} [vq=''] 值封套
			 * @param {string} [eq='='] 等号字符
			 * @returns {object} 结果对象
			 * @example
	QZFL.util.commonDictionarySplit(
		'form-data; name="file_upload"; file_name="c:\\data\\data.ini"; ',
		'; ',
		'"',
		'='
	);
			 */
			commonDictionarySplit : function(s, esp, vq, eq, valueHandler) {
				var res = {},
					l,
					ks,
					vs,
					t,
					vv;

				if(!s || typeof(s) != "string"){
					return res;
				}
				if (typeof(esp) != 'string') {
					esp = "&";
				}
				if (typeof(vq) != 'string') {
					vq = "";
				}
				if (typeof(eq) != 'string') {
					eq = "=";
				}

				l = s.split(esp); //a="1=2"tt"&b="2"s=t" -> a="1=2"tt"     b="2"s=t"

				if(l && l.length){
					for(var i = 0, len = l.length; i < len; ++i){
						ks = l[i].split(eq); //a="1=2"tt" -> a    "1    2"tt"
						if(ks.length > 1){
							t = ks.slice(1).join(eq); //"1=2"tt"
							vs = t.split(vq);
							vv =   vs.slice(vq.length, vs.length - vq.length).join(vq);
							res[ks[0]] = (typeof valueHandler == 'function' ? valueHandler(vv) : vv);
						}else{
							ks[0] && (res[ks[0]] = true); //没有值的时候直接就用true作为值
						}
					}
				}

				return res;
			},

			/**
			 * 将一个字典型映射表对象变为序列字符串
			 * @param {object} [o={}] 源映射对象
			 * @param {string} [esp='&'] 项分隔符
			 * @param {string} [vq=''] 值封套
			 * @param {string} [eq='='] 等号字符
			 * @param {function} [valueHandler=QZFL.emptyFn] 处理值的方法引用
			 * @returns {string} 结果串
			 * @example
	QZFL.util.commonDictionaryJoin(
		{
			'form-data' : true,
			'name' : 'file_upload',
			'file_name' : 'c:\\data\\data.ini'
		}
		'; ',
		'"',
		'='
	); //form-data="true"; name="file_upload"; file_name="c:\\data\\data.ini"
			 */
			commonDictionaryJoin : function(o, esp, vq, eq, valueHandler) {
				var res = [],
					t, ok;

				if(!o || typeof(o) != "object"){
					return '';
				}
				if(typeof(o) == "string"){
					return o;
				}
				if (typeof(esp) != 'string') {
					esp = "&";
				}
				if (typeof(vq) != 'string') {
					vq = "";
				}
				if (typeof(eq) != 'string') {
					eq = "=";
				}

				for(var k in o){//debugger
					ok=(o[k]+"").replace(re, "\\\"");
					res.push(k + eq + vq + (typeof valueHandler == 'function' ? valueHandler(ok) : ok) + vq);
				}

				return res.join(esp);
			}

		}


		return {
			stringify : function(obj) {
				return tool.genHttpParamString(obj);
			},
			parse : function(str) {
				return tool.splitHttpParamString(str);
			}
		}
	}();

	var $String = function() {
		var res= [
			/&/g,
			/</g,
			/>/g,
			/\x27/g,
			/\x22/g
		], rep = [
			'&amp;',
			'&lt;',
			'&gt;',
			'&#039;',
			'&quot;'
		];

		return {
			escHTML : function(str) {
				var ret = str;
				for(var i = 0, l=res.length; i<l; i++) {
					ret = ret.replace(res[i], rep[i]);
				}

				return ret;
			},
			format : $Toolkit.format
		}

	}();

	var $Cookie = function() {
		var domainPrefix = document.domain||"";
		return{
			/**
			 * 设置一个cookie,还有一点需要注意的，在qq.com下是无法获取qzone.qq.com的cookie，反正qzone.qq.com下能获取到qq.com的所有cookie.
			 * 简单得说，子域可以获取根域下的cookie, 但是根域无法获取子域下的cookie.
			 * @param {String} name cookie名称
			 * @param {String} value cookie值
			 * @param {String} domain 所在域名
			 * @param {String} path 所在路径
			 * @param {Number} hour 存活时间，单位:小时
			 * @return {Boolean} 是否成功
			 * @example
			 *  QZFL.cookie.set('value1',QZFL.dom.get('t1').value,"qzone.qq.com","/v5",24); //设置cookie
			 */
			set : function(name, value, domain, path, hour) {
				if (hour) {
					var expire = new Date();
					expire.setTime(expire.getTime() + 3600000 * hour);
				}
				document.cookie = name + "=" + value + "; " + (hour ? ("expires=" + expire.toGMTString() + "; ") : "") + (path ? ("path=" + path + "; ") : "path=/; ") + (domain ? ("domain=" + domain + ";") : ("domain=" + domainPrefix + ";"));
				return true;
			},

			/**
			 * 获取指定名称的cookie值
			 *
			 * @param {String} name cookie名称
			 * @return {String} 获取到的cookie值
			 * @example
			 *		 QZFL.cookie.get('value1'); //获取cookie
			 */
			get : function(name) {
				//ryan
				//var s = ' ' + document.cookie + ';', pos;
				//return (pos = s.indexOf(' ' + name + '=')) > -1 ? s.slice(pos += name.length + 2, s.indexOf(';', pos)) : '';

				var r = new RegExp("(?:^|;+|\\s+)" + name + "=([^;]*)"), m = document.cookie.match(r);
				return (!m ? "" : m[1]);
			},

			/**
			 * 删除指定cookie,复写为过期
			 *
			 * @param {String} name cookie名称
			 * @param {String} domain 所在域
			 * @param {String} path 所在路径
			 * @example
			 *		 QZFL.cookie.del('value1'); //删除cookie
			 */
			del : function(name, domain, path) {
				document.cookie = name + "=; expires=Mon, 26 Jul 1997 05:00:00 GMT; " + (path ? ("path=" + path + "; ") : "path=/; ") + (domain ? ("domain=" + domain + ";") : ("domain=" + domainPrefix + ";"));
			}
		}
	}();

	var $Console = function() {
		var _QC_CONSOLE_DEBUG_LEVEL = 2;
		var cons_prefix = ' :: [QQConnect] > ';
		var trace = function(funName) {
			return function(args) {
				window.console && console[funName] && getDebugLevel()>=LEVELS[funName] && console[funName](cons_prefix + args);
			}
		};

		var LEVELS = {
			log : 3,
			info : 2,
			warn : 1,
			error : 0
		};

		var getDebugLevel = function() {
			return ~~(_QC_CONSOLE_DEBUG_LEVEL||LEVELS.info);
		};

		return {
			log : trace("log"),
			info : trace("info"),
			warn : trace("warn"),
			error : trace("error"),
			setLevel : function(lvNm) {
				return _QC_CONSOLE_DEBUG_LEVEL = LEVELS[lvNm]||_QC_CONSOLE_DEBUG_LEVEL;
			}
		}
	}();

//	var url,loaded=false;
//	function transOpen(){
//		url=arguments[0];
//		loaded && transOpen.iframe.contentWindow.postMessage(url, "*");
////		alert(arguments)
////		transOpen.iframe.src="https://graph.qq.com/jsdkproxy/success.html#"+arguments[0];
//	}
//	transOpen.iframe = document.createElement("iframe");
//	transOpen.iframe.src = "https://graph.qq.com/jsdkproxy/success.html#proxy";
//	transOpen.iframe.onload = function() {
//		loaded=true;
//		url && transOpen.iframe.contentWindow.postMessage(url, "*");
//		url=null;
////		alert("T_ONLOAD");
//	};
//	document.body.appendChild(transOpen.iframe);

	var Login = function() {
		var //g_clientId = 0,
			access_token,
			dt_cache;	//getMe 返回的数据
		
		var BUTTON_STYLE = {
			A_XL : {styleId:5, size:'230*48'},
			A_L : {styleId:4, size:'170*32'},
			A_M : {styleId:3, size:'120*24'},
			A_S : {styleId:2, size:'105*16'},

			B_M : {styleId:7, size:'63*24'},
			B_S : {styleId:6, size:'50*16'},

			C_S : {styleId:1, size:'16*16'}
		};
		
		/**
		 * 创建QQ登录按钮
		 * @param opts
		 * 	#opts 参数:
		 * 		btnId  :
		 * 		size :
		 * 		key :
		 *
		 */
		function _insertButton(opts) {//debugger
			if(opts.clientId) {
				QC.init({appId:opts.clientId});
			}
			var appid = QC.getAppId();
			if(appid<0) {
				QC.getAppId(arguments);
				return;
			}

			opts.size=opts['size']||'B_M';
			var btn = $(opts['btnId']),
				sizeObj = BUTTON_STYLE[opts['size']]||BUTTON_STYLE['B_M'],
				size = sizeObj['styleId'],
//				g_clientId = opts['clientId'] || opts['client_id']/*, clientId = g_clientId*/,
//				scope = opts['scope']||'',
//				redirectURI = opts['redirectURI'],
				fullWindow = opts['fullWindow']||false,
//				display = opts['display']||'',

				btnMode = opts['btnMode']||'standard';

//			var paras = [
//				'client_id='+clientId,
//				'response_type=token'
//			],url='https://graph.qq.com/oauth2.0/authorize';
//
//			if(scope) {
//				paras.push('scope='+scope);
//			}
//			if(redirectURI) {
//				if(redirectURI.indexOf('?')>0) {//防止被重复编码
//					redirectURI = encodeURIComponent(redirectURI);
//				}
//				paras.push('redirect_uri='+redirectURI);
//			}
//			if(display=='mobile') {
//				paras.push('display='+display);
//			}
//
//			url = url +"?"+ paras.join("&");
			var url = arguments.callee._getPopupUrl(opts);
			//alert(url)
			var parasObj = {
				size : size,
				fullWindow : fullWindow,
				url : url
			};


			if(opts && opts['btnId']) {
				if(btn) {//debugger
					btn.innerHTML = arguments.callee.getBtnHtml(parasObj, btnMode, opts);
					var onclick = btn.firstChild.onclick;
					(btn.firstChild.onclick=function(_a){//over write
						var crtPop,  _close=function(){
							crtPop&&crtPop.close();
						};

						window.addEventListener
								? window.addEventListener("unload", _close, false)
								: window.attachEvent("onunload", _close);
						
//						debugger
						return function(){
							if(crtPop){crtPop.close();}
							crtPop = _a();
//							transOpen.apply(null, _a);
						}
					}(onclick));
//					btn.firstChild.onclick=null;
				}else{
					throw new Error('未找到插入节点:')
				}
			}
		}
		_insertButton.TEMPLATE = [
			'<a href="javascript:;" onclick="{onclick}"><img src="{src}" alt="{alt}" border="0"/></a>'
		].join('');

		_insertButton.getBtnHtml = function(parasOpts, btnMode, opts) {
			return arguments.callee.MODE[btnMode] && arguments.callee.MODE[btnMode](parasOpts, opts);//baseStr.replace("$1", arguments.callee[btnMode]||"<?$1?>");
		};
		_insertButton.getBtnHtml.MODE = {
			"standard":function(parasObj){
				var windowId = ~~$Cookie.get("__qc_wId") + 10000;
				var baseStr = $Toolkit.format(_insertButton.TEMPLATE, {
					src : 'http://'+resDomain+'/qzone/vas/opensns/res/img/Connect_logo_'+parasObj.size+'.png',
					onclick : parasObj.fullWindow ? 'return window.open(\''+parasObj.url+'\', \'oauth2Login_'+windowId+'\');' : 'return window.open(\''+parasObj.url+'\', \'oauth2Login_'+windowId+'\' ,\'height=525,width=585, toolbar=no, menubar=no, scrollbars=no, status=no, location=yes, resizable=yes\')',
					alt : 'QQ登录'
				});

				return baseStr;
			},
			"showUserAfterLogin" : function(parasObj, opts){
				var baseStr = $JSON.stringify(opts),//this.standard(parasObj),
					sizeObj = BUTTON_STYLE[opts['size']] || BUTTON_STYLE['B_M'],
					size = sizeObj['size'].split("*"),
//					outerStr = '<iframe frameBorder="0" src="http://'+mainDomain+'/qzone/openapi/frames/login_button.html#ctt='+encodeURIComponent(baseStr)+'"></iframe>';
					outerStr = '<iframe frameBorder="0" scrolling="no" src="http://'+mainDomain+'/qzone/openapi/frames/login_button.html#para='+encodeURIComponent(baseStr)+'" width="'+Math.max(200, size[0])+'" height="'+size[1]+'" allowTransparency="true"></iframe>';

				return outerStr;
			}
		};
		_insertButton._getPopupUrl = function(opts) {//debugger
			var scope = opts['scope']||'all',
				redirectURI = opts['redirectURI']||(ieVer<=6?'https%3A%2F%2Fgraph.qq.com%2Fjsdkproxy%2Fredirect.html':'http%3A%2F%2Fqzonestyle.gtimg.cn%2Fqzone%2Fopenapi%2Fredirect.html'),//'http%3A%2F%2Fqzs.qq.com%2Fqzone%2Fopenapi%2Fsuccess.html',//,'http%3A%2F%2Fqzs.qq.com%2Fqzone%2Fopenapi%2Fsuccess.html',
				display = opts['display']||'',
				clientId = QC.getAppId();//opts['clientId'] || opts['client_id'];

			var paras = [
				'client_id='+clientId,
				'response_type=token'
			],url='https://graph.qq.com/oauth2.0/authorize';

			if(scope) {
				paras.push('scope='+scope);
			}
			if(redirectURI) {
				if(redirectURI.indexOf('?')>0) {//防止被重复编码
					redirectURI = encodeURIComponent(redirectURI);
				}
				paras.push('redirect_uri='+redirectURI);
			}
			if(display=='mobile') {
				paras.push('display='+display);
			}

			url = url +"?"+ paras.join("&");

			return url;
		};


		var _getACToken = function() {
			return access_token || function() {
				var matcher = location.hash.match(/access_token=([^&]*)/i),
					/*dt_cache,*/
					_timer, _cbPool=[], _keys;

				//从cookie中获取tokenKeys
				var __qc__k;
	//			access_token = matcher&&matcher[1]//||'46B2F024FCF6C0783E5649333EE316CF',//for debugger
				if(!(dt_cache&&dt_cache.openid) && (__qc__k = $Cookie.get("__qc__k"))) {//debugger
					_keys = __qc__k.split("=");
					if(__qc__k.length && _keys.length!=2) throw new Error("QQConnect -> cookie : __qc__k 格式非法");
					dt_cache = {
						client_id : -1,//通过本地形式调用，无该项值
	//						client_id : appId,  _qc_appid,//[2],
						openid : _keys[0]
					};

				}
				access_token = (matcher&&matcher[1])||(_keys&&_keys[1]);//||'46B2F024FCF6C0783E5649333EE316CF',//for debugger

			}();
		};

		var _getMe = function() {//debugger
			var /*matcher = location.hash.match(/access_token=([^&]*)/i),*/
				/*dt_cache,*/
				_timer, _cbPool=[]/*, _keys*/;

			//从cookie中获取tokenKeys
//			var __qc__k;
////			access_token = matcher&&matcher[1]//||'46B2F024FCF6C0783E5649333EE316CF',//for debugger
//			if(!dt_cache && (__qc__k = $Cookie.get("__qc__k"))) {//debugger
//				_keys = __qc__k.split("=");
//				if(__qc__k.length && _keys.length!=2) throw new Error("QQConnect -> cookie : __qc__k 格式非法");
//				dt_cache = {
//					client_id : -1,//通过本地形式调用，无该项值
////						client_id : appId,  _qc_appid,//[2],
//					openid : _keys[0]
//				};
//
//			}
//			access_token = (matcher&&matcher[1])||(_keys&&_keys[1]);//||'46B2F024FCF6C0783E5649333EE316CF',//for debugger
//debugger
			_getACToken();

			var _fireCallBack = function(openId, accessToken, _dt) {
				var _crtReq;
				while(_crtReq = _cbPool.shift()) {
					_crtReq(openId, accessToken, _dt);
				}
			};

			var _getMeError = function(error_description) {
				window.callback({error_description:error_description});
			};

			//cookie命中失败时，异步请求方式获取tokenKeys，并将结果记入cookie，用已下次调用是命中
			var getOpenId = function(_cb) {
				var script, fn = window.callback;
				window.callback = function(_dt) {//debugger
					clearTimeout(_timer);
					
					try {
						dt_cache = _dt;
						var openId = _dt.openid;
						var aToken = access_token;

						$Console.log(" getMe => openId & accessToken " + [openId, aToken, script?'通过me接口':'通过本地']);
//						if(openId && aToken) {// todo move to onLoginBack
//							document.cookie = ['__qc__k='+[openId,aToken].join("="), 'path=/'].join(";");
//
////							try{
////								if(window.opener) {//debugger
//////									window.opener.QC.Login({});//._onLoginBack();
////									window.opener.QC.Login._onLoginBack();
////								}
////							}catch(e){}
//						}
						_cb && _cb(openId, access_token, _dt);
					}catch(e){
						$Console.error(e.message+" : getOpenId");
					}

					script&&document.body.removeChild(script);
					window.callback = fn;//EMPTY_FUN;
//					fn&&fn();
				};

				if(!_getACToken()) {
					_getMeError("access_token丢失");
					return;
				}

				if(!dt_cache&&!script) {
					script = document.createElement("script");
					script.type = "text/javascript";
					script.src = "https://graph.qq.com/oauth2.0/me?access_token="+access_token;
					script.onerror = function(){_getMeError("me接口返回格式错误");};
					document.body.appendChild(script);
					_timer=setTimeout(function(){//3秒后模拟超时、失败
						_getMeError("me接口超时");
					}, 5000);
				}else{
					window.callback(dt_cache);
				}
				//			https://graph.qq.com/oauth2.0/me?access_token=iamaccesstoken
			};

			return function(_cb, _isInitFn) {//debugger
				_isInitFn
						? _cbPool.unshift(_cb)	//qc.init回调插入为队列中第一个
						: _cbPool.push(_cb);
				//木有access_token就不要烦啦
				getOpenId(_fireCallBack);

//				(access_token||_withOutToken) ? getOpenId(_fireCallBack) : alert('access_token丢失');
			}

		}();
		
		var _signOut = function() {//debugger
			dt_cache=null;
			access_token = undefined;
			_user_info = null;

			var logoutFun;
			for(var i=0;i<_logoutFuns.length;i++) {
				logoutFun = _logoutFuns[i];
				logoutFun();
			}

//			if(ieVer) {//如果是ie浏览器，signout后销毁PMProxy重新初始化为flashProxy，已响应登录回调
//				QC.init();
//			}
//			while(logoutFun=_logoutFuns.shift()) {
//				logoutFun();
//			}
		};

		var _showPopup = function(opts) {
			var url = _insertButton._getPopupUrl(opts||{});
			return window.open(url);
		};

		var _DEF_LOGIN_FUN = function(dt, opts) {
			QC.Login.fillUserInfo(opts['btnId'], dt);
		};

		var _loginFuns=[], _logoutFuns=[], _user_info;
		/**
		 * 加入QQ登录按钮
		 * @param opts {Object} 按钮参数，包括
		 * 						btnId	{String}	插入按钮html容器节点id
		 * 						size		{String}	按钮大小，可用值[A_XL, A_L, A_M, A_S;  B_M, B_S;  C_S]：可选参数，默认B_M
		 * 						scope	{String}	授权项，用逗号分隔
		 * 						display	{String}	应用场景，可用值[pc, mobile]，可选参数，默认pc
		 * @param loginFun {Function} 登录成功回调函数，回调参数：
		 * 						dt {Object} 当前登录用户基本信息
		 * 						opts {Object} 回传opts参数
		 * @param logoutFun {Function} 注销成功回调函数
		 */
		var retFun = function(opts, loginFun, logoutFun, __outCallFlag){//debugger
			var args = arguments;
//debugger
			//如果不是退出后的自动回调刷新，推入logoutFuns调用堆栈
			!__outCallFlag && logoutFun!==null && _logoutFuns.push(function(__opts){//debugger
				return function(){
					var argPara= [args[0], null, null, 1];//参数1为打标记，说明本次为logout后的自动调用
					(logoutFun||EMPTY_FUN)(__opts);
					args.callee.apply(null, argPara);//logout后自刷新按钮
				}
			}(opts));
//alert(_logoutFuns.length)
			var _loginFun, 
				loginFunFire = function () {
					for(var i=0;i<_loginFuns.length;i++) {
						_loginFun = _loginFuns[i];
						_loginFun(_user_info);
					}
//					while(_loginFun = _loginFuns.shift()) {
//						_loginFun(_user_info);
//					}

				};

			!__outCallFlag && loginFun!==null && _loginFuns.push(function(__opts){
				return function(dt) {
					(loginFun||_DEF_LOGIN_FUN)(dt, __opts);
				}
			}(opts));
//			alert(_loginFuns.length)
			 if(!_user_info/*&&!_loginFuns.length<=1*/){
				_getMe(function(openId){
					if(openId) {
						QC.api("get_user_info")
							.success(function(req){
								_user_info = req.data;
								loginFunFire();
							})
							.error(function(req){
								QC.Console.error("Login => getMe 获取数据失败"+req);
							});
					} else {//debugger
						_insertButton(opts);
					}
				});
			} else {
				 _user_info && loginFunFire();
			}
		};


		$Object.extend(retFun, {
			/**
		 	 * @deprecated 不推荐，改用QC.Login
			 */
			insertButton : _insertButton,
			/**
			 * 获取当前登录用户基本信息
			 */
			getMe : _getMe,

			showPopup : _showPopup,
			/**
			 * 注销当前用户
			 */
			signOut : function(){
				document.cookie=["__qc__k=", "path=/;"].join(";");
				_signOut();
			},
			/**
			 * 获取当前登录用户 openid 与 accessToken
			 * @return {Object}
			 */
			getTokenKeys : function() {//debugger
				return {
					openid : dt_cache&&dt_cache.openid,
					accessToken : access_token
				}
			},
			/**
			 * 检测登录态
			 * @return {Boolean}
			 */
			check : function() {
				return !!(dt_cache && access_token && _user_info);
			},
			_onLoginBack : function(openId, aToken) {//debugger
				if(openId && aToken) {
					document.cookie = ['__qc__k='+[openId,aToken].join("="), 'path=/'].join(";");
				}

				_getACToken();
				QC.init();
				QC.Login({}, null, null, 1);

				QC.invoke("close");//尝试调用关闭登录窗口
			},
			reset : function() {
				_loginFuns=[];
				_logoutFuns=[];
			},
			/**
			 * 提供的默认登录成功填充用户基本信息方法
			 * @param btnId 按钮容器
			 * @param reqData 当前登录用户基本信息
			 */
			fillUserInfo : function(btnId, reqData){
				var dom = $(btnId),
					 _logoutTemplate=[
						'<span class="qc_item figure"><img src="{figureurl}" class="{size_key}"/></span>',
						'<span class="qc_item nickname" style="margin-left:6px;">{nickname}</span>',
						'<span class="qc_item logout"><a href="javascript:QC.Login.signOut();" style="margin-left:6px;">退出</a></span>'
					].join("");

				dom && (dom.innerHTML = QC.String.format(_logoutTemplate, {
					nickname : QC.String.escHTML(reqData.nickname),
					figureurl : reqData.figureurl
				}));
			}
		});

		return retFun;
	};

	var Like = function() {
		return {
			_insertButton : EMPTY_FUN
		}
	};

	var Share = function() {
		return {
			
		}
	};

	return {
		Login : Login(),
		Like : Like(),
		Share : Share(),

		Toolkit: $Toolkit,
		JSON :  $JSON,
		XML : $XML,
		Object: $Object,
		QueryString : $QueryString,
		String : $String,
		Cookie : $Cookie,
		Console : $Console
	}
}();


/**
 * file Request.js
 */
(function(_qc){
	var EMPTY_FUN = function() {};
	var ieVer = window.ActiveXObject && navigator.userAgent.match(/MSIE\s+(\d+)/)[1];
	var config = {
		PMCrossPage : 'https://graph.qq.com/jsdkproxy/PMProxy.html',
		FLACrossPage : 'https://graph.qq.com/jsdkproxy/FLAProxy.swf',
		getCrossSolution:function(){//debugger
			var solution;
			if(window.postMessage && (!ieVer/* || _qc.Login.check()*/ ) ) {//ie 9 浏览器在opener.postMessage时有问题，ie下如果未登录，统一采用fla方案
				solution = "PMProxy";
			} else if ( !!(
					(window.ActiveXObject && new ActiveXObject('ShockwaveFlash.ShockwaveFlash') ) ||
					(navigator.plugins && navigator.plugins["Shockwave Flash"]) || false
				) ) {
				solution = "FLAProxy";
			} else {
				_qc.Console.error("未找到可用的跨域通信方案");
				solution = "EMPProxy";
			}
			
			_qc.Console.info("确定跨域代理策略：" + solution);

			return solution;
		}
	};
	var sequence = 1000;

	_qc.getConfig = function(){
		return config;
	};
//	_qc.init = function(opt) {
//		config.appid = opt.appid;
//	};


//	var requestQueue = [];
	/**
	 * 请求抽象类
	 * @param uri
	 * @param paras
	 * @param fmt
	 * @param method
	 */
	var Request = function(uri, paras, fmt, method) {
		this.uri=uri;
		this.paras=paras||{};
		this.fmt=fmt||"json";
		this.method=(method||"get").toLocaleLowerCase();

		this.successPool = [];
		this.errorPool = [];
		this.completePool = [];

		this.seq = sequence ++;
	};
	Request.prototype.success = function(fun){this.successPool.push(fun);return this;};
	Request.prototype.error = function(fun){this.errorPool.push(fun);return this;};
	Request.prototype.complete = function(fun){this.completePool.push(fun);return this;};
	/**
	 * 发送请求虚方法
	 */
	Request.prototype.send = EMPTY_FUN;
	Request.prototype._onCallback = function(xhr, fmt, seq){//debugger
		if(xhr.status == 200 || xhr.status == 204) {
			var responseText = xhr.responseText,
				response = new Response(responseText, xhr.status, fmt, seq);
			!~~response.code ? this.onSuccess(response) : this.onError(response);
		} else {
			this.onError(new Response("", xhr.status, fmt, seq));
		}
	};
	Request.prototype.onSuccess = function(response){
		var pool = this.successPool;
		for(var i=0;i<pool.length;i++){
			pool[i](response);
		}
		this.onComplete(response);
	};
	Request.prototype.onError = function(response){
		var pool = this.errorPool;
		for(var i=0;i<pool.length;i++){
			pool[i](response);
		}
		this.onComplete(response);
	};
	Request.prototype.onComplete = function(response){
		var pool = this.completePool;
		for(var i=0;i<pool.length;i++){
			pool[i](response);
		}
	};

	/**
	 * 响应抽象类
	 * @param respData
	 * @param status
	 * @param fmt
	 * @param seq
	 */
	var Response = function(respData, status, fmt, seq) {
		this.status = status||-1;
		this.fmt = fmt || "json";
		this.code = this.ret = -1;
		this.data = null;
		this.seq = seq||-1;//响应时序

		this.parseData(respData);

		if(this.code && Response[this.code]) {
			Response[this.code](this.data, this.dataText);
		}
	};
	Response.prototype.parseData = function(rd) {
		this.dataText = rd;
		switch (this.fmt) {
			case "xml":
					this.data = _qc.XML.parse(rd||'<root></root>');
//					debugger
					var node = this.data.selectNodes("//ret")[0];
					this.code = this.ret = (node&&node.firstChild.nodeValue)||-1;

//					throw new Error("尚未支持xml格式");
				break;
			
			case "json":
			default:
//					rd=rd.replace(/\\/g, "\\\\");
					this.data = _qc.JSON.parse(rd||'{}');
					this.code = this.ret = this.data.ret!==undefined
							? ~~this.data.ret
							: this.data.data&&this.data.data.ret!==undefined	//兼容不规范的返回格式
									? ~~this.data.data.ret
									: -1;
				break;
		}
	};
	Response.prototype.stringifyData = function() {
		return this.dataText;
	};
	Response[100013] = function(dt, dtTxt) {//token 失效
		_qc.Login.signOut();
		_qc.Console.warn("api返回token失效");
	};


	/**
	 * 通过XHR发起请求
	 */
	var XHRRequest = _qc.Toolkit.extend(function(){
		Request.apply(this, arguments);

		this.xhr = XHRRequest.createInstance();
	}, Request);

	_qc.Object.extend(XHRRequest.prototype, {
		send : function() {//debugger
			var xhr = this.xhr,
				method = this.method,
				fmt = this.fmt,
				me = this,
				paras = _qc.QueryString.stringify(me.paras),
				uri = method=="post"
						? this.uri
						: this.uri.indexOf("?")<0
							? this.uri + '?' + paras
							: this.uri.replace(/[&?]*/g, "") + '&' + paras;

			xhr.open(method, uri, !!this.async);
			try{
				xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
				xhr.setRequestHeader("X-Requested-From","_TC_QC_jsProxy_");
			}catch(e){}


			xhr.onreadystatechange = function() {
				if(xhr.readyState === 4) {
					me._onCallback(xhr, fmt, me.seq);
//					if(xhr.status === 200 || xhr.status === 204) {
//						var responseText = xhr.responseText;
//						me.onSuccess(new Response(responseText, xhr.status, fmt));
//					} else {
//						me.onError(new Response("{}", xhr.status));
//					}
				}
			};

			xhr.send(paras||null);
		}
	});
	XHRRequest.createInstance = window.XMLHttpRequest
					? function() {	return new window.XMLHttpRequest();	}
					: function() {	return new window.ActiveXObject( "Microsoft.XMLHTTP" );	};


	/**
	 * 代理抽象类
	 */
	var Proxy = function() {
		this.requests = [];
		this.invokes = [];
//		this.pendingRequests = [];
		this.readyPool = [];
		this.isReady = false;
		this.timeStamp = +new Date();
		this.init();
	};
//	var Proxy = _qc.extend(function() {
//		Request.apply(this, arguments);
//
//		this.requests = [];
////		this.pendingRequests = [];
//		this.readyPool = [];
//		this.isReady = false;
//		this.init();
//	}, Request);
	/**
	 * 初始化代理，虚方法
	 */
	Proxy.prototype.init = EMPTY_FUN;
	Proxy.prototype.ready = function(fun){
		this.readyPool.push(fun);
	};
	Proxy.prototype.onReady = function() {
		this.isReady = true;
		var pool = this.readyPool;
		for(var i=0;i<pool.length;i++){
			pool[i]();
		}
	};
	Proxy.prototype.send = function(req) {
		var pendingRequest;
		req && ( /*req.seq = sequence++, */this.requests.push(req) );

		while(this.isReady && (pendingRequest = this.requests.shift())) {
			Proxy.pendingRequests.push(pendingRequest);
			QC.Console.log("seq no :" + pendingRequest.seq +"请求发起" + "  ts -> " + (+new Date()));
			this._doSend(pendingRequest);
//			this.send();//自递归调用
		}
	};
	/**
	 * 触发调用 虚方法
	 */
	Proxy.prototype._doSend = function(req){};
//	Proxy.prototype.receive = function(req, responseText, status, fmt) {
//		(status==200||status==204)
//				? req.onSuccess(new Response(responseText, status, fmt))
//				: req.onError(new Response(responseText, status, fmt));
//	};
	/**
	 * 派发命令格式
	 * 	@1 : response@...  标示请求返回
	 * 	@2 : invoke@... 标示调用
	 * @param cstDt
	 * @param seq
	 * @param fmt
	 */
	Proxy.prototype._preDispatch = function(_this, cstDt, seq, fmt) {
		var dt = cstDt.data || (cstDt.currentTarget && cstDt.currentTarget.data) || {};
		var cmd = dt.split("@@@");
//		alert("###"+cmd)
		switch(cmd[0]) {
			case "invoke":
					this.invoke(cmd[1]);
//					Proxy.invoke(cmd[1]);
				break;
			default:
					this.dispatch(cmd[1]||cstDt, seq, fmt);
//					_this.dispatch(cmd[1]||cstDt, seq, fmt);
				break;
		}
	};
	Proxy.prototype.invoke = function(ivk) {
		var pendingInvoke;
		ivk && ( /*req.seq = sequence++, */this.invokes.push(ivk) );

		while(this.isReady && (pendingInvoke = this.invokes.shift())) {
//			Proxy.pendingRequests.push(pendingRequest);
//			QC.Console.log("seq no :" + pendingRequest.seq +"请求发起" + "  ts -> " + (+new Date()));
			this._doInvoke(pendingInvoke);
//			this.invoke();//自递归调用
		}
	};
	Proxy.prototype._doInvoke = function(ivk) {
		
	};
	Proxy.prototype.dispose = function() {
		_proxy=null;
		this.onDispose();
	};
	Proxy.prototype.onDispose = function() {};

	Proxy.pendingRequests=[];//从发起请求开始hold住各个请求，待响应后找到对应的触发点
	//找到该响应是那个pendingRequest发起的<-------------------------------------------------------入口
	Proxy.dispatchReceive = function(seq, resText, status, fmt) {
		var pendingRequests = Proxy.pendingRequests;
		for(var i=0;i<pendingRequests.length;i++) {
			if(pendingRequests[i].seq==seq) {//QC.JSON.stringify(QC.QueryString.parse(resText))
				QC.Console.log("seq no :" + seq +"响应收到" + "  ts -> " + (+new Date()));
				pendingRequests[i]._onCallback({status:status, responseText: resText}, fmt, seq);//构造模拟xhr对象，进入回调分支
//				pendingRequests[i].receive(pendingRequests[i], resText, status, fmt);
				pendingRequests.splice(i, 1);
				return;
			}
		}

		//error
	};
	/**
	 *
	 * @param cmdStr
	 * 	eg: a.b("X","Y"); ==> a.b#X,Y
	 */
	Proxy.invoke = function() {
		var _pendingPool=[];

//		var invoke = function(cmdStr) {
//			var pas = cmdStr.split("#"),
//				cmdP=pas[0],
//				args=pas[1]&&pas[1].split(","), cmd;
//
//			cmdP=cmdP.split(".");
//			for(var i=0;i<cmdP.length;i++) {
//				cmd=cmd ? cmd[cmdP[i]] : window[cmdP[i]];
//			}
//
//			cmd.apply(null, args);
//			_qc.Console.log("invoke:\t"+cmdStr);
//		};

		return function(cmdStr) {//alert(cmdStr)
			cmdStr && _pendingPool.push(cmdStr);

			if(!_proxy) {
				_qc.Console.info("Proxy未初始化，invoke入栈");
				Proxy.generateProxy();
				return;
			}

			var _crtIvk;
			while(_crtIvk = _pendingPool.shift()) {
				_proxy._doInvoke(_crtIvk);
//				invoke(_crtIvk);
			}
		}
	}();
	var _proxy;
	Proxy.generateProxy = function() {
		var _solutions = {
			PMProxy : PMProxy,
			FLAProxy : FLAProxy,
			EMPProxy : EMPProxy
		};
//			if(!_proxy) {_proxy=new PMProxy();}
//			if(!_proxy) {_proxy=new FLAProxy();}
//			if(!_proxy) {_proxy=new EMPProxy();}
		if(!_proxy) {_proxy=new _solutions[config.getCrossSolution()]();}//lazy init...

		return _proxy;
	};
	Proxy.getFunction = function(cmdP) {
		var cmd;
		cmdP=cmdP.split(".");
		for(var i=0;i<cmdP.length;i++) {
			cmd=cmd ? cmd[cmdP[i]] : window[cmdP[i]];
		}
		return cmd;
	};

	/**
	 * flash 代理
	 */
	var FLAProxy = _qc.Toolkit.extend(function(){
		Proxy.apply(this, arguments);
	}, Proxy);

	_qc.Object.extend(FLAProxy.prototype, {
		prefix : '_TC_QC_flaProxy_',
		init : function() {//debugger
			//如果有window.name，说明是succ页引用的QC，作为响应体，conId应该大于10000
			//否则则为触发点引用的QC，conId小于10000
			var _me = this,
				conId = function(){//debugger
					var mat = window.name.match(/oauth2Login_(\d+)/),
						__qc_wId = ~~_qc.Cookie.get("__qc_wId"),

						ret = ~~( (mat&&mat[1])||(+new Date()%1000) );

						!mat && (document.cookie=["__qc_wId=" + ret, "; path=/"].join(";"));

						_qc.Console.info("跨域窗口标识号 __qc_wId : " + __qc_wId);
					return ret;
				}(),
				receiveId = conId<10000 ? conId + 10000 : conId - 10000;

			var flaStr = FLAProxy.getFlashHtml({
				"src" : config.FLACrossPage,
				"width" : "100%",
				"height" : "100%",
				"allowScriptAccess" : "always",
				"id" : "_qc_cross_request_flash_proxy",
				"name" : "_qc_cross_request_flash_proxy",
				"flashVars":"suffix="+(this.timeStamp)+"&conId="+conId+"&conId_receive="+receiveId
//				"wmode" : "opaque",
			});

			var cot = this.cot = document.createElement("div");
			cot.style.cssText = "position:fixed; _position:absolute; top:30px; left:30px; width:3px; height:3px; margin:0; padding:0; display:none;";
			cot.innerHTML = flaStr;

			document.body.appendChild(cot);
			cot.style.display="block";

			window[this.prefix+'onFlashReady_'+this.timeStamp] = function() {
			 	_qc.Console.info("FLAProxy代理创建成功，耗时"+(new Date() - _me.timeStamp));
				setTimeout(function(){//打断flash调用堆栈
					_me.isReady=true;
					_me.send();
					_me.invoke();
				});

				if(!_qc.Login.check()) {
					document['_qc_cross_request_flash_proxy'].initConn();//初始化连接器，未跨页面调用交互做准备
				}
			};

			window[this.prefix+'onFlashRequestComplete_'+this.timeStamp] = function(cstDt, seq, fmt) {
				setTimeout(function(){//打断flash调用堆栈
					_me._preDispatch(_me, cstDt, seq, fmt);
				});
			};

			window[this.prefix+'onFlashInvokeBack_'+this.timeStamp] = function() {//debugger
				var arg = arguments;
				setTimeout(function(){//打断flash调用堆栈
					var fun=Proxy.getFunction(arg[0]);
	//				var paras = [].slice.call(arguments, 1);
					var paras = arg[1];
					arg[0].indexOf(".")>-1
							? fun.apply(null, paras)
							: fun(paras);
				});
			};
		},
		_doSend : function(regObj) {//debugger
			var uri = regObj.uri,
				paras = _qc.QueryString.stringify(regObj.paras),
				seq = regObj.seq,
				fmt = regObj.fmt,
				method = regObj.method;
			
//			var proxyFun = document['_tencent_cross_request_flash_proxy'].httpRequest;
			var proxyFun = document['_qc_cross_request_flash_proxy'].httpRequest;
			proxyFun ? proxyFun(uri, paras, method, fmt, seq) : (!function(){throw new Error("flash proxy 初始化失败")}());
		},
		dispatch : function(cstDt, seq, fmt) {//debugger
			var data = cstDt.currentTarget.data,
				status=cstDt.type!="complete"?404:200;
			Proxy.dispatchReceive(seq, data, status, fmt);
		},
		_doInvoke : function(args) {
			var fun = document['_qc_cross_request_flash_proxy'].jsCallSwf;
			fun && fun.apply(null, args);
//			alert("F::"+args);
		}
	});

	/**
	 * 获取flash实例字符串
	 * @param flashArguments
	 * @param requiredVersion
	 * @param flashPlayerCID
	 */
	FLAProxy.getFlashHtml = function(flashArguments, requiredVersion, flashPlayerCID) {
		var _attrs = [],
			_params = [],
			_isIE = !!window.ActiveXObject;

		requiredVersion = requiredVersion||9;

		for (var k in flashArguments) {
			switch (k) {
				case "noSrc" :
				case "movie" :
					continue; //sds 这里是不处理的特性
					break;
				case "id" :
				case "name" :
				case "width" :
				case "height" :
				case "style" :
					if(typeof(flashArguments[k]) != 'undefined'){
						_attrs.push(' ', k, '="', flashArguments[k], '"');
					}
					break;
				case "src" :
					if (_isIE) {
						_params.push('<param name="movie" value="', (flashArguments.noSrc ? "" : flashArguments[k]), '"/>');
					//	_params.push('<param name="movie" value="', flashArguments[k], '"/>');
					}else{
						_attrs.push(' data="', (flashArguments.noSrc ? "" : flashArguments[k]), '"');
					}
					break;
				default :
					_params.push('<param name="', k, '" value="', flashArguments[k], '" />');
			}
		}

		if (_isIE) {
			_attrs.push(' classid="clsid:', flashPlayerCID || 'D27CDB6E-AE6D-11cf-96B8-444553540000', '"');
		}else{
			_attrs.push(' type="application/x-shockwave-flash"');
		}

		//当没有安装并且应用没有刻意指定的时候，走Codebase路线
		if(location&&location.protocol.indexOf("https")<0) {//https页面不要触发不安全内容提示
			_attrs.push(' codeBase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab#version=', requiredVersion, '"');
		}

		return "<object" + _attrs.join("") + ">" + _params.join("") + "</object>";
	};

	/**
	 * postMessage代理
	 */
	var PMProxy = _qc.Toolkit.extend(function(){
		Proxy.apply(this, arguments);
	}, Proxy);
	_qc.Object.extend(PMProxy.prototype, {
		init : function() {//alert('m')
			var _me=this;
			_me._connFrame = document.createElement("iframe");
			_me._connFrame.style.cssText = "width:0px; height:0px; display:none; overflow:hidden;";

			_me._connFrame.src = config.PMCrossPage;
			_me._connFrame.onload = function(){//debugger;//alert('frame loaded')
				_qc.Console.info("PMProxy代理创建成功，耗时"+(new Date() - _me.timeStamp));
				_me.isReady=true;
				_me.send();
				_me.invoke();
			};
			document.body.appendChild(_me._connFrame);
//			debugger

			var _preDispatchHandler = function(crsDt){
				_me._preDispatch(_me, crsDt);
			};

			window.addEventListener
					? window.addEventListener("message", _preDispatchHandler, false)
					: window.attachEvent("onmessage", _preDispatchHandler);
		},
		_doSend : function(regObj) {//debugger
//			var str = _qc.QueryString.stringify(regObj);
			var str = _qc.QueryString.stringify({uri:regObj.uri, paras:_qc.QueryString.stringify(regObj.paras), fmt:regObj.fmt, method:regObj.method});
			this._connFrame.contentWindow.postMessage(str, "*");
		},
		/**
		 * 派发跨域回调
		 */
		dispatch : function(crsDt) {//debugger
//			alert('s')
			var dt = crsDt.data,
			obj = dt.split("#"),
			seq = obj[0],
			status = obj[1],
			fmt = obj[2],
			data = obj[3];
//			data = _qc.JSON.stringify(_qc.QueryString.parse(dt));
//			dtObj = QC.QueryString.parse(data);
			_qc.Console.log("data:\t"+data);
			Proxy.dispatchReceive(seq, data, status, fmt);
		},
		_doInvoke : function(cmdStr) {
			_qc.Console.log("invoke:\t"+cmdStr);
			if(typeof cmdStr!="string") return;
			
			var pas = cmdStr.split("#"),
				cmdP=pas[0],
				args=pas[1]&&pas[1].split(","), cmd;

			cmd = Proxy.getFunction(cmdP);

			cmd.apply(null, args);
		},

		onDispose : function() {
			this._connFrame.parentNode.removeChild(this._connFrame);
			this._connFrame=null;
		}
	});

	/**
	 * 空代理
	 */
	var EMPProxy = _qc.Toolkit.extend(function(){
		Proxy.apply(this, arguments);
	}, Proxy);
	_qc.Object.extend(EMPProxy.prototype, {
		init : function() {_qc.Console.info("init:"+arguments)},
		_doSend : function(regObj) {_qc.Console.info("_doSend:"+arguments)},
		dispatch : function(crsDt) {_qc.Console.info("dispatch:"+arguments)}
	});

	_qc.XHRRequest = XHRRequest;
	_qc.request = function(uri, paras, fmt, method) {
		return new XHRRequest(uri, paras, fmt, method);
	};
	var fun_ready_pool=[];
	_qc.api = function() {
		var _pendingPool = [];

		/**
		 * 绑定请求openapi的必备参数
		 * @param req Request请求对象
		 * @return Request请求对象
		 */
		var bindTokenPara = function(req) {//debugger
			var TKObj = _qc.Login.getTokenKeys();

			if(appId<=0) throw new Error("意外的调用了绑定token到req的方法 bindTokenPara");
			req.paras.oauth_consumer_key = appId;
			req.paras.access_token = TKObj.accessToken;
			req.paras.openid = TKObj.openid;
			req.paras.format = req.fmt;

			return req;
		};

		/**
		 * 用QC.api函数 调用openapi接口
		 * @param api {String} api名称或全路径
		 * @param paras {Object} api参数
		 * @param fmt {String} 期待返回格式，可用值[json, xml]，可选，默认json
		 * @param method {String} 发送请求方式，可用值[get, post], 可选，根据默认配置自适应
		 */
		var fun = function(api, paras, fmt, method) {//debugger
			_proxy = Proxy.generateProxy();

			var defAPICfg = getAPIConfig(api);
			api = defAPICfg.api||api;
			paras = paras||{};
			method = method||defAPICfg.method;

			var req = new Request(api, paras, fmt, method);
			/**
			 * setTimeout重要 * 先将return后面的success与error事件绑定成功后再发起请求
			 */
			if(appId>0) {
				setTimeout(function(){
					var aToken = _qc.Login.getTokenKeys();
					if(aToken.openid && aToken.accessToken) {
						_proxy.send(bindTokenPara(req));
					}else{
						_pendingPool.push(req);
						_qc.Console.warn("openid与accessToken丢失，调用请求入栈 : ["+api+"]，栈大小："+_pendingPool.length);
					}
				},10);
			}else{
				_pendingPool.push(req);
				_qc.Console.warn((_proxy.isReady&&appId<0?"token获取失败，请调用用户登录流程":"api代理尚未初始化成功")+"，调用请求入栈 : ["+api+"]，栈大小："+_pendingPool.length);
			}

			return req;
		};

		fun._ready = function() {
			_qc.Console.info("init成功，开始触发api调用堆栈");
//			_proxy.invoke();
//			Proxy.invoke();

			var _crtReq;
			while(_crtReq = _pendingPool.shift()) {
				_proxy.send(bindTokenPara(_crtReq));
			}
		};

		fun.getDoc = function() {
			var DOCS = null,
				loadDocJS = function(key, fun) {
					var script = document.createElement("script");
					script.type = "text/javascript";
					script.src = "http://qzonestyle.gtimg.cn/qzone/openapi/qc_jsdkdoc.js";
					document.body.appendChild(script);
					
					window.on_qc_jsdkdoc_loaded = function(_docs) {
						DOCS = _docs;
						fun && fun(DOCS[key]);

						document.body.removeChild(script);
						script=null;
					};
				};
			
			return function(key, fun){
				(DOCS && fun)
						? fun(DOCS[key])
						: loadDocJS(key, fun||EMPTY_FUN);	
			};
		}();

		return fun;
	}();


//	var openId = -1, accessToken = "", appId = -1;
	var appId = -1, tmpCfg=null;//alias : client_id

	/**
	 * QC.init初始化QQ登录jssdk
	 * @param cfg {Object} ，参数包括：
	 * 						appId {Number}，申请到的appId(也叫做clientId)
	 */
	_qc.init = function(cfg) {//debugger
		cfg = cfg || tmpCfg ||{};
		tmpCfg = cfg;
		var TKObj = _qc.Login.getTokenKeys();
		appId = cfg.appId;
		
		if(!TKObj.openid) {
//			if(_proxy&&ieVer) {
//				_proxy.dispose();
//			}
//			_proxy.invoke();
			Proxy.invoke();
			if(fun_ready_pool.length && cfg.appId>-1){
				for(var i=0;i<fun_ready_pool.length;i++) {
					fun_ready_pool[i]();
				}
			}

			return;
		}

		_qc.Login.getMe(function(oid, token, dt){
			if(!~~dt.error && (dt.client_id<=0 || dt.client_id%1000000==cfg.appId%1000000)) {
//				openId = oid;
//				accessToken = token;
				appId =
						dt.client_id = cfg.appId||cfg.clientId||cfg.app_id||cfg.client_id;
//
//				//是否潜在风险??
//				document.cookie = '__qc__k='+[openId,accessToken,appId].join("=");
				_qc.api._ready && _qc.api._ready();//触发先于初始化创建的req请求
			} else {
//				_qc.Login.showPopup();
				_qc.Console.error(dt.error_description||"appId/client_id 不匹配");
			}
		}, true);

//		tmpCfg=null;
	};

	_qc.getAppId = function(ars) {
		if(ars) {
			fun_ready_pool.push(function(){
				ars.callee.apply(null, ars);
			});
		}
		return appId;
	};

	/**
	 * 响应跨窗口flash调用
	 */
	_qc.invoke = function() {//alert("M");debugger
		var pxy = Proxy.generateProxy();
		pxy.invoke(arguments);
	};


	/**
	 * 通过apikey获得各个api的基本调用配置
	 * @param apiKey
	 */
	var getAPIConfig = function() {
		var API_DICT = {
			"get_user_info" : {api:"https://graph.qq.com/user/get_user_info",method:"get"},
			"add_topic" : {api:"https://graph.qq.com/shuoshuo/add_topic",method:"post"},
			"add_one_blog" : {api:"https://graph.qq.com/blog/add_one_blog",method:"post"},
			"add_album" : {api:"https://graph.qq.com/photo/add_album",method:"post"},
			"upload_pic" : {api:"https://graph.qq.com/photo/upload_pic",method:"post"},
			"list_album" : {api:"https://graph.qq.com/photo/list_album",method:"get"},
			"add_share" : {api:"https://graph.qq.com/share/add_share",method:"post"},
			"check_page_fans" : {api:"https://graph.qq.com/user/check_page_fans",method:"get"},

			"add_t" : {api:"https://graph.qq.com/t/add_t",method:"post"},
			"add_pic_t" : {api:" https://graph.qq.com/t/add_pic_t",method:"post"},
			"del_t" : {api:"https://graph.qq.com/t/del_t",method:"post"},
			"get_repost_list" : {api:"https://graph.qq.com/t/get_repost_list",method:"get"},
			"get_info" : {api:"https://graph.qq.com/user/get_info",method:"get"},
			"get_other_info" : {api:"https://graph.qq.com/user/get_other_info",method:"get"},
			"get_fanslist" : {api:"https://graph.qq.com/relation/get_fanslist",method:"get"},
			"get_idollist" : {api:"https://graph.qq.com/relation/get_idollist",method:"get"},
			"add_idol" : {api:"https://graph.qq.com/relation/add_idol",method:"get"},
			"del_idol" : {api:"https://graph.qq.com/relation/del_idol",method:"post"},

			"get_tenpay_addr" : {api:"https://graph.qq.com/cft_info/get_tenpay_addr",method:"get"}
		};

		return function(apiKey){
			return API_DICT[apiKey]||{};
		}
	}();

	/**
	 * 自检测是否script url中带入了appId
	 */
	(function(){
		var reg = /\/qzone\/openapi\/qc\.js[?#]appId=(\d+)/i;
		var scripts = document.getElementsByTagName("script");
		for(var i=0, l=scripts.length;i<l;i++){
			var src = scripts[i].src||"";
			var mat = src.match(reg);
			if(mat&&mat[1]){
				_qc.Console.info("检测到自动初始化参数[appId]" + mat[1]);
				_qc.init({appId:mat[1]});
				return;
			}
		}
	})();
})(QC);


(function(){
	if(typeof Object.freeze=="function") {
		Object.freeze(QC);
	}
})();

/*  |xGv00|8dacfc178f1e680a4eb9af9c301ca2e6 */
