	var g_app;
	var g_db;
	var g_cmn;
	var g_cal;
	var g_calendarMain;
	var g_fullCreate;
	var Cookies = {};
	function _d2s(date){}
	function _s2d(str){}
	function _eventObject(doc){}
	function _newPseudoDoc(doc){}
	function _getUrlParam(name){}
	function _repeatEventInit(pseudoDoc){}
	function _getDocRepeatEvent(events, pseudoDoc){}
	function _renderEventBeforeCreate(guid, start, end, title, bkColor, repeatRule, endRec, allDay, textColor){}
	function _interDays(eventStart, eventEnd){}
	function _removeStrPx(str){}
	function _renderDocEvent(doc){}
	function wizAddTags(select){}
	function createDefaultEvent(start, stop, title, defaultColor){}
	function wizUpdateLayout(){}
	function wizDeleteEvent(guid){}
	function wizCreateDatepicker($obj){}
	function _getRemindFromInfo(info){}
	function _getEventColorIdFromInfo(){}
	function _getDocInfo(){}
	function setCaretToPos (input, pos) {}
	function setSelectionRange(input, selectionStart, selectionEnd) {}
	function getDocTags(){}
	function setCookie(key, accessToken){}
	function getCookie(key){}
	function formatIntToDateString(n){}
	function setChosenIdsToDb(ids){}
	//
	var g_isChrome;
	function isChrome() {
		if (g_isChrome) return g_isChrome;
		//
		var ua = navigator.userAgent.toLowerCase();
		g_isChrome = ua.indexOf('chrome') != -1;
		//
		return g_isChrome;
	}
	function IsArray(array) {
        return (array instanceof Array);
    }
	// TODO: js函数可以返回对象的拷贝，而不是引用，修改所有相关错误。
	// TODO: 修改获得event函数，例如：_getGoogleEventObj,_getWizEventObj,_getFullCalEventObj();
	// TODO: 看看js异步编程，不影响编程风格（google日历同步代码）。
	// TODO: 业务逻辑 与 页面 通过一个结构体传递参数，避免乱套。
	var g_weeklyRptRule = "EveryWeek";

////////////////////////////////////////////////////////////
//
//	
	// TODO: _getAllWizEvent();
	function _getAllOriginalEvent(events, start, end){
		var sql = "DOCUMENT_LOCATION not like '/Deleted Items/%' and (KB_GUID is null or KB_GUID = '')";
		var and1 = " and DOCUMENT_GUID in (select DOCUMENT_GUID from WIZ_DOCUMENT_PARAM where PARAM_NAME = 'CALENDAR_START'  and  PARAM_VALUE <= '" + end + "' )";
		var and2 = " and DOCUMENT_GUID in (select DOCUMENT_GUID from WIZ_DOCUMENT_PARAM where PARAM_NAME = 'CALENDAR_END'  and  PARAM_VALUE >= '" + start + "' )";
		if (start)
			sql += and2;
		if (end)
			sql += and1;
		if (g_db.DocumentsDataFromSQL) {
			try { 
				var data = g_db.DocumentsDataFromSQL(sql);
				//
				var obj = JSON.parse(data);
				//
				if (!obj || !IsArray(obj))
					return;
				//
				for (var i = 0; i < obj.length; i ++) {
					events.push(EVENTOBJECT(obj[i]));
				}
			}
			catch(err) {
				toLog("_getAllOriginalEvent failed, sql: " 
					+ sql + "data: " + data + "err: " + err);
				return;
			}			
		}
		else {
			var docColletion = g_db.DocumentsFromSQL(sql);
			//
			if (docColletion && docColletion.Count){
				var doc;
				for (var i = 0; i < docColletion.Count; ++ i){
					doc = docColletion.Item(i);
					var eventObj = _eventObject(_newPseudoDoc(doc));
					if (eventObj)
						events.push(eventObj);
				}
			}			
		}

	}
	function getEventHtml(title, content){
		var htmlText = '<html><head><meta http-equiv="Content-Type" content="text/html; charset=unicode"><title>'
  				+ title + '</title>' + '</head><body><!--WizHtmlContentBegin--><div>' + content + '</div><!--WizHtmlContentEnd--></body></html>';

  		return htmlText
	}
    function getTimeStr(start, end){
    	// TODO: locailize and/or modify month view
    	var startStr = _d2s(start);
    	var endStr = _d2s(end);
    	var interDays = _interDays(startStr, endStr);
    	var view = g_cal.fullCalendar('getView');

    	if (view.name == "month"){
    		
    		if (endStr.indexOf("23:59:59") != -1){
    			startStr = startStr.substr(0, 10);
	    		if (interDays < 2){
	    			endStr = g_loc_leftbracket + g_loc_create_allday + g_loc_rightbracket;
	    		}
	    		else{
	    			endStr = endStr.substr(0, 10);
	    			endStr = ' ~ ' + endStr + ' ' + g_loc_leftbracket + interDays + g_loc_days + g_loc_rightbracket;
	    		}
    		}else {
    			if (interDays < 2)
    				endStr = '~' + endStr.substr(11);
    			else {
    				endStr = ' ' + endStr;
    			}
    		}
    	}else {
    		endStr = '~' + endStr.substr(11);
    	}

    	return startStr + endStr;
    }
    function formatDefaultEditTag(tagStr){
    	return g_loc_tag + "  " + tagStr;
    }
	function setBubbleBg(){

		var html = "<div id='fc-bu-bg'></div>";
		$(document.body).append(html);
		$('#fc-bu-bg').addClass("bubbleBg");
		var width = document.documentElement.clientWidth;
		var height = document.documentElement.clientHeight;
		$('#fc-bu-bg').css({"width":width, "height":height});
		$('#fc-bu-bg').css("visibility", "visible");
	} 
	function hiddenBubbleBg(){
		$('#fc-bu-bg').css("visibility", "hidden");	
	}
	function getRepeateHtml(){
		var html = 
				"<div id='rpt-main'>" + 
					"<div >" + 
						"<div id='rpt-title'>" + 
							"<span>" + g_loc_repeat + "</span>" + 
						"</div>" + 
						"<div id='rpt-close'>" + 
						"</div>" + 
					"</div>" + 
					"<div id='rpt-mid'>" + 
						"<table id='rpt-mid-t'>" + 
							"<tdody >" + 
								"<tr>" + 
									"<th>" + 
										"<span class='fc-font'>" + g_loc_repeat + g_loc_colon + "</span>" + 
									"</th>" + 
									"<td>" + 
										"<div>" + 
										"<select id='rpt-rpt'></select>" + 
										"</div>" + 
									"</td>" + 
								"</tr>" + 
								"<tr id='rpt-fre-row'>" + 
									"<th>" + 
										"<span class='fc-font'>" + g_loc_repeatevery + g_loc_colon + "</span>" + 
									"</th>" + 
									"<td>" + 
										"<div>" + 
										"<select id='rpt-fre' size='1'></select>" + 
										"</div>" + 
									"</td>" + 
								"</tr>" + 
								"<tr id='rpt-tiem'>" + 
									"<th>" + 
										"<span class='fc-font'>" + g_loc_repeaton + g_loc_colon + "</span>" + 
									"</th>" + 
									"<td>" + 
										"<div >" + 
											"<input id='rpt-time-1' type='checkbox'/>" + 
											"<label for='rpt-time-1'>" + g_loc_dtpicker_daynameshort_1 + "</label>" + 
											"<input id='rpt-time-2' type='checkbox'/>" + 
											"<label for='rpt-time-2'>" + g_loc_dtpicker_daynameshort_2 + "</label>" + 
											"<input id='rpt-time-3' type='checkbox'/>" + 
											"<label for='rpt-time-3'>" + g_loc_dtpicker_daynameshort_3 + "</label>" + 
											"<input id='rpt-time-4' type='checkbox'/>" + 
											"<label for='rpt-time-4'>" + g_loc_dtpicker_daynameshort_4 + "</label>" + 
											"<input id='rpt-time-5' type='checkbox'/>" + 
											"<label for='rpt-time-5'>" + g_loc_dtpicker_daynameshort_5 + "</label>" + 
											"<input id='rpt-time-6' type='checkbox'/>" + 
											"<label for='rpt-time-6'>" + g_loc_dtpicker_daynameshort_6 + "</label>" + 
											"<input id='rpt-time-7' type='checkbox'/>" + 
											"<label for='rpt-time-7'>" + g_loc_dtpicker_daynameshort_0 + "</label>" + 
										"</div>" + 
									"</td>" + 
								"</tr>" + 
								"<tr>" + 
									"<th>" + 
										"<span class='fc-font'>" + g_loc_start + g_loc_colon + "</span>" + 
									"</th>" + 
									"<td>" + 
										"<div>" + 
										"<input id='rpt-beg'/>" +
										"<span id='rpt-beg-lunar' class='fc-font' style='display:none'></span>" +  
										"</div>" + 
									"</td>" + 
								"</tr>" + 
								"<tr>" + 
									"<th valign='top' style='padding-top:5px;'>" + 
										"<span class='fc-font' id='rpt-endtitle' >" + g_loc_end + g_loc_colon + "</span>" + 
									"</th>" + 
									"<td>" + 
										"<span class='rpt-endtime'>" + 
											"<input id='rpt-end-no' type='radio' name='endtime'/>" + 
											"<label for='rpt-end-no'>" + g_loc_never + "</label>" + 
										"</span>" + 
										"<span class='rpt-endtime'>" + 
											"<input id='rpt-end' type='radio' name='endtime'>" +
											"<label for='rpt-end'>" + 
												g_loc_on + " " + 
												"<input id='rpt-end-val' type='text'/>" + 
											"</lable>" +  
										"</span>" + 
									"</td>" + 
								"</tr>" + 	
								"<tr >" + 
									"<th class='rpt-sum'>" + 
										"<span class='fc-font'>" + g_loc_summary + g_loc_colon + "</span>" + 
									"</th>" + 
									"<td class='rpt-sum'>" + 
										"<span class='fc-font' id='rpt-sum-content'></span>" +
									"</td>" + 
								"</tr>" + 			
							"<tbody>" + 
						"</table>" + 
					"</div>" + 
					"<div id='rpt-bottom'>" + 
						"<span class='fc-button'><span id='rpt-ok' class='fc-button-content'>" + g_loc_done + "</span></span>" + 
						"   <span class='fc-button'><span id='rpt-cancel' class='fc-button-content'>" + g_loc_cancel + "</span></span>" + 
					"</div>" + 
				"</div>";

		return html;
	}
	function getLunarDate(date){
		var objChineseCal = new ChineseCalendar(date);
		var chineseStr = objChineseCal.solarDay2();

		return chineseStr;
	}
	function getRepeatIndex(rptVal){
		var info = [[g_loc_chineseyearly, 'ChineseYearly'],
					[g_loc_chinesemonthly , 'ChineseMonthly'],
					[g_loc_yearly, 'Yearly'],
					[g_lod_monthly, 'Monthly'],
					[g_loc_everyweek, 'Weekly'],
					[g_loc_everyweekday67, 'EveryWeekday67'],
					[g_loc_everyweekday24, 'EveryWeekday24'],
					[g_loc_everyweekday135, 'EveryWeekday135'], 
					[g_loc_everyweekday, 'EveryWeekday'],
					[g_loc_daily, 'Daily']
				];
		for (var i = 0; i < info.length; i ++){
			if (rptVal == info[i][1]){
				return info.length - (i + 1);
			}
		}
		return 5;// "Weekly".
	}
	function getBubbleCenterCoordinate($bubble){
		var pageWidth = getBodyWidth();
		var pageHeight = getBodyHeight();
		var center = {};
		center.left = pageWidth / 2 - _removeStrPx($bubble.css("width")) / 2;
		center.top = pageHeight / 2 - _removeStrPx($bubble.css("height")) / 2;
		return center;
	}	
	function setRepeatRule(beg, flag){
		var $main = $('#rpt-main');
		var $rptrpt;
		var $rptFre;
		// 给time定义一个class，$('.class')就可以选择到所有的DOM对象
		var $rptTime;
		var $rptTime1;
		var $rptTime2;
		var $rptTime3;
		var $rptTime4;
		var $rptTime5;
		var $rptTime6;
		var $rptTime7;
		var $rptBeg;
		var $rptEnd;
		var $rptEndVal;
		var $rptEndno;
		var $rptSum;
		var $close;
		var $ok;
		var $cancel;
		var week = [g_loc_dayname_0, g_loc_dayname_1, g_loc_dayname_2, g_loc_dayname_3, g_loc_dayname_4, g_loc_dayname_5, g_loc_dayname_6];
		var objRptTime = new Array();
		g_rptFlag = flag;
		if ($main.length == 0){
			var html = getRepeateHtml();
			$(document.body).append(html);
			$main = $('#rpt-main');
			$close = $('#rpt-close');
			$rptrpt = $('#rpt-rpt');
			$rptFre = $('#rpt-fre');
			$rptTime = $('#rpt-tiem');
			$rptTime1 =$('#rpt-time-1');
			$rptTime2 =$('#rpt-time-2');
			$rptTime3 =$('#rpt-time-3');
			$rptTime4 =$('#rpt-time-4');
			$rptTime5 =$('#rpt-time-5');
			$rptTime6 =$('#rpt-time-6');
			$rptTime7 =$('#rpt-time-7');
			$rptBeg = $('#rpt-beg');
			$rptEnd = $('#rpt-end');
			$rptEndVal = $('#rpt-end-val');
			$rptEndno = $('#rpt-end-no');
			$rptSum = $('#rpt-sum-content');
			$ok = $('#rpt-ok');
			$cancel = $('#rpt-cancel');
			objRptTime[0] = $rptTime7;
			objRptTime[1] = $rptTime1;
			objRptTime[2] = $rptTime2;
			objRptTime[3] = $rptTime3;
			objRptTime[4] = $rptTime4;
			objRptTime[5] = $rptTime5;
			objRptTime[6] = $rptTime6;




			$main.draggable();
			$rptEndVal.click(function(){
				if ($rptEndVal.attr("readonly") == "readonly"){
					$rptEndVal.css("backgroundColor", "white");
					$rptEndVal[0].readOnly = false;
					$rptEnd.attr("checked", "checked");
					var now = new Date();
					$rptEndVal[0].value = _d2s(now).substr(0, 10);
				}
			});
			$rptEnd.click(function(){
				$rptEndVal.css("backgroundColor", "white");
				$rptEndVal[0].readOnly = false;
				// wtl calendar has a bug ,if create a event after today,
				// time of end repeat also be set today.
				var now = new Date();
				$rptEndVal[0].value = _d2s(now).substr(0, 10); 
			});
			$rptEndno.click(function(){
				$rptEndVal.css("backgroundColor", "#EBEBE4");
				$rptEndVal[0].value = "";
				$rptEndVal.attr("readonly", "readonly");
			});
			wizCreateDatepicker($rptEndVal); 
			// 
			var _getWeeklyRuleSum = function(ret){
				var rule;
				var summary;
				var index = $rptrpt[0].selectedIndex;
				var rptText = $rptrpt[0].options[index].text;
				
				if ($rptrpt[0].value == "Weekly"){
					// should define global var
					summary = g_loc_everyweek + " ";
					rule = "EveryWeek";
					for (var i = 0; i < 7; i ++){
						if(objRptTime[i].attr("checked") == "checked"){
							
							if (i == 0){
								rule += 7;
							}else {
								rule += i;
							}
							summary += week[i] + '、';
						}
					}
					summary = summary.substr(0, summary.length-1);
				}else {
					rule = $rptrpt[0].value;
					summary = rptText;
				}
				ret.rule = rule;
				ret.summary = summary;	
			}
			$rptrpt.change(function(){
				if ($rptrpt[0].value != "Weekly"){
					// 耦合度比较大，依赖标签的display属性
					$rptTime.css("display", "none");
				}else {
					$rptTime.css("display", "table-row");
				}
				//
				if ($rptrpt[0].value.indexOf("Chinese") != -1){
					var begDate = _s2d(beg + " 00:00:00");
					var text = getLunarDate(begDate);
					text = '（' + text.replace("农历", "") + '）';
					var $begLunar = $("#rpt-beg-lunar");
					$begLunar.html(text);
					$begLunar.css("display", "inline");
				}else {
					var $begLunar = $("#rpt-beg-lunar");
					$begLunar.css("display", "none");
				}

				var obj = new Object();
				_getWeeklyRuleSum(obj);
				$rptSum.html(obj.summary);
				delete obj;
			});

			var timeClick = function(){
				var obj = new Object();
				_getWeeklyRuleSum(obj);

				$rptSum.html(obj.summary);
			}
			// TODO： 用$来取
			for (var i = 0; i < 7; i ++){
				objRptTime[i].click(function(){ timeClick(); });
			}

			var cancel = function(){
				if (g_rptFlag != "modify"){
					g_rptRule = '';
					g_rptSummary = '';
					g_rptEnd = '';
					$fc_rpt[0].checked = false;
				}
				$main.css('visibility', 'hidden');
				hiddenBubbleBg();
			}
			$close.click(function(){
				cancel();
			});
			$cancel.click(function(){
				cancel();
			});
			$ok.click(function(){
				$main.css("visibility", "hidden");
				hiddenBubbleBg();
				$('#fc-rpt-lb').html(g_loc_repeat + g_loc_colon);
				$fc_rptModify.css("display", "inline");
				$('#fc-rpt-value').css("display", "inline");		
				// 
				g_rptEnd = $rptEndVal.val();
				g_rptrptIndex = $rptrpt[0].selectedIndex;
				//
				var obj = new Object();
				_getWeeklyRuleSum(obj);
				g_rptRule = obj.rule;
				g_rptSummary = obj.summary;

				$('#fc-rpt-value').html(g_rptSummary);
			});
		}
		
		$main = $('#rpt-main');
		$close = $('#rpt-close');
		$rptrpt = $('#rpt-rpt');
		$rptFre = $('#rpt-fre');
		$rptTime = $('#rpt-tiem');
		$rptTime1 =$('#rpt-time-1');
		$rptTime2 =$('#rpt-time-2');
		$rptTime3 =$('#rpt-time-3');
		$rptTime4 =$('#rpt-time-4');
		$rptTime5 =$('#rpt-time-5');
		$rptTime6 =$('#rpt-time-6');
		$rptTime7 =$('#rpt-time-7');
		$rptBeg = $('#rpt-beg');
		$rptEnd = $('#rpt-end');
		$rptEndVal = $('#rpt-end-val');
		$rptEndno = $('#rpt-end-no');
		$rptSum = $('#rpt-sum-content');
		objRptTime[0] = $rptTime7;
		objRptTime[1] = $rptTime1;
		objRptTime[2] = $rptTime2;
		objRptTime[3] = $rptTime3;
		objRptTime[4] = $rptTime4;
		objRptTime[5] = $rptTime5;
		objRptTime[6] = $rptTime6;
		
		$rptBeg.attr("readonly", "readonly");
		$rptBeg.css("backgroundColor", "#EBEBE4");
		$rptBeg.val(beg);

		$("#rpt-beg-lunar").css("display", "none");


		$rptEndVal.css("backgroundColor", "#EBEBE4");
		$rptEndVal.attr("readonly", "readonly");
		$rptEndVal[0].value = '';

		// 
		setfrequencyInfo($rptFre[0]);
		//
		g_rptrptIndex = getRepeatIndex(getEventRepeatBaseRule());
		setRepeatInfo($rptrpt[0], g_rptrptIndex);

		//
		if (g_rptEnd == '')
			$rptEndno.attr("checked", "checked");
		else {
			$rptEnd.attr("checked", "checked");
			$rptEndVal[0].value = g_rptEnd.substr(0, 10);
		}
		// TODO: 
		for (var i = 0; i < 7; i ++){
			objRptTime[i][0].checked = false;
		}
		// TODO: 
		if (flag == "create"){
			var sD = _s2d(beg+" 00:00:00");
			objRptTime[sD.getDay()].attr("checked", "checked");
		}
		// hard coded
		if (g_rptrptIndex == 5){
			$rptTime.css('display', 'table-row');
		}else {
			$rptTime.css('display', 'none');
		}
		if (flag == "modify"){
			// TODO: "EveryWeek" 
			if (g_rptRule.indexOf("EveryWeek") != -1 && g_rptRule.indexOf("EveryWeekday") == -1){
				var days = g_rptRule.substr("EveryWeek".length).split('');
				for (var i = 0; i < days.length; i ++){
					objRptTime[days[i]%7].attr("checked", "checked");
				}
			} 
			else {
				// 
			}
		}
		if (flag == "create"){
			// first hard coded
			var sD = _s2d(beg + " 00:00:00");

			g_rptRule = "EveryWeek" + sD.getDay();

			g_rptSummary = g_loc_everyweek;

			if (flag == "create")
				g_rptSummary += ' ' + week[sD.getDay()];
		}

		$rptSum.html(g_rptSummary);
		//
		var center = getBubbleCenterCoordinate($main);
		$main.css({'visibility': 'visible', left: center.left, top: 100});

		// reserve frequency
		$('#rpt-fre-row').css("display", "none");
	}
	function setRemindInfo(remind, remindVal){
		// TODO: localize
		var info = [
					[g_loc_remind_twoweeks, '1209600'],
					[g_loc_remind_oneweek, '604800'], 
					[g_loc_remind_twodays, '172800'], 
					[g_loc_remind_oneday, '86400'], 
					[g_loc_remind_halfaday, '43200'], 
					[g_loc_remind_twohours , '7200'], 
					[g_loc_remind_onehour, '3600'],
					[g_loc_remind_fortyfive, '2700'],
					[g_loc_remind_thirty, '1800'],
					[g_loc_remind_fifteen, '900'],
					[g_loc_remind_ten, '600'],
					[g_loc_remind_five, '300'],
					[g_loc_remind_noahead, '0'],
					[g_loc_remind_noremind , '-1']
				];
		var remindIndex = 0;
		if (remindVal){
			for (var i = 0; i < info.length; i++) {
				if (info[i][1] == remindVal){
					remindIndex = info.length - i - 1;
					break;
				}
			}
		}
		remind.length = 0;
		for (var i in info){
			var opt = new Option(info[i][0], info[i][1]);
			remind.options.add(opt, 0);
		}
		remind[remindIndex].selected = 'selected';
	}
	function setBegEndTime(t, time){
		// TODO: 全天事件的结束时间需要调整。
		var info = ['23:30', '23:00', '22:30', '22:00', '21:30', '21:00', '20:30', '20:00', 
					'19:30', '19:00', '18:30', '18:00', '17:30', '17:00', '16:30', '16:00', 
					'15:30', '15:00', '14:30', '14:00', '13:30', '13:00', '12:30', '12:00', 
					'11:30', '11:00', '10:30', '10:00', '09:30', '09:00', '08:30', '08:00',
					'07:30', '07:00', '06:30', '06:00', '05:30', '05:00', '04:30', '04:00',
					'03:30', '03:00', '02:30', '02:00', '01:30', '01:00', '00:30', '00:00', ];

		t.length = 0;

		for (var i in info){
			var opt = new Option(info[i], info[i]);
			t.options.add(opt, 0);
		}
		var tt = time.split('');

		var i = (+(tt[0])*10 + +(tt[1]))*2;
		i += +(tt[3]) > 0 ? 1 : 0;
		t[i].selected = 'selected';
	}
	function setfrequencyInfo(fre){
		fre.length = 0;
		for (var i = 30; i > 0; i --){
			var opt = new Option(i, i);
			fre.options.add(opt, 0);
		}
		fre[0].selected = 'selected';	
	}
	function setRepeatInfo(rpt, sel){
		var info = [[g_loc_chineseyearly, 'ChineseYearly'],
					[g_loc_chinesemonthly , 'ChineseMonthly'],
					[g_loc_yearly, 'Yearly'],
					[g_lod_monthly, 'Monthly'],
					[g_loc_everyweek, 'Weekly'],
					[g_loc_everyweekday67, 'EveryWeekday67'],
					[g_loc_everyweekday24, 'EveryWeekday24'],
					[g_loc_everyweekday135, 'EveryWeekday135'], 
					[g_loc_everyweekday, 'EveryWeekday'],
					[g_loc_daily, 'Daily']
				];		
		rpt.length = 0;
		for (var i in info){
			var opt = new Option(info[i][0], info[i][1]);
			rpt.options.add(opt, 0);
		}
		rpt[sel].selected = 'selected';

	}
	var g_createStart;
    var g_createEnd;
    var g_createFlag;
    var g_createObjEvent;
    var g_createCallBack;
    function createDefaultEvent(start, stop, title, defaultColor){
    	if (!g_db)
    		return;
    	var now = new Date(start);
    	var month = formatIntToDateString(now.getMonth() + 1);
    	var location = 'My Events/' + now.getFullYear() + '-' + month + '/';
  		
  		var objFolder = g_db.GetFolderByLocation(location, true);
  		var tempHtml = g_cmn.GetATempFileName('.html');
  		var htmlText = getEventHtml(title, '');
   		g_cmn.SaveTextToFile(tempHtml, htmlText, 'unicode');
  		var doc = objFolder.CreateDocument2(title, "");
  		doc.ChangeTitleAndFileName(title);
  		doc.UpdateDocument6(tempHtml, tempHtml, 0x22);

  		doc.AddToCalendar(_d2s(start), _d2s(stop), "b=" + defaultColor + "/r=-1/c=0");
  		// change database
  		doc.type = "event";
  		
  		return doc;
    }
	var $fc_title;
	var $fc_beg;
	var $fc_beg2;
	var $fc_end;
	var $fc_end2;
	// var $fc_color;
	var $fc_remind;
	var $fc_recur;
	var $fc_restop;
	var $fc_rechk;
	var $fc_content;
	var $fc_ok;
	var $fc_cancel;
	var $fc_close;
	var $fc_save;
	var $fc_allDchk;
	var $fc_rptModify;
	var $fc_giveup;
	var $fc_delete;
	var $fc_rpt;
	var g_fullCreateFlag;
	var g_rptRule = '';
	var g_rptSummary = '';
	var g_rptEnd = '';
	var g_rptFlag = '';
	var g_rptrptIndex = 5;
	var g_fcDoc;
	var g_remind;
	function _initEventRepeatInfo(value){
		var info = [[g_loc_chineseyearly, 'ChineseYearly'],
					[g_loc_chinesemonthly , 'ChineseMonthly'],
					[g_loc_yearly, 'Yearly'],
					[g_lod_monthly, 'Monthly'],
					[g_loc_everyweek, 'Weekly'],
					[g_loc_everyweekday67, 'EveryWeekday67'],
					[g_loc_everyweekday24, 'EveryWeekday24'],
					[g_loc_everyweekday135, 'EveryWeekday135'], 
					[g_loc_everyweekday, 'EveryWeekday'],
					[g_loc_daily, 'Daily']
				];
		var text;
		for (var i = 0; i < info.length; i ++){
			if (value == info[i][1]){
				text = info[i][0];
				break;
			}
		}
		// TODO: 
		var week = [g_loc_dayname_1, g_loc_dayname_2, g_loc_dayname_3, g_loc_dayname_4, g_loc_dayname_5, g_loc_dayname_6, g_loc_dayname_0];
		
		var DAYS_BEGIN;
		if (value != "EveryWeekday"){
			if (value.indexOf("EveryWeekday") != -1){
				DAYS_BEGIN = ("EveryWeekday").length;
			}else if (value.indexOf("EveryWeek") != -1){
				DAYS_BEGIN = ("EveryWeek").length;
			}
		}

		if (value.indexOf("EveryWeek") != -1 && value != "EveryWeekday"){
			var rule = value.substr(DAYS_BEGIN).split('');
			// 
			rule.sort().toString().replace(/,/gi,"");
			text = g_loc_everyweek + " ";
			for (var i = 0; i < rule.length; i ++){
				text += week[Number(rule[i])-1] + '、';
			}
			text = text.substr(0, text.length-1);
		}
		g_rptSummary = text;
		g_rptRule = value;

		return g_rptSummary;
	}
	function getDocText(doc){
		if (!doc)
			return "";
		var text;
		try{
			text = doc.GetText(0);
		}catch(err){
			toLog("doc.GetText(0) error.");
			return "";
		}
		
		return text = text.replace('\r\n', '');
	}
	function colorSquare(colorId){
		return $("#fc-color" + colorId);
	}
	function setCreateOrModifyColorStatus(prevColorId, curColorId){
		if (prevColorId != -1){
			$prevColor = $("#fc-color" + prevColorId);
			$prevColor.children(".fc-to-select").removeClass("ecs-selected");
		}
		$colorSquare = colorSquare(curColorId);
		if ($colorSquare.length != 0){
			$colorSquare.children(".fc-to-select").addClass("ecs-selected");
			return true;
		}else {
			return false;
		}
	}
	function InitColorSetStatus(prevColorId, curColorId){
		setCurrentColorId(curColorId);
		setCreateOrModifyColorStatus(prevColorId, curColorId);
	}
	function _getEventRepeatSummary(doc){

	}
	var g_rptBaseRule;
	function getEventRepeatBaseRule(){
		return g_rptBaseRule;
	}
	function setEventRepeatBaseRule(baseRule){
		g_rptBaseRule = baseRule;
	}
	function _createFullEventInit(start, end, title, allDay, doc){
		// 
		if (!title){
			$fc_title.css({"color":"#888"});
			$fc_title.val(g_loc_untitled);

		}else {
			$fc_title.unbind("click");
			$fc_title.css({"color":"black"});
			$fc_title[0].value = title;
			// TODO: focus the end of text
			setCaretToPos($fc_title[0], $fc_title.val().length);
			$fc_title.focus();
		}
		$fc_title.unbind("click").bind("click", function(){
			if ($fc_title.val() == g_loc_untitled){
				$fc_title.val("");	
			}
			
			$fc_title.css({"color":"black"});
		});
		var test2 = document.getElementById('fc-title');
		
		$fc_save[0].disabled = false;
		//
		$fc_beg[0].value = start.substr(0, 10);
		setBegEndTime($fc_beg2[0], start.substr(11, 5));
		$fc_end[0].value = end.substr(0, 10);
		setBegEndTime($fc_end2[0], end.substr(11, 5));

		setRemindInfo($fc_remind[0]);
		// 
		$fc_beg.attr("readonly", "readonly");
		$fc_end.attr("readonly", "readonly");
		// $fc_color.attr("readonly", "readonly");
		if (allDay == true || (allDay == "true")){

			$('#fc-beg2').css('display', 'none');
			$('#fc-end2').css('display', 'none');
			$('#fc-dp-alld').attr('checked', true);
		}
		// 
		$fc_rptModify.css("display", "none");
		var info;
		var rpt;
		var endrpt;
		var isfromdocument;
		if (doc){
		    info = doc.ParamValue('CALENDAR_INFO');
			rpt = doc.ParamValue('CALENDAR_RECURRENCE');

			setEventRepeatBaseRule(rpt);

			endrpt = doc.ParamValue('CALENDAR_ENDRECURRENCE');
			g_fcDoc = doc;
			remind = _getRemindFromInfo(info);
			$fc_tagVal[0].value = doc.TagsText;
		    //
			isfromdocument = _getdocumentflagFromInfo(info);

		}else {
			$fc_tagVal[0].value = $("#dc-tag").val();
		}

		$fc_selectTag = $('#fc-tag-selectVal');
		addPureTags($fc_selectTag[0]);
		$fc_selectTag[0].selectedIndex = -1;

		if (g_fullCreateFlag == "create"){
			$fc_giveup.parent().css("display", "none");
			$fc_delete.parent().css("display", "none");
			$fc_cancel.parent().css("display", "inline-block");

			var prevColorId = getCurrentColorId();
			InitColorSetStatus(prevColorId, 0);
			// $fc_color[0].value = '#D5F8DD';
			// $fc_color.css('backgroundColor', $fc_color[0].value);
			// $fc_color.miniColors('value', $fc_color[0].value);	
			$fc_content.val("");
			$fc_rptModify.css("display", "none");
			$('#fc-rpt-value').html("");
			$('#fc-rpt-lb').html(g_loc_repeat + "...");
			$fc_rpt[0].checked = false;

		}else {
			$fc_giveup.parent().css("display", "inline-block");
			$fc_delete.parent().css("display", "inline-block");
			$fc_cancel.parent().css("display", "none");

			if (isfromdocument == true || isfromdocument == "true")
			{
			    $fc_content.attr("disabled", true);
			}
			else {
			    $fc_content.attr("disabled", false);
			}
			//
		    $fc_content.val(getDocText(doc));
			// 
			var prevColorId = getCurrentColorId();
			var info = _getDocInfo(doc);
			var curColorId = _getEventColorIdFromInfo(info);
			if (!curColorId)
				curColorId = 0;

			InitColorSetStatus(prevColorId, curColorId);

			// $fc_color[0].value = '#' + info.substr(2, 6);
			// $fc_color.css('backgroundColor', $fc_color[0].value);
			// $fc_color.miniColors('value', $fc_color[0].value);
			if (rpt){
				$fc_rptModify.css("display", "inline-block");
				$fc_rpt.attr("checked", "checked");
				_initEventRepeatInfo(rpt);
				g_rptEnd = endrpt;
				$('#fc-rpt-value').html(g_rptSummary);
				$('#fc-rpt-lb').html(g_loc_repeat + g_loc_colon);
			}else {
				$fc_rptModify.css("display", "none");
				$('#fc-rpt-value').html("");
				$('#fc-rpt-lb').html(g_loc_repeat + "...");
				$fc_rpt[0].checked = false;
			}
			setRemindInfo($fc_remind[0], remind);
		}
	}
	function _currentEventInfo(oldInfo, newColor, newRemind, newComplete, newColorId){
		var arr = oldInfo.split('/');
		//
		var hasColorId = false;
		for(var i = 0; i < arr.length; i++){
			if(arr[i].indexOf("b=") != -1){
				arr[i] = arr[i].substr(0, 2) + (newColor ? newColor.replace("#", '') : arr[i].substr(2));
			}else if(arr[i].indexOf("r=") != -1){
				arr[i] = arr[i].substr(0, 2) + (newRemind ? newRemind : arr[i].substr(2));
			}else if(arr[i].indexOf("c=") != -1){
				arr[i] = arr[i].substr(0, 2) + (newComplete ? 1 : 0);
			}else if(arr[i].indexOf("ci=") != -1){
				arr[i] = arr[i].substr(0, 3) + (newColorId ? newColorId : arr[i].substr(3));
				hasColorId = true;
			}
		}
		//
		if(!hasColorId){
			arr.push("ci=" + (newColorId ? newColorId : 0));
		}
		//
		return arr.join('/');
	}
	function _isReminderEventComplete(start, remind){
		var now = new Date();
		if (now.getTime() > (start.getTime() - remind*60)){
			return true;
		}else {
			return false;
		}
	}
	function getOriginalWizTag(doc){
		var tagSet = doc.TagsText;
		if (!tagSet){
			return "";
		}
		if (tagSet.indexOf(WIZ_GOOGLE_CALENDAR_TAG) == -1){
			return tagSet;
		}
		var tagArray = tagSet.split(';');
		for (var i in tagArray){
			if (tagArray[i].indexOf(WIZ_GOOGLE_CALENDAR_TAG) != -1){
				tagArray.splice(tagArray[i].indexOf(WIZ_GOOGLE_CALENDAR_TAG), 1);
				return tagArray.join(';');
			}
		}
	}
	function makeWizTag(doc, GoogleTag){
		var wizTag = getOriginalWizTag(doc);
		if (wizTag){
			wizTag += ";" + GoogleTag;
			return wizTag;
		}else {
			return GoogleTag;
		}
	}
	function wizUpdateEvent(doc, eventResource){
		if (!doc || (!eventResource)){
			return;
		}
		setParamValue(doc, "CALENDAR_START", eventResource.start);
		setParamValue(doc, "CALENDAR_END", eventResource.end);
		doc.Title = eventResource.title;

		if (eventResource.rptRule){
			setParamValue(doc, "CALENDAR_RECURRENCE", eventResource.rptRule);
			if (eventResource.rptEnd){
				var now = new Date();
				setParamValue(doc, "CALENDAR_ENDRECURRENCE", eventResource.rptEnd + _d2s(now).substr(10));
			}
		}else {
			setParamValue(doc, "CALENDAR_RECURRENCE", '');
			setParamValue(doc, "CALENDAR_ENDRECURRENCE", '');
		}
		if (eventResource.tag){
			var wizTag = makeWizTag(doc, eventResource.tag);
			if (wizTag){
				doc.SetTagsText2(wizTag, "Calendar");
			}else {
				toLog("wizUpdateEvent makeWizTag wizTag failed.");
			}
		}
		var oldInfo = doc.ParamValue('CALENDAR_INFO');
		var complete = _isReminderEventComplete(_s2d(eventResource.start), eventResource.remind);
		var curInfo = _currentEventInfo(oldInfo, eventResource.color, eventResource.remind, complete, eventResource.colorId);
        //
		setParamValue(doc, "CALENDAR_INFO", curInfo);
        //
		var isFromDocument = _getdocumentflagFromInfo(curInfo);
		if ((!eventResource.id || doc.ParamValue('CALENDAR_SOURCE') != 'ADD_TO_CALENDAR')
            && (isFromDocument != true || isFromDocument != "true")) {
		    var eventHtml = getEventHtml(eventResource.title, eventResource.content);
			doc.UpdateDocument3(eventHtml, 0);
		}
		// for google
		if (eventResource.id){
			setParamValue(doc, "CALENDAR_GOOEVENTID", eventResource.id);
			
		}
		// revise updated date
		if (eventResource.updated)
			doc.DateModified = eventResource.updated;
	}
	function wizCreateFullEventTest(eventResource){
		//alert("wizCreateFullEventTest");
		var doc;
		// TODO: 应修改成createDefaultEvent(eventResource);
		doc = createDefaultEvent(_s2d(eventResource.start), _s2d(eventResource.end), eventResource.title, eventResource.color.replace("#", ""));
		// for google TODO: 这个东西先放这。
		if (eventResource.id && doc){
			setParamValue(doc, "CALENDAR_SOURCE", "GOOGLE");
		}
		wizUpdateEvent(doc, eventResource);
		return doc;
	}
	function wizCreateFullEvent(createFlag, gDoc, beg, end, title, color, rptRule, rptEnd, content, remind, eventTag, colorId){
			var doc;
			if (createFlag == "modify")
				doc = gDoc;
			else
				doc = createDefaultEvent(_s2d(beg), _s2d(end), title, color);
			if (createFlag == "modify"){
				setParamValue(doc, "CALENDAR_START", beg);
				setParamValue(doc, "CALENDAR_END", end);
			}
			if (rptRule){
				setParamValue(doc, "CALENDAR_RECURRENCE", rptRule);
				if (rptEnd){
					var now = new Date();
					setParamValue(doc, "CALENDAR_ENDRECURRENCE", rptEnd + _d2s(now).substr(10));
				}
			}else {
				setParamValue(doc, "CALENDAR_RECURRENCE", '');
				setParamValue(doc, "CALENDAR_ENDRECURRENCE", '');
			}
			doc.SetTagsText2(eventTag, "Calendar");

			var oldInfo = doc.ParamValue('CALENDAR_INFO');
			var curInfo = oldInfo.substr(0, 2) + color + 
						  oldInfo.substr(8, 3) + remind + 
						  "/c=0";
			curInfo += "/ci=" + colorId;

			var isFromDocument = _getdocumentflagFromInfo(oldInfo);
			if (isFromDocument == true || isFromDocument == "true")
			{
			    curInfo += "/fd=" + isFromDocument;
			}
			setParamValue(doc, "CALENDAR_INFO", curInfo);
			//
			content = content.replace(/[\n]/ig, '<br/>');
			content = content.replace(/[ ]/ig, '&nbsp;');

			var eventHtml = getEventHtml(title, content);
			
			isFromDocument = _getdocumentflagFromInfo(curInfo);
			if (isFromDocument != true && isFromDocument != "true")
			{
			    doc.UpdateDocument3(eventHtml, 0);
			}
			//
			doc.Title = title;
			return doc;
	}
    function _createFullEvent(start, end, title, allDay, flag, doc){
    	g_fullCreateFlag = flag;
		_createFullEventInit(start, end, title, allDay, doc);

    }
 	function _getDefaultEventHtml(){
		var html = 
			"<div id='defaultcreate'>" + 
				"<div id='dc-prong3'></div>" + 
				"<div id='dc-prong4'></div>" + 
				"<div id='dc-close'/>" + 
				"<div id='dc-main'>" + 
				"<div>" + 
					"<table id='dc-t'>" + 
						"<tbody>" + 
							"<tr>" + 
								"<th class='dc-font'>" + g_loc_when + g_loc_colon + "</th>" +
								"<td>" +
									"<span id='dc-time'></span>" + 
								"</td>" + 
							"</tr>" +
							"<tr>" + 
								"<th  class='dc-font'>" + g_loc_what + g_loc_colon + "</th>" +
								"<td>" +
									"<div>" + 
										"<div>" +  
											"<input id='dc-title' type='text'/>" + 
										"</div>" + 
									"</div>" + 
								"</td>" + 
							"</tr>" +
							"<tr>" + 
								"<th class='dc-font'>" + g_loc_tag + g_loc_colon + "</th>" + 
								"<td>" +
									"<input id='dc-tag' type='text'/>" + 
								"</td>" + 
							"</tr>" + 
							"<tr>" + 
								"<td>" +
									"<span class='fc-button'><span id='dc-create' class='fc-button-content'>" + g_loc_createevent + "</span></span>" + 
									"<span id='dc-details' class='dc-font'>" + g_loc_edit + " »</span>" + 
								"</td>" + 
							"</tr>" +													
						"</tbody>" + 
					"</table>" + 
				"</div>" + 
				"<div id='dc-prong1'></div>" + 
				"<div id='dc-prong2'></div>" + 
			"</div>";

		return html;
	}
	function _getBubblePageCoordinate(ev, coo, prongWidth, bubbleWidth, bubbleHeight, defaultProngRight, defaultProngTop){
		var width = document.documentElement.clientWidth;
		var height = document.documentElement.clientHeight;
		// right overflow
		if ((width - ev.pageX - prongWidth) < defaultProngRight){
			coo.right = width - 5 - ev.pageX - prongWidth;
		}else {
			coo.right = defaultProngRight;
		}
		var defaultProngLeft = bubbleWidth - defaultProngRight - 2*prongWidth;
		// left overflow
		if (ev.pageX - defaultProngLeft - prongWidth < 0){
			var left = ev.pageX - 5 - prongWidth;
			coo.right = bubbleWidth - left - 2*prongWidth;
		}

		if (ev.pageY < (bubbleHeight+prongWidth + 5)){
			coo.top = -1;
		}else {
			coo.top = defaultProngTop;
		}
		coo.x = ev.pageX - (bubbleWidth - coo.right - prongWidth + 1);
		if (coo.top < 0){
			coo.y= ev.pageY + prongWidth;
		}else {
			coo.y= ev.pageY - (bubbleHeight + prongWidth + 2);
		}
	}
	function getClickRect($ele){
		var left = $ele[0].offsetLeft;
		var right = $ele[0].offsetLeft + $ele[0].clientWidth;
		var top = $ele[0].offsetTop;
		var bottom = $ele[0].offsetTop + $ele[0].clientHeight;
		return {left: left, top: top, right: right, bottom: bottom};
	}	
	function isClickOnBubblePage(e, $ele){

		if ($ele && $ele.css("visibility") == "visible"){

			var rect = getClickRect($ele);

			if ((rect.left <= e.pageX && e.pageX <= rect.right) &&
				(rect.top <= e.pageY && e.pageY <= rect.bottom) 
				)
			{
				return true;
			}

		}
		return false;
	}

	function hiddenBubblePage(e, $ele){
		if (!isClickOnBubblePage(e, $ele)){
			$ele.css("visibility", "hidden");
		}
	}
	function wizAddBodyMousedownEvent(){
		$(document).mousedown(function(e){
			var $dcMain = $('#defaultcreate');
			hiddenBubblePage(e, $dcMain);
			var $deMain = $('#defaultedit');
			hiddenBubblePage(e, $deMain);
		});	
	}
    function stopBubble(e) {
        //如果提供了事件对象，则这是一个非IE浏览器  
        if (e && e.stopPropagation) {
            //因此它支持W3C的stopPropagation()方法  
            e.stopPropagation();
        } else {
            //否则，我们需要使用IE的方式来取消事件冒泡
            window.event.cancelBubble = true;
        }
        return false;
   	}
	function wizAddFullCalendarMousedownEvent(){
		if (!g_cal)
			return;
		g_cal.mousedown(function(e){
			var $dcMain = $('#defaultcreate');
			if (isClickOnBubblePage(e, $dcMain)){
					stopBubble(e);
					return true;
			}
			var $deMain = $('#defaultedit');
			if (isClickOnBubblePage(e, $deMain)){
					stopBubble(e);
					return true;
			}
		});
	}
	function getCurrentTag(){
		var index = $('#wizTag')[0].selectedIndex;
		var tag;
		if (index != -1){
			tag = $('#wizTag')[0].options[index].value;
		}else {
			tag = "";
		}
		if (tag == g_loc_tagfilter_all){
			return "";
		}else {
			return tag;
		}
	}
	function createDefaultEventBubblePage(start, end, allDay, jsEvent){
		var $main = $('#defaultcreate');
		var $details;
		var $close;
		var $create;
		var $time;
		var $title;
		g_createStart = start;
		g_createEnd = end;
		g_allDay = allDay;

		if ($main.length == 0){
			//
			var html = _getDefaultEventHtml();

			g_cal.append(html);
			//
			$main = $('#defaultcreate');
			$details = $('#dc-details');
			$close = $('#dc-close');
			$create = $('#dc-create');
			$time = $('#dc-time');
			$title = $('#dc-title');
			// 
			$main.mousedown(function(e){
				stopBubble(e);
				return true;
			});
			$details.click(function(){
				$main.css("visibility", "hidden");
				// TODO: 检查title，不能是特殊符号'?' '&'等。
				g_cal.fullCalendar('unselect');
				g_calendarMain.css("display", "none");
				g_fullCreate.css("display", "block");

				_createFullEvent(_d2s(g_createStart), _d2s(g_createEnd), $title[0].value, g_allDay, "create");
				
				return false;
			});
			$close.mousedown(function(e){
				$main.css("visibility", "hidden");
				g_cal.fullCalendar('unselect');
			});
			$create.click(function(){
				// // first render events have many bugs.
				var title = $title[0].value ? $title[0].value : g_loc_notitle;
				// _renderEventBeforeCreate(guid, g_createStart, g_createEnd, title, "D5F8DD", '', '', g_allDay, 'black');
				// $main.css("visibility", "hidden");
				// g_cal.fullCalendar('unselect');
				// //
				// g_createCallBack = setTimeout(function(){ createDefaultEvent(g_createStart, g_createEnd, title, 'D5F8DD'); }, 500);
				var doc = createDefaultEvent(g_createStart, g_createEnd, title, 'D5F8DD');
				//
				if ($("#dc-tag").val())
					doc.SetTagsText2($("#dc-tag").val(), "Calendar");

				_setEventColorId(0, doc);

				_renderDocEvent(doc);
				wizUpdateLayout();
				$("#dc-tag").val("");
				$main.css("visibility", "hidden");
				g_cal.fullCalendar('unselect');

				//
				// TODO: guid, 名字完全一样的时候，不会显示出来。, 
				// var event = g_cal.fullCalendar('clientEvents', guid);
				// event[0].title = 'abcaaaa';
				// g_cal.fullCalendar('updateEvent', event[0]);

			});
			$details.mouseover(function(){
				$(this).css("textDecoration", "underline");
			}).mouseout(function(){
				$(this).css("textDecoration", "none");
			});
		}

		$details = $('#dc-details');
		$close = $('#dc-close');
		$create = $('#dc-create');
		$time = $('#dc-time');
		$title = $('#dc-title');
		$prong1 = $('#dc-prong1');
		$prong2 = $('#dc-prong2');
		$prong3 = $('#dc-prong3');
		$prong4 = $('#dc-prong4');
		//
		$time.html(getTimeStr(start, end));
		$title[0].value ="";
		//
		$(document).one('mousedown', function(){
			$main.css("visibility", "hidden");
		});
		//
		var prongWidth = _removeStrPx($prong1.css("border-left-width"));
		var bubbleWidth = _removeStrPx($main.css("width"));
		var bubbleHeight = _removeStrPx($main.css("height"));

		var defaultProngRight = 179;
		var defaultProngTop = 174;	
		var coo = new Object();
		if (g_cal.fullCalendar("getView").name == "month"){
			_getBubblePageCoordinate(jsEvent, coo, prongWidth, bubbleWidth, bubbleHeight, defaultProngRight, defaultProngTop);
		}else {
			var tEvent = new Object();
			tEvent.pageX = jsEvent.pageX;// - jsEvent.offsetX;
			tEvent.pageY = jsEvent.pageY - jsEvent.offsetY;
			// TODO: jsEvent.offsetY have a low-probability bug equ. -1.
			_getBubblePageCoordinate(tEvent, coo, prongWidth, bubbleWidth, bubbleHeight, defaultProngRight, defaultProngTop);
		}
		if (coo.top > 0){
			$prong1.css("display", "block");
			$prong2.css("display", "block");
			$prong3.css("display", "none");
			$prong4.css("display", "none");
			$prong1.css("right", coo.right);
			$prong2.css("right", coo.right + 1);
		}else {
			$prong1.css("display", "none");
			$prong2.css("display", "none");
			$prong3.css("display", "block");
			$prong4.css("display", "block");
			$prong3.css("right", coo.right);	
			$prong4.css("right", coo.right + 1);		
		}

		$("#dc-tag").val(getCurrentTag());

		$main.css({"visibility": "visible", left: coo.x, top: coo.y});

		$title.focus();
	}
	function wizCreateEvent(startDate, endDate, allDay, jsEvent){
		var end = new Date(endDate);
		// database can not accept that start == end.
		if (allDay){
			end.setHours(23);
			end.setMinutes(59);
			end.setSeconds(59);
		}
		createDefaultEventBubblePage(startDate, end, allDay, jsEvent);
	}
	function _updateDocModifyDate(doc){
		var now = new Date();
		if (!doc)
			return;
		now.setSeconds((now.getSeconds() + 1) % 60);
		doc.DateModified = _d2s(now);
	}	
	function wizUpdateDocResize(event, dayDelta){
		var doc = g_db.DocumentFromGUID(event.id);
		var eventStart = doc.ParamValue('CALENDAR_START');
		var eventEnd;
		
		var curEndStr = _d2s(event.end);
		var eventEndDate = new Date(_s2d(eventStart));
		
		var interDays = _interDays(_d2s(event.start), _d2s(event.end));
		eventEndDate.setDate(eventEndDate.getDate() + interDays - 1);
		
		eventEnd = _d2s(eventEndDate);
		eventEnd = eventEnd.substr(0, 10) + ' ' + curEndStr.substr(11, 8);

		setParamValue(doc, "CALENDAR_END", eventEnd);

		_updateDocModifyDate(doc);
	}

	function wizUpdateDocDrop(event, dayDelta, minuteDelta, allDay){
 		var doc = g_db.DocumentFromGUID(event.id);
 		var eventStart = doc.ParamValue('CALENDAR_START');
 		var eventEnd = doc.ParamValue('CALENDAR_END');
 		
 		var eventStartDate = new Date(_s2d(eventStart));
 		var eventEndDate = new Date(_s2d(eventEnd));
 		eventStartDate.setDate(eventStartDate.getDate() + dayDelta);
 		eventStartDate.setMinutes(eventStartDate.getMinutes() + minuteDelta);

 		eventEndDate.setDate(eventEndDate.getDate() + dayDelta);
 		eventEndDate.setMinutes(eventEndDate.getMinutes() + minuteDelta);

 		if (allDay == true){
 			var startStr = _d2s(eventStartDate);
 			var endStr = _d2s(eventEndDate);
  			setParamValue(doc, "CALENDAR_START", startStr.substr(0, 10) + ' ' + "00:00:00");
  			setParamValue(doc, "CALENDAR_END", endStr.substr(0, 10) + ' ' + "23:59:59");
 		}else {
 			setParamValue(doc, "CALENDAR_START", _d2s(eventStartDate));
 			setParamValue(doc, "CALENDAR_END", _d2s(eventEndDate));	
 		}

 		// 
 		_updateDocModifyDate(doc);
	}
	function _getEditEventHtml(){
		var html = 
			"<div id='defaultedit'>" + 
				"<div id='de-prong3'></div>" + 
				"<div id='de-prong4'></div>" + 	
				"<div id='de-close'/>" + 
				"<div id='de-main'>" + 
					"<table id='de-table'>" + 
						"<tbody>" + 
						"<tr>" + 
							"<th>" + 
								"<div id='de-eventcolor'>" + 
									"<div id='de-dropdown-indicator'>" + 

									"</div>" + 
								"</div>" + 
							"</th>" + 
							"<td id='de-title-parent'>" + 
								"<div id='de-title'></div>" + 
							"</td>" + 
						"</tr>" + 
						"<tr>" + 
							"<td>" + 
								"<div id='de-tag'></div>" + 
							"</td>" + 
						"</tr>" + 
						"<tr>" + 
							"<td>" + 
								"<span id='de-time'></span>" + 
							"</td>" + 
							"<td>" + 
								"<span class='sperate-line'></span>" + 
							"</td>" + 
						"</tr>" + 
						"<tr id='de-action-parent'>" + 
							"<td>" + 
								"<span id='de-delete'>" + g_loc_delete + "</span>" + 
							"</td>" + 
							"<td>" + 
								"<span id='de-details'>" + g_loc_edit + " »</span>" + 
							"</td>" + 
						"</tr>" + 
						"<tbody>" + 
					"</table>" + 
				"</div>" + 
				"<div id='de-prong1'></div>" + 
				"<div id='de-prong2'></div>" + 
			"</div>";
		return html;
	}
	// TODO: reread here.
	var g_delGuid;
	var g_editCalEvent;	
	function setSelectionRange(input, selectionStart, selectionEnd) {
	  if (input.setSelectionRange) {
	    input.focus();
	    input.setSelectionRange(selectionStart, selectionEnd);
	  }
	  else if (input.createTextRange) {
	    var range = input.createTextRange();
	    range.collapse(true);
	    range.moveEnd('character', selectionEnd);
	    range.moveStart('character', selectionStart);
	    range.select();
	  }
	}

	function setCaretToPos (input, pos) {
	  setSelectionRange(input, pos, pos);
	}
	function getColorSetBubbleHtml(){
		var html = "<div id='eventcolorset'>" + 
						"<div>" + 
							"<div id='ecs-popup-tip'></div>" + 
							"<div id='ecs-lable'>" + 
								"<span>" + g_loc_chooseColor + g_loc_colon +"</span>" + 
							"</div>" + 
							"<div>" + 
								"<div class='ecs-color' id='ecs-color0' index='0'></div>" + 
								"<div class='ecs-color-separate'></div>" +  
								"<div class='ecs-color' id='ecs-color1' index='1'></div>" + 
								"<div class='ecs-color' id='ecs-color2' index='2'></div>" + 
								"<div class='ecs-color' id='ecs-color3' index='3'></div>" + 
								"<div class='ecs-color' id='ecs-color4' index='4'></div>" + 
								"<div class='ecs-color' id='ecs-color5' index='5'></div>" + 
								"<div class='ecs-color' id='ecs-color6' index='6'></div>" + 
								"<div class='ecs-color' id='ecs-color7' index='7'></div>" + 
								"<div class='ecs-color' id='ecs-color8' index='8'></div>" + 
								"<div class='ecs-color' id='ecs-color9' index='9'></div>" + 
								"<div class='ecs-color' id='ecs-color10' index='10'></div>" + 
								"<div class='ecs-color' id='ecs-color11' index='11'></div>" + 
							"</div>" + 
						"</div>" + 
				   "</div>";

		return html;
	}
	var g_colorCount = 11;
	var g_colorItems = [  {"colorValue": "", "colorName": g_loc_none},
						  {"colorValue": "#5484ED", "colorName": g_loc_boldBlue},
						  {"colorValue": "#A4BDFE", "colorName": g_loc_blue},
						  {"colorValue": "#46D6DB", "colorName": g_loc_turquoise},
						  {"colorValue": "#7AE7BF", "colorName": g_loc_green},
						  {"colorValue": "#51B749", "colorName": g_loc_boldGreen},
						  {"colorValue": "#FBD75B", "colorName": g_loc_yellow},
						  {"colorValue": "#FFB878", "colorName": g_loc_orange},
						  {"colorValue": "#FF887C", "colorName": g_loc_red},
						  {"colorValue": "#DC2127", "colorName": g_loc_boldRed},
						  {"colorValue": "#DBADFF", "colorName": g_loc_purple},
						  {"colorValue": "#E1E1E1", "colorName": g_loc_gray}
						];
	var g_curColorId = -1;
	function getCurrentColorId(){
		return g_curColorId;
	}
	function setCurrentColorId(colorId){
		g_curColorId = colorId;
	}			
	function getColorValue(colorId){
		if (!colorId || colorId < 0 || colorId > g_colorCount)
			return getCalendarColor();
		return g_colorItems[colorId].colorValue;
	}
	function getSelectedColor(){
		var curColorId = getCurrentColorId();
		if (curColorId == -1)
			return "#000";// black
		return getColorValue(curColorId);
	}
	function getColorName(colorId){
		if (colorId < 0 || colorId > g_colorCount)
			return;
		return g_colorItems[colorId].colorName;
	}
	function getCalendarColor(){
		return "#32CD32";
	}
	function checkAndAddStrLength(str){
		if (str.length < 2){
			return '0' + str;
		}else {
			return str;
		}
	}
	function getCalendarBorderColor(){
		var calendarColor = getCalendarColor();
		var red = parseInt(calendarColor.substr(1, 2), 16);
		var green = parseInt(calendarColor.substr(3, 2), 16);
		var blue = parseInt(calendarColor.substr(5, 2), 16);

		red -= red * (0.2);
		green -= green * (0.2);
		blue -= blue * (0.2);

		return "#" + checkAndAddStrLength(Math.floor(red).toString(16)) + 
					 checkAndAddStrLength(Math.floor(green).toString(16)) + 
					 checkAndAddStrLength(Math.floor(blue).toString(16));
	}
	function setAllEventsBkColor(colorVal, calEvent){
		var events = g_cal.fullCalendar("clientEvents", calEvent.id);
		for (var i = 0; i < events.length; i ++){
			events[i].backgroundColor = colorVal;
		}
	}
	function PopupEventColorSetBubble($parent, coordinate, doc, calEvent){
		var colorCount = 11;

		// 如果页面不存在，就创建一个页面，并把页面插入到默认编辑页面中。
		$main = $("#eventcolorset");
		if ($main.length == 0){
			var html = getColorSetBubbleHtml();
			$(document.body).append(html);
			
			for (var i = 1; i < colorCount + 1; i ++){
				$colorSquare = $("#ecs-color" + i);
				if ($colorSquare.length == 0){
					continue;
				}
				// 设置所有颜色框的背景色、边框色。
				$colorSquare.css("backgroundColor", getColorValue(i));
				$colorSquare.css("borderColor", getColorValue(i));

				// 设置所有颜色框的title。
				$colorSquare.attr("title", getColorName(i));
				// 对多个颜色框设置鼠标移动事件，鼠标移动到颜色框上时，设置这个颜色框边框颜色，当鼠标移开时，再设置回来。
				$colorSquare.mouseover(function(){
					$(this).css("borderColor", "black");
				}).mouseout(function(){
					var index = $(this).attr("index");
					$(this).css("borderColor", getColorValue(index));
				});
			}
			// 得到Bubble页面根DOM节点的Jquery对象。
			$main = $("#eventcolorset");
			$main.mousedown(function(e){
				stopBubble(e);
				return true;
			});
		}

		// 取得日历颜色。
		var calendarColor = getCalendarColor();
		// 设置第一个颜色框的背景色、边框色为日历颜色。
		var $firstColor = $("#ecs-color0");
		$firstColor.css("backgroundColor", calendarColor);
		// 边框颜色需要根据日历颜色计算出一个更深一点的颜色。
		var borderColor = getCalendarBorderColor();
		$firstColor.css("borderColor", borderColor);
		$firstColor.attr("title", g_loc_none);
		// 动态设置第一个颜色框当鼠标移入移出的边框颜色。
		$firstColor.unbind("mouseover").bind("mouseover", function(){
			$(this).css("borderColor", "black");
		}).unbind("mouseout").bind("mouseout", function(){
			$(this).css("borderColor", borderColor);
		});	
		// 取得颜色id，并根据颜色id，设置哪一个颜色框是选中状态，并移除以前的颜色框的选中状态。
		var info = _getDocInfo(doc);
		var eventColorId = _getEventColorIdFromInfo(info);
		if (!eventColorId)
			eventColorId = 0;
		for (var i = 0; i < colorCount + 1; i ++){
			$colorSquare = $("#ecs-color" + i);
			$toSelected = $colorSquare.children(".ecs-select");
			if ($toSelected){
				$toSelected.remove();
			}
		}
		$selectedSquare = $("#ecs-color" + eventColorId);
		$selectedSquare.append("<div class='ecs-select'></div>");
		$selectedSquare.children().addClass("ecs-selected");
		
		
		// 对多个颜色框设置鼠标单击事件，单击颜色框时，取出对应的颜色框的颜色值，存储到数据库（如果不是第一个颜色框被选择），设置界面事件的背景色，
		// 同时隐藏默认编辑事件界面，从新在界面上显示这个事件。
		for (var i = 0; i < colorCount + 1; i ++){
			$colorSquare = $("#ecs-color" + i);
			$colorSquare.unbind("click").bind("click", function(){
				var colorId = $(this).attr("index");
				// 如果选中的是默认颜色，不存储颜色id
				// 否则存储颜色id
				_setEventColorId(colorId, doc);
				// 更新Doc的修改时间，以备跟Google日历同步
				_updateDocModifyDate(doc);
				// 隐藏自己
				$main.css("visibility", "hidden");
				// 隐藏默认编辑事件界面。
				$parent.css("visibility", "hidden");
				// 设置界面的事件背景色，如果颜色是0，设置为日历颜色。
				var colorVal = Number(colorId) ? getColorValue(colorId) : calendarColor;
				// 从新再界面上显示这个事件。
				setAllEventsBkColor(colorVal, calEvent);
				g_cal.fullCalendar("updateEvent", calEvent);
			});
		}

		// 显示页面。

		$main.css({"visibility": "visible", left: coordinate.left, top: coordinate.top});
	}
	function ColorSetCoordinate($dropDown){
		var point = {};
		var dropTop = $dropDown.offset().top;
		var dropLeft = $dropDown.offset().left;

		var tipTop = dropTop + 3 + 4;
		var tipLeft = dropLeft + 2 + 3;

		point.top = tipTop + 7;
		point.left = tipLeft - (5 + 5);

		return point;
	}
	function _editEventPage(calEvent, jsEvent){

		var $main = $('#defaultedit');
		var $close;
		var $title;
		var $time;
		var $details;
		var $delete;
		g_editCalEvent = calEvent;
		if ($main.length == 0){
			var html = _getEditEventHtml();
			g_cal.append(html);

			$main = $('#defaultedit');
			$close = $('#de-close');
			$details = $('#de-details');
			$delete = $('#de-delete');

			$close.click(function(){
				$main.css('visibility', 'hidden');
			});
			$details.click(function(){
				$main.css('visibility', 'hidden');
				
				var doc = g_db.DocumentFromGUID(g_editCalEvent.guid);
				var start = doc.ParamValue('CALENDAR_START');
				var end = doc.ParamValue('CALENDAR_END');
				var title = doc.Title;
				g_calendarMain.css("display", "none");
				g_fullCreate.css("display", "block");
				_createFullEvent(start, end, title, g_editCalEvent.allDay, "modify", doc);
				
			});
			$details.mouseover(function(){
				$(this).css("textDecoration", "underline");
			}).mouseout(function(){
				$(this).css("textDecoration", "none");
			});

			$delete.click(function(){
				wizDeleteEvent(g_delGuid);
				$main.css('visibility', 'hidden');
			})

			$main.mousedown(function(e){
			 	stopBubble(e);
			 	$("#eventcolorset").css("visibility", "hidden");
			 	return true; 
			});

		}
		$titleParent = $("#de-title-parent");
		$actionParent = $("#de-action-parent");
		$time = $('#de-time');
		$tag = $('#de-tag');

		$prong1 = $('#de-prong1');
		$prong2 = $('#de-prong2');
		$prong3 = $('#de-prong3');
		$prong4 = $('#de-prong4');

		// 
		$main.css("height", 140);
		$prong1.css("top", 140);
		$prong2.css("top", 140);

		$(document.body).one('mousedown', function(){
			$("#eventcolorset").css("visibility", "hidden");
			$main.css('visibility', 'hidden');
		});
		if ($("#de-title").length == 0)
			$titleParent.append("<div id='de-title'></div>");
		if ($("#de-title-input").length != 0){
			$("#de-title-input").remove();
		}
		$title = $('#de-title');
		$title.html(calEvent.title);
		$title.css("color", calEvent.borderColor);
		$time.html(getTimeStr(calEvent.start, calEvent.end));

		$tag.css("display", "none");
		if (calEvent.tag){
			$tag.html(formatDefaultEditTag(calEvent.tag));
			$tag.css("display", "inline");
			$(".sperate-line").css("top", 75);
		}else {
			$(".sperate-line").css("top", 65);
		}


		$title.mouseover(function(){
			$(this).css("backgroundColor", "#FFF7D7");
		}).mouseout(function(){
			$(this).css("backgroundColor", "white");
		});
		if ($("#de-save").length != 0){
			$("#de-save").parent().remove();
		}
		if ($("#de-giveup").length != 0){
			$("#de-giveup").parent().remove();
		}
		$details = $('#de-details');
		$delete = $('#de-delete');
		$details.css("display", "inline");
		$delete.css("display", "inline");
		$delete.mouseover(function(){
			$(this).css("textDecoration", "underline");
		}).mouseout(function(){
			$(this).css("textDecoration", "none");
		});	
		$title.unbind('click').bind('click', function(){
			$titleParent = $("#de-title-parent");
			$titleParent.append("<div><input  id='de-title-input' type='text'/></div>");
			$("#de-title-input").val(calEvent.title);
			$("#de-title-input").css("color", calEvent.borderColor);
			

			setCaretToPos(document.getElementById("de-title-input"), $("#de-title-input").val().length);
			$("#de-title-input").focus();

			var mainHeight = _removeStrPx($main.css("height"));
			var prongWidth = _removeStrPx($prong1.css("border-left-width"));
			prongWidth --;
			$main.css("height", mainHeight + prongWidth);
			$prong1.css("top", mainHeight + prongWidth);
			$prong2.css("top", mainHeight + prongWidth);

			var moveVal = prongWidth;
			if ($prong3.css("display") != "none")
			 	moveVal = 0;
			$main.css("top", _removeStrPx($main.css("top")) - moveVal);

			$details.css("display", "none");
			$delete.css("display", "none");
			$actionParent.append("<td><span id='de-save' class='fc-button'><span class='fc-button-content'>" + g_loc_save + "</span></span></td>");
			$actionParent.append("<td><span id='de-giveup' class='fc-button'><span class='fc-button-content'>" + g_loc_giveup + "</span></span></td>");

			$("#de-save").click(function(){
				// 
				var doc = g_db.DocumentFromGUID(g_editCalEvent.guid);
				doc.Title = $("#de-title-input").val();
				wizRenderAllEvent();
				$main.css("visibility", "hidden");
			});
			$("#de-giveup").click(function(){
				// 
				$main.css("visibility", "hidden");
			});

			$(this).remove();
		});
		//
		function _CurrentDoc(){
			return g_db.DocumentFromGUID(g_editCalEvent.guid);
		}
		$eventColor = $("#de-eventcolor");
		$eventColor.css("borderColor", calEvent.borderColor);
		$eventColor.css("backgroundColor", calEvent.backgroundColor);
		$eventColor.unbind("click").bind("click", function(){
			// 弹出窗口，选择或者不选择一个颜色值，设置数据库中事件的颜色id，设置界面的颜色值，
			// 如果用户选择了颜色值，隐藏默认编辑事件页面。
			$dropDown = $("#de-eventcolor");
			var point = ColorSetCoordinate($dropDown);
			PopupEventColorSetBubble($main, point, _CurrentDoc(), calEvent);
		});
		//
		var prongWidth = _removeStrPx($prong1.css("border-left-width"));
		var bubbleWidth = _removeStrPx($main.css("width"));
		var bubbleHeight = _removeStrPx($main.css("height"));
		var defaultProngRight = 179;
		var defaultProngTop = 140;

		var coo = new Object();
		if (g_cal.fullCalendar("getView").name == "month"){
			_getBubblePageCoordinate(jsEvent, coo, prongWidth, bubbleWidth, bubbleHeight, defaultProngRight, defaultProngTop);
		}else {
			var tEvent = new Object();
			tEvent.pageX = jsEvent.pageX - jsEvent.offsetX;
			tEvent.pageY = jsEvent.pageY - jsEvent.offsetY;
			//
			_getBubblePageCoordinate(jsEvent, coo, prongWidth, bubbleWidth, bubbleHeight, defaultProngRight, defaultProngTop);
		}
		if (coo.top > 0){
			$prong1.css("display", "block");
			$prong2.css("display", "block");
			$prong3.css("display", "none");
			$prong4.css("display", "none");
			$prong1.css("right", coo.right);	
			$prong2.css("right", coo.right + 1);
		}else {
			$prong1.css("display", "none");
			$prong2.css("display", "none");
			$prong3.css("display", "block");
			$prong4.css("display", "block");
			$prong3.css("right", coo.right);
			$prong4.css("right", coo.right + 1);	
		}
		// 
		$main.css({"visibility": "visible", left: coo.x, top: coo.y});
	}
	function wizEditEvent(calEvent, jsEvent, view){
		g_delGuid = calEvent.id;
		var doc = g_db.DocumentFromGUID(calEvent.guid);
		calEvent.tag = doc.TagsText;
		//
		_editEventPage(calEvent, jsEvent);
	}
////////////////////////////////////////////////////////////
//
//	change google id bubble
	// function getChangeBubbleHtml(){
	// 	var html = "<div id='changegoogleid'>" + 
	// 					"<div id='cg-prong1'></div>" + 
	// 					"<div id='cg-prong2'></div>" + 	
	// 					"<div id='cg-main'>" + 
	// 						"<div id='cancel-p'>" + 
	// 							"<span id='cancelAuth'>取消授权</span>" + 
	// 						"</div>" + 
	// 					"</div>" + 
	// 			   "</div>";

	// 	return html;
	// }
	function wizClearChosenIdsInDb(){
		setChosenIdsToDb("");
	}
	function  wizCancelGoogleAuth(){
		$("#gidChange").css("display", "none");

		// setCookie("WizGCalendarToken", "");
		// setCookie("WizGoogleId", "");
		//
		setAccessTokenToDb("");
		setDefaultGoogleCalendarIDToDb("");
		// 
		wizClearChosenIdsInDb();

	}
	// function wizChangeGoogleIdPage(eventOri){
	// 	var $main = $("#changegoogleid");
	// 	if ($main.length == 0){
	// 		var html = getChangeBubbleHtml();
	// 		$(document.body).append(html);


	// 		$main = $("#changegoogleid");
	// 		$main.mousedown(function(e){
	// 			stopBubble(e);
	// 		 	return true; 
	// 		});

	// 	}
	// 	$("#cancel-p").unbind("click").bind("click", function(){
	// 	 	wizCancelGoogleAuth();
	// 	 	$main.css("visibility", "hidden");
	// 	}).unbind("mouseover").bind("mouseover", function(){
	// 		$(this).css("backgroundColor", "#CCC");
	// 	}).unbind("mouseout").bind("mouseout", function(){
	// 		$(this).css("backgroundColor", "white");
	// 	});

	// 	$(document.body).one("mousedown", function(){
	// 		$main.css("visibility", "hidden");
	// 	});
	// 	var eventPageX = eventOri.offset().left;
	// 	var eventPageY = eventOri.offset().top;
	// 	eventPageY += _removeStrPx(eventOri.css("height"));
	// 	var prongHeight = _removeStrPx($("#cg-prong1").css("borderLeftWidth"));
	// 	var prongWidth = prongHeight;
	// 	var bubbleWidth = _removeStrPx($main.css("width"));
	// 	eventPageX -= (bubbleWidth - prongWidth)/2;
	// 	eventPageY += prongHeight;

	// 	$main.css({left: eventPageX, top: eventPageY});
	// 	$main.css("visibility", "visible");
	// }

////////////////////////////////////////////////////////////
//
//	Wiz Calendar Options.
	function wizSelectCalendarsForSync(){}
		
	function getWizOptionsHtml(){
		var html = "<div id='wizoptions'>" + 
						"<div id='wo-main'>" + 
							"<div id='selectgooglecalender-p'>" + 
								"<span id='selectgooglecalender'>" + g_loc_selectcalendar + "</span>" + 
							"</div>" + 
							"<div id='cancel-p'>" + 
								"<span id='cancelAuth'>" + g_loc_cancelauth + "</span>" + 
							"</div>" + 
						"</div>" + 
				   "</div>";

		return html;
	}
	function getAlignLowRightCoordinate($parent, $child){
		if (!$parent || !$child){
			return;
		}
		var point = {};
		var parentTop = $parent.offset().top;
		var parentLeft = $parent.offset().left; 
		var parentWidth = $parent.width() + 
							_removeStrPx($parent.css("paddingLeft")) + 
							_removeStrPx($parent.css("paddingRight")) + 2;
		var parentHeight = $parent.height() + 
							_removeStrPx($parent.css("paddingTop")) + 
							_removeStrPx($parent.css("paddingBottom")) + 2;

		var childWidth = $child.width() + 
							_removeStrPx($child.css("paddingLeft")) + 
							_removeStrPx($child.css("paddingRight")) + 2;

		point.top = parentTop + parentHeight;
		point.left = (parentLeft + parentWidth) - childWidth;

		return point;
	}
	function PopupWizOptionsBubble($parent){
		var $main = $("#wizoptions");
		if ($main.length == 0){
			var html = getWizOptionsHtml();
			$(document.body).append(html);

			$main = $("#wizoptions");
			$main.mousedown(function(e){
				stopBubble(e);
			 	return true; 
			});
		}
		$(document.body).one("mousedown", function(){
			$main.css("visibility", "hidden");
		});
		$("#selectgooglecalender-p").unbind("click").bind("click", function(){
		 	wizSelectCalendarsForSync();
		 	$main.css("visibility", "hidden");
		}).unbind("mouseover").bind("mouseover", function(){
			$(this).css("backgroundColor", "#EEE");
		}).unbind("mouseout").bind("mouseout", function(){
			$(this).css("backgroundColor", "white");
		});
		$("#cancel-p").unbind("click").bind("click", function(){
		 	wizCancelGoogleAuth();
		 	$main.css("visibility", "hidden");
		}).unbind("mouseover").bind("mouseover", function(){
			$(this).css("backgroundColor", "#EEE");
		}).unbind("mouseout").bind("mouseout", function(){
			$(this).css("backgroundColor", "white");
		});



		var point = getAlignLowRightCoordinate($parent, $main);

		$main.css({left: point.left, top: point.top});
		$main.css("visibility", "visible");
	}

////////////////////////////////////////////////////////////
//
//	deal with repeat events
	var g_view;
	var g_eventStart;
	var g_eventEnd;
	var g_repeatRule;
	var g_endRecurrences;

	var g_offsetDays;
	var g_firstDay = 1;
	function _repeatEventInit(pseudoDoc){
		// 
		g_eventStart = pseudoDoc.start;
		g_eventEnd = pseudoDoc.end;
		g_repeatRule = pseudoDoc.rptRule;
		g_endRecurrences = pseudoDoc.rptEnd;
		g_offsetDays = _interDays(g_eventStart, g_eventEnd);
	}
	function getWeeklyRepeatDay(dayArray, number){
		
		for (index in number){

			var tVisStart = new Date(g_view.visStart);

			if (g_view.name == "agendaDay"){
				tVisStart.setDate(tVisStart.getDate() + (+(number[index]) - g_firstDay) - tVisStart.getDay());	
			} else{
				tVisStart.setDate(tVisStart.getDate() + (+(number[index]) - g_firstDay));	
			}
			var start = new Date(tVisStart);
			var endRec = _s2d(g_endRecurrences);
			var end = new Date();
			var eventstart = new Date(_s2d(g_eventStart));
			var maxWeek;
			if (g_view.name == "month") maxWeek = 6;
			if (g_view.name == "agendaWeek") maxWeek = 1;
			if (g_view.name == "agendaDay") maxWeek = 1;
			for (var i = 0; i < maxWeek; ++ i){
				if (g_endRecurrences && (start.getTime() > endRec.getTime())){
					break;
				}
				if (start.getTime() < eventstart.getTime()){
					start.setDate(start.getDate() + 7);
					continue;
				}
				var beg = new Date(start);
				var end = new Date(start);

				end.setDate(end.getDate() + g_offsetDays - 1);
				dayArray.push([beg, end]);
				
				start.setDate(start.getDate() + 7);
			}
		}
	}
	function getMonthlyRepeatDay(dayArray){
		var visEnd = g_view.visEnd;
		var viewStart = g_view.start;
		var eventStart = new Date(_s2d(g_eventStart));
		
		var beg = new Date(eventStart);
		var end;
		beg.setYear(viewStart.getFullYear());
		beg.setMonth(viewStart.getMonth());
		if (beg.getTime() != eventStart.getTime()){
			end = new Date(beg);
			end.setDate(beg.getDate() + g_offsetDays - 1);
			dayArray.push([beg, end]);
		}
		if ((visEnd.getDate() - 1) >= 6 ){
			beg = new Date(eventStart);
			beg.setYear(visEnd.getFullYear());
			beg.setMonth(visEnd.getMonth());
			end = new Date(beg);
			end.setDate(beg.getDate() + g_offsetDays - 1);
			dayArray.push([beg, end]);
		}
	}
	function _isValidYearlyDate(beg, end, eventStart){
		if ((beg.getTime() != eventStart.getTime()) && 
			(g_view.visStart.getTime() <= beg.getTime()) && 
			(beg.getTime() < g_view.visEnd.getTime()))
		{
			return true;
		}
		return false;
	}
	function getYearlyRepeatDay(dayArray){
		var y1 = g_view.visStart.getFullYear();
		var y2 = g_view.start.getFullYear();
		var y3 = g_view.visEnd.getFullYear();
		var eventStart = new Date(_s2d(g_eventStart));
		var beg = new Date(eventStart);
		var end = new Date(beg);
		// 如果一个事件，跨度是一年，应该是不允许的。
		beg.setYear(y1);
		end.setYear(y1);
		if (_isValidYearlyDate(beg, end, eventStart)){
			dayArray.push([beg, end]);
			return;
		}
		//
		var beg2 = new Date(beg);
		var end2 = new Date(end);
		beg2.setYear(y2);
		end2.setYear(y2);
		if (_isValidYearlyDate(beg2, end2, eventStart)){
			dayArray.push([beg2, end2]);
			return;
		}
		//
		var beg3 = new Date(beg);
		var end3 = new Date(end);
		beg3.setYear(y3);
		end3.setYear(y3);
		if (_isValidYearlyDate(beg3, end3, eventStart)){
			dayArray.push([beg3, end3]);
			return;
		}
	}
	function getChineseRepeatDay(dayArray, flag){
		var eventStart = new Date(_s2d(g_eventStart));
		var tVisStart = new Date(g_view.visStart);
		var tVisEnd = new Date(g_view.visEnd);
		var objLunarCal1 = new ChineseCalendar(eventStart);
		var objLunarCal2;
		var lunarStr = objLunarCal1.solarDay2();
		lunarStr = lunarStr.substr(lunarStr.indexOf(flag) + 1);
		while (tVisStart.getTime() < tVisEnd.getTime()){

			objLunarCal2 = new ChineseCalendar(tVisStart);
			var lunarStr2 = objLunarCal2.solarDay2();
			lunarStr2 = lunarStr2.substr(lunarStr2.indexOf(flag) + 1);
			if (lunarStr == lunarStr2){
				var beg = new Date(tVisStart);
				var end = new Date(tVisStart);
				end.setDate(end.getDate() + g_offsetDays - 1);
				var originalS = new Date(eventStart.getFullYear(), 
										eventStart.getMonth(), eventStart.getDate());
				if ((beg.getTime() != originalS.getTime()) && 
					(beg.getTime() > originalS.getTime()))
				{
					dayArray.push([beg, end]);
				}
			}
			tVisStart.setDate(tVisStart.getDate() + 1);
		}
	}
	function getRenderRepeatDay(){
		var dayArray = new Array();
		var eventStart = new Date(_s2d(g_eventStart));
		
		switch (g_repeatRule){
                case "EveryWeek1":
                case "EveryWeek2":
                case "EveryWeek3":
                case "EveryWeek4":
                case "EveryWeek5":
                case "EveryWeek6":
                case "EveryWeek7":
					getWeeklyRepeatDay(dayArray, [g_repeatRule.charAt(9)]);
                	break;
                case "EveryWeekday":
					getWeeklyRepeatDay(dayArray, [1, 2, 3, 4, 5]);
                	break;
                case "EveryWeekday135":
					getWeeklyRepeatDay(dayArray, [1, 3, 5]);
					break;
                case "EveryWeekday24":
					getWeeklyRepeatDay(dayArray, [2, 4]);
					break;
                case "EveryWeekday67":
					getWeeklyRepeatDay(dayArray, [6, 7]);
					break;
                case "Daily":
					getWeeklyRepeatDay(dayArray, [1, 2, 3, 4, 5, 6, 7]);
					break;
                case "Weekly":// 每周
					getWeeklyRepeatDay(dayArray, [eventStart.getDay()]);
					break;
                case "Every2Weeks":
					getWeeklyRepeatDay(dayArray, [eventStart.getDay()]);
					for (var i = 0; i < dayArray.length; ++ i){
						var inter = _interDays(_d2s(eventStart), _d2s(dayArray[i][0]));
						if ((parseFloat((inter-1)/7.0) % 2) != 0 ){
							dayArray.splice(i, 1);
							i --;
						}
					}
					break;
                case "Monthly":
					getMonthlyRepeatDay(dayArray);
					break;
                case "Yearly":
					getYearlyRepeatDay(dayArray);
					break;
				// TODO: 汉字需要考虑
                case "ChineseMonthly":
                	getChineseRepeatDay(dayArray, '月');
					break;
                case "ChineseYearly":
                	getChineseRepeatDay(dayArray, '历');
					break;
				default:{
					if (g_repeatRule.indexOf("EveryWeek") == 0){
						var days = g_repeatRule.substr("EveryWeek".length).split('');
						getWeeklyRepeatDay(dayArray, days);
					}
				}
            }
        
		return dayArray;
	}
	function _getRepeatEvent(events, pseudoDoc){
		var dayArray = getRenderRepeatDay();
		var start;
		var end;
		for (var i in dayArray){
			start = _d2s(dayArray[i][0]);
			start = start.substr(0, 10) + ' ' + g_eventStart.substr(11, 8);// 时间连接起来
			end = _d2s(dayArray[i][1]);
			end = end.substr(0, 10) + ' ' + g_eventEnd.substr(11, 8);
			//
			if (_s2d(start).getTime() != _s2d(g_eventStart).getTime()){
				var tEvent = _eventObject(pseudoDoc);
				tEvent.start = start;
				tEvent.end = end;
				events.push(tEvent);
			}
		}
	}
	function _getDocInfo(doc){
		return doc.ParamValue("CALENDAR_INFO");
	}
	function _setDocInfo(doc, info){
		setParamValue(doc, "CALENDAR_INFO", info);
	}
	function _getRemindFromInfo(info){
		var infoArray = info.split('/');
		for (var i = 0; i < infoArray.length; i++) {
			if (infoArray[i].indexOf("r=") != -1){
				return infoArray[i].substr(infoArray[i].indexOf("=")+1);
			}
		};
		return;
	}
	function _getEndRemindFromInfo(info){
		var infoArray = info.split('/');
		for (var i = 0; i < infoArray.length; i ++){
			if (infoArray[i].indexOf("c=") != -1){
				return infoArray[i].substr(infoArray[i].indexOf("=")+1);
			}
		}
		return;
	}
	function _getdocumentflagFromInfo(info)
	{
	    var infoArray = info.split('/');
	    for(var i = 0; i < infoArray.length; i++)
	    {
	        if(infoArray[i].indexOf("fd=") != -1)
	        {
	            return infoArray[i].substr(infoArray[i].indexOf("=") + 1);
	        }
	    }
	}
	function _setEventColorId(colorId, doc){
		var info = _getDocInfo(doc);

		if (info.indexOf("ci") == -1){
			info += "/ci=" + colorId;
		}else {
			info = info.replace(/ci=[\d]+[\/$]?/ig, "ci=" + colorId + "/");
			if (info[info.length-1] == '/'){
				info = info.substr(0, info.length - 1);
			}
		}

		_setDocInfo(doc, info);
	}
	function _getEventColorIdFromInfo(info){
		var infoArray = info.split('/');
		for (var i = 0; i < infoArray.length; i ++){
			if (infoArray[i].indexOf("ci=") != -1){
				return infoArray[i].substr(infoArray[i].indexOf("=")+1);
			}
		}
		return;
	}
	function _getEventColorFromInfo(info){
		var infoArray = info.split('/');
		for (var i = 0; i < infoArray.length; i ++){
			if (infoArray[i].indexOf("b=") != -1){
				return infoArray[i].substr(infoArray[i].indexOf("=")+1);
			}
		}
		return;		
	}
	function _isAllDay(start, end){
		var tEnd = _s2d(end);
		tEnd.setSeconds(tEnd.getSeconds() + 1);
		if (_interDays(start, _d2s(tEnd)) >=2 )
			return true;
		else {
			return false;
		}
	}
	function _getEventBkColor(info){
		var colorId = _getEventColorIdFromInfo(info);
		if (!colorId){
			return _getEventColorFromInfo(info);
		}
		if (colorId == 0){
			return getCalendarColor().replace('#', '');
		}else {
			return getColorValue(colorId).replace('#', '');
		}
	}
	function _newPseudoDoc(doc){
		var pseudoDoc = new Object();
		var guid, start, end, title, bkColor, text;
		var rptRule, rptEnd, allDay, textColor, remind, googleEventId;
		var created, updated, tag, colorId;

		if (arguments.length == 1){
			// aim at these events have been deleted
			if (!(doc.ParamValue('CALENDAR_START')) || 
				!(doc.ParamValue('CALENDAR_END')) || 
				!(doc.ParamValue('CALENDAR_INFO')))
			{
				return '';
			}
			guid = doc.GUID;
			start = doc.ParamValue('CALENDAR_START');
			end = doc.ParamValue('CALENDAR_END');
			title = doc.Title;
			var info = doc.ParamValue('CALENDAR_INFO');
			bkColor = _getEventBkColor(info);
			remind = _getRemindFromInfo(info);
			
			colorId = _getEventColorIdFromInfo(info);
			rptRule = doc.ParamValue('CALENDAR_RECURRENCE');
			rptEnd = doc.ParamValue('CALENDAR_ENDRECURRENCE');
			if (end.indexOf("23:59:59") != -1)
				allDay = true;
			else 
				allDay = false;
			textColor = 'black';// TODO:
			googleEventId = doc.ParamValue('CALENDAR_GOOEVENTID');
			text = getDocText(doc);
			created = _d2s(new Date(doc.DateCreated));
			updated = _d2s(new Date(doc.DateModified));
			tag = doc.TagsText;

		}else {
			guid = arguments[1];
			start = arguments[2];
			end = arguments[3];
			title = arguments[4];
			bkColor = arguments[5];
			rptRule = arguments[6];
			rptEnd = arguments[7];
			allDay = arguments[8]; // TODO: 需要根据start end 计算。
			textColor = arguments[9];// TODO:

		}
		// 
		pseudoDoc.guid = guid;
		pseudoDoc.start = start;
		pseudoDoc.end = end;
		pseudoDoc.title = title;
		pseudoDoc.text = text;
		pseudoDoc.bkColor = bkColor;
		pseudoDoc.colorId = colorId;
		pseudoDoc.rptRule = rptRule;
		pseudoDoc.rptEnd = rptEnd;
		pseudoDoc.allDay = allDay;
		pseudoDoc.textColor = textColor;
		pseudoDoc.remind = remind;
		pseudoDoc.created = created;
		pseudoDoc.updated = updated;
		pseudoDoc.tag = tag;
		pseudoDoc.googleEventId = googleEventId;

		return pseudoDoc;
	}
	function _getDocRepeatEvent(events, pseudoDoc){
		if (pseudoDoc == '')
			return;
		// 
		_repeatEventInit(pseudoDoc);
		// 
		var visStart = g_view.visStart;
		// 不可能出现在当前view中的repeat事件
		if (g_endRecurrences){
			end = _s2d(g_endRecurrences);
			if (end.getTime() < visStart.getTime()){
				return;
			}
		}
		_getRepeatEvent(events, pseudoDoc);
	}
	function fullCalendarRemoveAllEvents()
	{

	}
	function fullCalendarAddEvents(events)
	{
		g_cal.fullCalendar('addEventSource', events);	
	}
	function _renderEventBeforeCreate(guid, start, end, title, bkColor, repeatRule, endRec, allDay, textColor){
		var events = new Array();
		var pseudoDoc = _newPseudoDoc('', guid, _d2s(start), _d2s(end), title, bkColor, repeatRule, endRec, allDay, textColor);
		g_view = g_cal.fullCalendar('getView');
		
		_getDocRepeatEvent(events, pseudoDoc);

		events.push(_eventObject(pseudoDoc));

		fullCalendarAddEvents(events);

	}
	function _getDocEvent(events, doc){
		_getDocRepeatEvent(events,  _newPseudoDoc(doc));
		events.push(_eventObject(_newPseudoDoc(doc)));
	}
	function _renderDocEvent(doc){
		var events = new Array();
		_getDocEvent(events, doc);
		g_cal.fullCalendar('removeEvents', doc.GUID);

		fullCalendarAddEvents(events);
	}
	function getAllRepeatEventDoc(){
		var sql = "DOCUMENT_LOCATION not like '/Deleted Items/%' and (KB_GUID is null or KB_GUID = '') and " + 
				  "DOCUMENT_GUID in (select DOCUMENT_GUID from WIZ_DOCUMENT_PARAM where PARAM_NAME='CALENDAR_RECURRENCE')";
				
		if (!g_db)
			return;

		return g_db.DocumentsFromSQL(sql);


		// var guidArray = [];
		// //
		// var objRowset = g_db.SQLQuery(sql, '');
		// while (!(objRowset.EOF)){
		// 	guidArray.push(objRowset.GetFieldValue(0));
		// 	objRowset.MoveNext();
		// }
		// try{
		// 	objRowset.Close();
		// }catch(err){}
		
		// return guidArray;
	}
	function wizRenderAllEvent(){
		if (!g_cal)
			return;
		g_view = g_cal.fullCalendar('getView');
		var doc;
		var objDocColletion = getAllRepeatEventDoc();

		var events = [];
		for (var i = 0; i < objDocColletion.Count; i ++){
			doc = objDocColletion.Item(i);
			if (doc){
				_getDocRepeatEvent(events,  _newPseudoDoc(doc));
			}		
		}
		//
		_getAllOriginalEvent(events, _d2s(g_view.visStart), _d2s(g_view.visEnd));
		//
		g_cal.fullCalendar('removeEvents');
		fullCalendarAddEvents(events);
	}
////////////////////////////////////////////////////////////
//
//	render week numbers
	function getWeekNumberBubble(){
		var html = "<div id='weeknumber'>" + 
						"<div id='wn-close'/>" + 
						"<div>" + 
							"<div id='wn-tips-p'>" + 
								"<span id='wn-tips'></span>" + 
							"</div>" + 
							"<div id='wn-separate'>" + 
							"</div>" + 
							"<div id='wn-set-p'>" + 
								"<span id='wn-set'>" + g_loc_setfirstweek + "</span>" + 
							"</div>" + 
						"</div>" + 
						"<div id='wn-prong1'></div>" + 
						"<div id='wn-prong2'></div>" + 
				   "</div>";

		return html;
	}
	function getDateStartOn(theDate){}
	function setDateStartOn(dateStr){}
	function isWeekInCurrentYear(dateStr){
		var date = _s2d(dateStr);
		var startOn = getDateStartOn(date);
		startOn.setFullYear(date.getFullYear());
		if (date.getTime() >= startOn.getTime()){
			return true;
		}else {
			return false;
		}
	}
	function showWeekNumberBubble(e, dayNumber, date){
		$main = $("#weeknumber");
		if ($main.length == 0){
			var html = getWeekNumberBubble();
			$(document.body).append(html);

			$main = $("#weeknumber");
			$("#wn-close").click(function(){
				$main.css("visibility", "hidden");
			});
			$("#wn-set").mouseover(function(){
				$(this).css("textDecoration", "underline");
			}).mouseout(function(){
				$(this).css("textDecoration", "none");
			});
			$main.mousedown(function(e){
				stopBubble(e);
				return true;
			});

		}
		//
		var year = _s2d(date).getFullYear();
		if (!isWeekInCurrentYear(date)){
			year --;
		}
		var tips = String.format(g_loc_weeknumber, dayNumber, year);
		$("#wn-tips").html(tips);
		//
		$("#wn-set").unbind("click").bind("click", function(){
			setDateStartOn(date);
			g_cal.fullCalendar("render");
			$main.css("visibility", "hidden");
		});
		$(document).one('mousedown', function(){
			$main.css("visibility", "hidden");
		});
		var $prong1 = $("#wn-prong1");
		var $prong2 = $("#wn-prong2");
		var point = {};
		var prongWidth = _removeStrPx($prong1.css("border-left-width"));
		var bubbleWidth = _removeStrPx($main.css("width"));
		var bubbleHeight = _removeStrPx($main.css("height"));
		var defaultProngRight = 146;
		var defaultProngTop = 110;
		_getBubblePageCoordinate(e, point, prongWidth, bubbleWidth, bubbleHeight, defaultProngRight, defaultProngTop);
		$main.css({"top": point.y, "left": point.x});
		
		$prong1.css("right", point.right);
		$prong2.css("right", point.right + 1);
		$main.css("visibility", "visible");

	}

	function getMeta(name, key){
		if (g_db) return g_db.Meta(name, key);
	}
	function setMeta(name, key, value){
		if (!g_db)
			return;
		if (isChrome()) {
			g_db.SetMeta(name, key, value);
		}
		else {
			g_db.Meta(name, key) = value;
		}
	}
	function setParamValue(doc, key, value) {
		if (!doc)
			return;
		//
		if (isChrome()) {
			doc.SetParamValue(key, value);
		}
		else {
			doc.ParamValue(key) = value;
		}
	}
	function setTagName(tag, name) {
		if (!tag)
			return;
		if (isChrome()) {
			tag.SetName(name);
		}
		else {
			tag.Name = name;
		}
	}
	function getDateStartOn(theDate){
		var startOnStr = getMeta("CALENDAR_WEEKNUMBER", "CALENDAR_WEEKSTARTON");
		if (!startOnStr){
			return new Date(theDate.getFullYear(), 0, 1);
		}
		var year = theDate.getFullYear();
		var startOn = _s2d(year + "-" + startOnStr + " 00:00:00");
		if (startOn.getTime() > theDate.getTime()){
			startOn.setFullYear(startOn.getFullYear() - 1);
		}
		return startOn;

	}
	function setDateStartOn(dateStr){
		var startOnStr = dateStr.substr(0, 10).substr(("yyyy-").length, ("mm-dd").length);
		setMeta("CALENDAR_WEEKNUMBER", "CALENDAR_WEEKSTARTON", startOnStr);
	}
	function getWeekOfYear(theDate) {
	        var a = new Date(theDate.getFullYear(), theDate.getMonth(), theDate.getDate());
	       	// TODO： 用户用来设置开始的周
	        var startOn = getDateStartOn(theDate);
	        var d = (a.getTime() - startOn.getTime()) / 86400000;
	        var w = Math.floor(d / 7) + 1;
	        if (7-startOn.getDay() < d % 7) {
	            w++;
	        }
	        return w;
	}
	function getWeekNumberHtml(dayNumber, top, left){
		var styl = "top:" + top + "px" + ";" + "left:" + left + "px";
		// var styl = "";
		var html = "<div class='fc-weeknumber'" + " style=" + "'" + styl + "'" + ">" + 
				   		"<div class='fc-wkn-main'>" + 
				   			"<span class='weeknumber'>" + dayNumber + "</span>" + 
				   		"</div>" + 
				   "</div>";

		return html;
	}
	function getWeekNumberCoordinates(index){
		var point = {};
		var $ancestor = $(".fc-view");
		var $father = $(".fc-week" + index + " .fc-first");
		// $child = $(".fc-week1 .fc-weeknumber");
		var fatherTop = $father.offset().top;
		var fatherLeft = $father.offset().left;
		var fatherHeight = _removeStrPx($father.css("height"));
		var fatherWidth = _removeStrPx($father.css("width"));
		
		var intervalTop = fatherTop - $ancestor.offset().top;

		// var childWidth = _removeStrPx($child.css("width"));
		// var childHeight = _removeStrPx($child.css("height"));
		
		var childWidth = 15;
		var childHeight = 16;

		point.top = intervalTop + fatherHeight - childHeight;
		point.left = fatherWidth - childWidth;	

		return point;
	}

	function setWeekNumber(index, date){
		var seletorStr = ".fc-week" + index + " > .fc-first > div";
		var domObj = $(seletorStr);
		var dayNumber = getWeekOfYear(date);
		if ($(".fc-week" + index + " .fc-weeknumber").length != 0){
			var point = getWeekNumberCoordinates(index);
			$(".fc-week" + index + " .fc-weeknumber").css({"top": point.top + "px", "left": point.left + "px"});
			$(".fc-week" + index + " .fc-weeknumber .weeknumber").html(dayNumber);
			$(".fc-week" + index + " .fc-weeknumber .weeknumber").data("date", _d2s(date));
			return;
		}
		var point = getWeekNumberCoordinates(index);

		var html = getWeekNumberHtml(dayNumber, point.top, point.left);
		domObj.append(html);

		$main = $(".fc-week" + index + " .fc-weeknumber");
		$(".fc-week" + index + " .fc-weeknumber .weeknumber").data("date", _d2s(date));

		$main.mousedown(function(e){
			stopBubble(e);
			return true;
		});
		$main.unbind("click").bind("click", function(e){
			
			var dayNumber = $(this).find(".weeknumber").html();
			var curDateStr = $(this).find(".weeknumber").data("date");
			showWeekNumberBubble(e, dayNumber, curDateStr);


		});
		
	}
	function setParentRelative(){
		for (var i = 0; i < 6; i ++){
			$(".fc-week" + i + " .fc-first > div").css("position", "relative");
		}
	}
	function wizRenderWeekNumber(view){
		if (!view){
			view = $("#calendar").fullCalendar("getView");
		}
		if (view.name != "month")
			return;

		// setParentRelative();

		var firstDay = new Date(view.visStart);
		for (var i = 0; i < 6; i ++){
			setWeekNumber(i, firstDay);
			firstDay.setDate(firstDay.getDate() + 7);
		}
	}
////////////////////////////////////////////////////////////
//
//	about tag
	function wizChangeDate(dateArr){
		g_cal.fullCalendar('gotoDate', dateArr[0], (dateArr[1] - 1), dateArr[2]);
	}
	function wizFilterEventTags(tag){
		if (!g_db)
			return;
		if (tag == g_loc_tagfilter_all){
			wizRenderAllEvent();
			return;
		}
		var view = g_cal.fullCalendar("getView");
		var start = _d2s(view.visStart);
		var end = _d2s(view.visEnd);
		var sql = "DOCUMENT_LOCATION not like '/Deleted Items/%' and (KB_GUID is null or KB_GUID = '')";
		var and1 = " and DOCUMENT_GUID in (select DOCUMENT_GUID from WIZ_DOCUMENT_PARAM where PARAM_NAME = 'CALENDAR_START'  and  PARAM_VALUE <= '" + end + "' )";
		var and2 = " and DOCUMENT_GUID in (select DOCUMENT_GUID from WIZ_DOCUMENT_PARAM where PARAM_NAME = 'CALENDAR_END'  and  PARAM_VALUE >= '" + start + "' )";
		var and3 = " and DOCUMENT_GUID in (select DOCUMENT_GUID from WIZ_DOCUMENT_TAG where TAG_GUID in (select distinct TAG_GUID from WIZ_TAG where TAG_NAME='" + tag + "'))";
		sql += and1 + and2 + and3;

		var events = [];
		if (g_db.DocumentsDataFromSQL) {
			var data = g_db.DocumentsDataFromSQL(sql);
			//
			var obj = JSON.parse(data);
			//
			if (!obj || !IsArray(obj))
				return;
			//
			for (var i = 0; i < obj.length; i ++) {
				events.push(EVENTOBJECT(obj[i]));
			}
		}
		else {
			var docColletion = g_db.DocumentsFromSQL(sql);
			//
			if (docColletion && docColletion.Count){
				var doc;
				for (var i = 0; i < docColletion.Count; ++ i){
					doc = docColletion.Item(i);
					var eventObj = _eventObject(_newPseudoDoc(doc));
					_getDocRepeatEvent(events,  _newPseudoDoc(doc));
					events.push(_eventObject(_newPseudoDoc(doc)));
				}
			}			
		}

		//
		g_cal.fullCalendar('removeEvents');
		fullCalendarAddEvents(events);
		
	}
	function getDocTags(){
		var sql = "SELECT tag_name from wiz_tag where TAG_GUID " + 
				  " in (select distinct TAG_GUID from WIZ_DOCUMENT_TAG WHERE DOCUMENT_GUID " + 
				  	" in (select distinct DOCUMENT_GUID from WIZ_DOCUMENT where DOCUMENT_LOCATION not like '/Deleted Items/%' and DOCUMENT_GUID" + 
				  		" in (select DOCUMENT_GUID from WIZ_DOCUMENT_PARAM where PARAM_NAME='CALENDAR_START')))";
		if (!g_db)
			return;
		var objNames = g_db.SQLQuery(sql, '');
		var tagsArray = [];
		//
		while(!(objNames.EOF)){
			var name = objNames.GetFieldValue(0);
			tagsArray.push(name);

			objNames.MoveNext();
		}
		try{
			objNames.Close();
		}catch(e){}
		
		return tagsArray;
	}
	function addPureTags(select){
		if (!select)
			return;
		var tagsArray = getDocTags();
		if (!tagsArray)
			return;

		select.length = 0;
		for (var i in tagsArray){
			var option = new Option(tagsArray[i], tagsArray[i]);
			select.options.add(option, 0);
		}
	}
	function wizAddTags(select){

		// 
		addPureTags(select);
		var option = new Option(g_loc_tagfilter_all, g_loc_tagfilter_all);
		select.options.add(option);

	}


////////////////////////////////////////////////////////////
//
//	
	function wizOnMouseWhell(e){
		var view = g_cal.fullCalendar('getView');
		if (view.name != "month")
			return;
		var start = view.start;
		var tStart = new Date(start);
		if (+(e.wheelDelta) < 0)
			tStart.setMonth(tStart.getMonth() + 1);			
		else
			tStart.setMonth(tStart.getMonth() - 1);

		g_cal.fullCalendar('gotoDate', tStart.getFullYear(), tStart.getMonth());

		var date = $("#bubbledp").datepicker("getDate");
		date.setYear(tStart.getFullYear());
		date.setMonth(tStart.getMonth());
		$("#bubbledp").datepicker("setDate", date);
	}
	function wizSetMouseWhellEvent(){
		var scrollFunc = function(){
			wizOnMouseWhell(window.event);
		}
		// just for ie
		window.onmousewheel = document.onmousewheel = scrollFunc;
	}
	function wizGetChineseDate(date){
		var objChineseCal = new ChineseCalendar(date);
		var chineseStr = objChineseCal.solarDay2();
		var ret = '';
		// if (String.locale.toLowerCase() == "zh-cn"){
			if (objChineseCal.solarDay4().length > 0){
				ret = ' ' + objChineseCal.solarDay4();

			}else if(chineseStr.indexOf('初一') != -1){
				ret = ' ' + chineseStr.substr(2, chineseStr.indexOf('初一') - 2);
			}else {
				ret = ' ' + chineseStr.substr(chineseStr.indexOf('月') + 1);
			}
		// }
		return ret;
	}
	function wizSetGoogleId(id){
		if (id)
			$("#googleId").html(id);
		else {
			$("#googleId").html("");
			$("#gidChange").css("display", "none");
		}
	}
	function wizUpdateLayout(){
		$('#wizTag')[0].length = 0;
		wizAddTags($('#wizTag')[0]);

		// var googleId = getCookie("WizGoogleId");
		var googleId = getDefaultGoogleCalendarIDFromDb();
		// wizSetGoogleId(googleId);
		// The html elements' coordinates error when FullCalendar's viewDisplay callback first invoke.
		var view = $("#calendar").fullCalendar("getView");
		wizRenderWeekNumber(view);
	}
	function wizSetView(view){
		setCookie("WizCalendarView", view);
		// setMeta("WIZCALENDAR", "WizCalendarView", view);
	}
	function wizGetView(){
		var view = Cookies.get("WizCalendarView");
		// var view = getMeta("WIZCALENDAR", "WizCalendarView");
		if (!view)
			view = "agendaWeek";
		return view;
	}
////////////////////////////////////////////////////////////
//
//	<body/> onload callback
	function format(baseStr){
		if (arguments.length < 1){
			return baseStr;
		}
		for (var i = 1; i < arguments.length; i ++){
			baseStr = baseStr.replace("%" + i, arguments[i]);
		}

		return baseStr;
	}
	function wizInit(){
		g_app = window.external;
		if (!g_app || !(g_app.Database)){
			try
			{
				g_app = new ActiveXObject("Wiz.WizExplorerApp");
			}
			catch (err)
			{
			}
		}

		g_db = g_app.Database;
		if (!g_db)
		{
			try
			{
				g_db = new ActiveXObject("WizKMCore.WizDatabase");
				g_db.Open3("", "", "", 0);
			}
			catch (err)
			{
			}
		}
		//
		g_cmn = g_db.CreateWizObject('WizKMControls.WizCommonUI');
		g_cal = $('#calendar');

		String.format = format;
		return '';		
	}
	function setTitle(){
		document.title = g_loc_calendar;
	}
	function wizOnLoad(){
		// TODO: $('#wizTag')[0] 应该保存在一个全局变量中
		wizInit();
		setTitle();
		wizUpdateLayout();
		//wizAddBodyMousedownEvent();
		wizAddFullCalendarMousedownEvent();
		wizRenderAllEvent();
	}
	function setGoogleDeleteEventMeta(doc){
		if (!g_db)
			return;
		var googleEventId = doc.ParamValue('CALENDAR_GOOEVENTID');
		if (googleEventId){

			var tag = doc.TagsText;
			tag = tag.replace(/;/ig, '-');
			var value =  tag + ":" + googleEventId;
			var metaVal = g_db.Meta("GOOGLECALENDAR", "DELETEDEVENTID");
			if (metaVal){
				metaVal += ';' + value;
			}else {
				metaVal = value;
			}
			setMeta("GOOGLECALENDAR", "DELETEDEVENTID", metaVal);
		}
	}
	function resetGoogleDeleteEventMeta(){
		setMeta("GOOGLECALENDAR", "DELETEDEVENTID", '');
	}
	function getGoogleDeleteEventMeta(){
		if (!g_db)
			return;
		return g_db.Meta("GOOGLECALENDAR", "DELETEDEVENTID");
	}
	function getNewGoogleCalendarId(metaVal, calendarId, newTag, splitter) {
		if (!metaVal || !calendarId || !newTag || !splitter)
			return metaVal;
		//
		var array = metaVal.split(splitter);
		if (!array || array.length == 0)
			return metaVal;
		//
		for (var i = 0; i < array.length; i ++) {
			var arrTagId = array[i].split(':');
			if (!arrTagId || arrTagId.length == 0)
				continue;
			//
			var tag = arrTagId[0];
			var id = arrTagId[1];
			//
			if (id != calendarId)
				continue;
			//
			array[i] = newTag + ':' + id;
		}
		//
		return array.join(';');
	}
	function renameTag(oldName, newName) {
		if (!oldName || !newName)
			return;
		//
		if (!g_db)
			return;
		//
		if (oldName == newName)
			return;
		//
		try {
			var objTag = g_db.GetTagByName(oldName, 0, '');
		}
		catch (err) {
			return;
		}
		if (!objTag)
			return;
		//
		try {
			setTagName(objTag, newName);
		}
		catch (err) {
			var prompt = "setTagName failed.oldName: %1, newName: %2, err: %3";
			prompt = prompt.replace("%1", oldName)
				  		   .replace("%2", newName)
				  		   .replace("%3", err);
			//
			alert(prompt);
		}
	}
	function setGoogleCalendarIdMeta(tag, calendarId){
		if (!g_db)
			return;
		if (!tag)
			return;
		var value = tag + ":" + calendarId;
		if (value){
			var metaVal = g_db.Meta("GOOGLECALENDAR", "CALENDARID");
			if (metaVal){
				if (metaVal.indexOf(calendarId) != -1) {
					metaVal = getNewGoogleCalendarId(metaVal, calendarId, tag, ';');
					//
					renameTag(getTagNameByGoogleCalendarId(calendarId), tag);
				}
				else {
					metaVal += ';' + value;
				}
			}else {
				metaVal = value;
			}
			//
			setMeta("GOOGLECALENDAR", "CALENDARID", metaVal);
		}
	}
	function clearGoogleCalendarIdMeta(){
		setMeta("GOOGLECALENDAR", "CALENDARID", "");
	}
	function getTagNameByGoogleCalendarId(calendarId){
		if (!g_db)
			return;
		var metaVal = g_db.Meta("GOOGLECALENDAR", "CALENDARID");
		if (!metaVal)
			return "";
		var arr = metaVal.split(';');
		for (var i = 0; i < arr.length; i ++){
			var metaId = arr[i].substr(arr[i].indexOf(':') + 1);
			if (metaId == calendarId){
				return arr[i].substr(0, arr[i].indexOf(':'));
			}
		}
		return "";
		
	}
	function getGoogleCalendarIdMeta(tag){
		if (!g_db)
			return;
		var metaVal = g_db.Meta("GOOGLECALENDAR", "CALENDARID");
		if (!metaVal)
			return "";
		var arr = metaVal.split(';');
		for (var i = 0; i < arr.length; i ++){
			var metaTag = arr[i].substr(0, arr[i].indexOf(':'));
			if (tag.indexOf(metaTag) != -1){
				return arr[i].substr(arr[i].indexOf(':') + 1);
			}
		}
		return "";
	}

	function wizDeleteEvent(guid){
		g_cal.fullCalendar('removeEvents', guid);
		var doc = g_db.DocumentFromGUID(guid);
		if (!doc){
			return;
		}
		// 
		setGoogleDeleteEventMeta(doc);
		// 
		doc.RemoveFromCalendar();
	}
	var g_winWidth;
	var g_winHeight;
	function getBodyWidth(){
		if(document.documentElement && document.documentElement.clientWidth){
			return document.documentElement.clientWidth;
		}
	}
	function getBodyHeight(){
		if(document.documentElement && document.documentElement.clientHeight){
			return document.documentElement.clientHeight;
		}
	}
	function wizGetAspectRatio(from){
		var winWidth = getBodyWidth();
		var winHeight = getBodyHeight();

		var $header = $(".fc-header");
		// var $contentHeader = $(".fc-first .fc-last");
		// var $allDay = $(".fc-agenda-allday");
		// var $divider = $(".fc-agenda-divider-inner");

		var view;
		var $cal = $("#calendar");
		if ($cal){
			view = $("#calendar").fullCalendar("getView");
		}
		var t = ($header.height());
		var paddingTop = _removeStrPx($(".fc-view").css("paddingTop"));
		if (view.name == "month")
		 	t += paddingTop;

		// 当改变日历事件元素的时候，会触发window.resize事件，但是浏览器大小其实是没变的，
		// 如果这个时候改变calendar的大小比例，就无法改变日历事件的大小。
		if ( (from != "changeView") && (winWidth == g_winWidth) && (winHeight == g_winHeight)){
			return;
		}else {
			g_winWidth = winWidth;
			g_winHeight = winHeight;
		}
		var aspectRatio = $header ? ((winWidth+1) / (winHeight - t)) : (winWidth / winHeight);

		return aspectRatio;
	}
	function wizOnWindowResize(from){
		var aspectRatio = wizGetAspectRatio(from);
		$('#calendar').fullCalendar('option', 'aspectRatio', aspectRatio);
	}
////////////////////////////////////////////////////////////
//
//	google calendar synchronization
	/**//**  
	 * 设置Cookies  
	 */
	Cookies.set = function(name, value){
	     var argv = arguments;   
	     var argc = arguments.length;
	     var expires = (argc > 2) ? argv[2] : null;
	     var path = (argc > 3) ? argv[3] : '/';   
	     var domain = (argc > 4) ? argv[4] : null;   
	     var secure = (argc > 5) ? argv[5] : false;   
	     document.cookie = name + "=" + escape (value) +   
	       ((expires == null) ? "" : ("; expires=" + expires.toGMTString())) +   
	       ((path == null) ? "" : ("; path=" + path)) +   
	       ((domain == null) ? "" : ("; domain=" + domain)) +   
	       ((secure == true) ? "; secure" : "");
	};   
	/**//**  
	 * 读取Cookies  
	 */  
	Cookies.get = function(name){   
	    var arg = name + "=";   
	    var alen = arg.length;   
	    var clen = document.cookie.length;   
	    var i = 0;   
	    var j = 0;   
	    while(i < clen){   
	        j = i + alen;   
	        if (document.cookie.substring(i, j) == arg)   
	            return Cookies.getCookieVal(j);   
	        i = document.cookie.indexOf(" ", i) + 1;   
	        if(i == 0)   
	            break;   
	    }   
	    return null;   
	};   
	/**//**  
	 * 清除Cookies  
	 */  
	Cookies.clear = function(name) {   
	  if(Cookies.get(name)){   
	    var expdate = new Date();    
	    expdate.setTime(expdate.getTime() - (86400 * 1000 * 1));    
	    Cookies.set(name, "", expdate);    
	  }
	};   
	  
	Cookies.getCookieVal = function(offset){
	   var endStr = document.cookie.indexOf(";", offset);   
	   if(endStr == -1){   
	       endStr = document.cookie.length;   
	   }   
	   return unescape(document.cookie.substring(offset, endStr));   
	}; 



	function getSyncBubbleHtml(){
		var html = 
				"<div id='syncprogress'>" + 
					"<span id='sync-info'></span>" + 
				"</div>";
		return html;
	}
	function hiddenSyncBubble(){
		if ($("#syncprogress")){
			$("#syncprogress").css("visibility", "hidden");
		}
	}
	function pushSyncInfo(info){
		$syncInfo = $("#sync-info");
		if (!$syncInfo)
			return;
		$syncInfo[0].innerHTML = info;
	}
	function googleSyncPage(){
		$main = $("#syncprogress");
		if ($main.length == 0){
			var html = getSyncBubbleHtml();
			$(document.body).append(html);

			$main = $("#syncprogress");
		}
		$syncInfo = $("#sync-info");
		$syncInfo.html("");
		//
		var center = getBodyWidth() / 2 - _removeStrPx($main.css("width")) / 2;
		$main.css({"visibility": "visible", left: center, top: 20});
	}
	var g_calendarId = '';
	var g_calendarDefaultId = '';

	function _date2DateTime(date){
		// TODO: 暂时先硬编码
		var timeZone = "08:00";
		var timeStr = _d2s(date);
		var retStr =  timeStr.substr(0, ("yyyy-mm-dd").length) + "T" + 
					  timeStr.substr(("yyyy-mm-dd").length + 1)+ "+" + 
					  timeZone;

		return retStr;
	}
	function _dateTime2DateStr(dateTimeStr){
		if (!dateTimeStr)
			return;
		var dateStr = dateTimeStr.substr(0, 10) + ' ' + dateTimeStr.substr(11, 8);
		var dateTimeSign = dateTimeStr.charAt(dateTimeStr.length - 1);
		var retStr = dateStr;
		if ( dateTimeSign == 'Z' || (dateTimeSign == 'z')){
			var dateDate = _s2d(dateStr);
			// TODO: timeZone hard code
			dateDate.setHours(dateDate.getHours() + 8);
			retStr = _d2s(dateDate);
		}
		return retStr;
	}
	function _dateStr2DateTime(dateStr){
		// TODO: hard code
		return dateStr.substr(0, 10) + 'T' + 
			   dateStr.substr(11) + "+08:00";
	}
	function _2GoogleEventStartTime(start, end){
		if (_isAllDay(start, end)){
			return {"date": start.substr(0, 10)};
		}else {
			return {"dateTime": _dateStr2DateTime(start)};
		}

	}
	function _2GoogleEventEndTime(start, end){
		if (_isAllDay(start, end)){
			var d = _s2d(end);
			d.setDate(d.getDate() + 1);
			return {"date": _d2s(d).substr(0, 10)};
		}else {
			return {"dateTime": _dateStr2DateTime(end)};
		}
	}
	function _gooDate2DateStr(dateStr){
		return dateStr + ' ' + "00:00:00";
	}
	function _reviseEndDate(end){
		var endDateStr = _gooDate2DateStr(end);
		var endDate = _s2d(endDateStr);
		endDate.setDate(endDate.getDate() - 1);
		endDateStr = _d2s(endDate);
		endDateStr = endDateStr.substr(0, 10) + ' ' + "23:59:59";
		
		return endDateStr;
	}
	// "RRULE:FREQ=WEEKLY;UNTIL=20130319;INTERVAL=2;BYDAY=MO,SU,TU,WE,TH,FR,SA"
	// "RRULE:FREQ=DAILY"
	// "RRULE:FREQ=MONTHLY"
	// "RRULE:FREQ=YEARLY;INTERVAL=2"
	var g_ruleBaseMap = { 
						"WEEKLY": "Weekly",
				  		"DAILY": "Daily",
				  		"MONTHLY": "Monthly",
				  		"YEARLY": "Yearly" 
					};
	var g_byDayMap = {
					"MO": "1",
					"TU": "2",
					"WE": "3",
					"TH": "4",
					"FR": "5",
					"SA": "6",
					"SU": "7" 
					};
	var g_wizRptRule2GooRule = {
		"EveryWeek": "WEEKLY",
		"Daily": "DAILY",
		"Monthly": "MONTHLY",
		"Yearly": "YEARLY",
		"EveryWeekday": "WEEKLY"
					};
	var g_wizDay2GooByDay = {
							"1": "MO",
							"2": "TU",
							"3": "WE",
							"4": "TH",
							"5": "FR",
							"6": "SA",
							"7": "SU"
					};
	// for holding default reminders of event
	var g_accessToken;
	var g_apiKey = "AIzaSyD5e2SZ1WuTFP3TUqAakfSMWowDrZAKXmg";
	var g_gooEventEntryResource;
	var g_googleColorEntry;
	// var g_googleCalendarListEntry;
	var g_urlBase = "http://localhost/";
	function toLog(logStr){
		if (g_app){
			g_app.WriteToLog(logStr);
		}
	}
	function _googleCalendarSyncInitUrlBase(){
		var curUrl = document.location.href;
		var index = curUrl.indexOf('?') != -1 ? curUrl.indexOf('?') : curUrl.length;
		curUrl = curUrl.substr(0, index);
		curUrl = curUrl.substr(0, curUrl.lastIndexOf('/'));
		g_urlBase = curUrl + '/';
	}
	function _parseGooRecurrence(recurrence, retObj){
		var googleRRule = {};
		if (!recurrence){
			googleRRule.rptRule = '';
			googleRRule.rptEnd = '';
			googleRRule.interval = '';
			return googleRRule;
		}
		for (var i = 0; i < recurrence.length; i++) {
			var ruleLine = recurrence[i];
			// 
			if (ruleLine.indexOf("RRULE") != -1){
				var rule = ruleLine.substr(("RRULE:").length);
				var ruleArray = rule.split(';');
				for (var j = 0; j < ruleArray.length; j++) {
					var ruleItemArray = ruleArray[j].split('=');
					// 
					if (ruleItemArray[0] == "FREQ"){
						googleRRule.rptRule = g_ruleBaseMap[ruleItemArray[1]];
					}
					// 
					var ruleVal = '';
					switch(ruleItemArray[0]){
						case "UNTIL":{
							googleRRule.rptEnd = ruleItemArray[1].substr(0, 4) + '-' +
											ruleItemArray[1].substr(4, 2) + '-' + 
											ruleItemArray[1].substr(6, 2);
							break;
						}
						case "INTERVAL":{
							googleRRule.interval = ruleItemArray[1];
							break;
						}
						case "BYDAY":{
							var byDay = ruleItemArray[1].split(',');
							for (var k = 0; k < byDay.length; k++) {
								ruleVal += g_byDayMap[byDay[k]];
							};
							break;
						}
						default:{

						}
					}
					// 
					if (googleRRule.rptRule == "Weekly" &&
						 (ruleVal != '') )
					{
						googleRRule.rptRule = g_weeklyRptRule + ruleVal;
					}
					// 每月第几个星期几
					if (googleRRule.rptRule == "Monthly" &&
						(ruleVal != '') )
					{

					}
				};
			}
			// 
			if (ruleLine.indexOf("EXRRULE") != -1){

			}
			// ...

			// ...

		}
		// 
		return googleRRule;
	}
	function _parseGooReminders(reminders){
		if (!reminders)
			return;
		var remindVal = -1;
		if (reminders.useDefault == false){
			var remindArray = reminders.overrides;
			var max = 10000000;
			var maxVal = max;
			if (remindArray){// 正常情况下是不存在这种现象的，但是为了
							// 防止错误日历数据影响代码正常执行
				for (var i = 0; i < remindArray.length; i++) {
					if (remindArray[i].method == "popup"){
						if (maxVal > remindArray[i].minutes)
							maxVal = remindArray[i].minutes;
					}
				};
			}
			remindVal = maxVal == max ? -1 : (maxVal * 60);
		}else {
			var defaultReminders = g_gooEventEntryResource.defaultReminders;
			if (defaultReminders){
				for (var i = 0; i < defaultReminders.length; i++) {
					if (defaultReminders[i].method == "popup"){
						remindVal = defaultReminders[i].minutes * 60;
					}
				}
			}
		}
		return remindVal;
	}
	function _getGuidFromGoogleId(id){
		var sql = "select DOCUMENT_GUID from WIZ_DOCUMENT_PARAM where PARAM_NAME='CALENDAR_GOOEVENTID' and PARAM_VALUE=" + "'" + id + "'";
		if (!g_db)
			return;
		var guid;
		var objRowset = g_db.SQLQuery(sql, '');
		if (!(objRowset.EOF)){
			guid = objRowset.GetFieldValue(0);
		}
		try{
			objRowset.Close();
		}catch(err){}
		return guid;
	}
	function _docFromGoogleId(id){
		var doc;
		var guid = _getGuidFromGoogleId(id);
		if (!guid){
			return;
		}
		doc = g_db.DocumentFromGUID(guid);
		return doc;
	}
	function _docFromGUID(guid){
		if (!g_db){
			return;
		}
		var doc;
		try {
			doc = g_db.DocumentFromGUID(guid);
		}
		catch(err){
			toLog("_docFromGUID failed, guid = " + guid);
		}
		return doc;
	}
	function _createGooIdGUIDMap(mapObj, tagName){
		if (!g_db)
			return;
		var sql = "select DOCUMENT_GUID,PARAM_VALUE from WIZ_DOCUMENT_PARAM where PARAM_NAME='CALENDAR_GOOEVENTID'" + 
				  " and DOCUMENT_GUID in (select DOCUMENT_GUID from WIZ_DOCUMENT_TAG where TAG_GUID" + 
				  " in (select TAG_GUID  from WIZ_TAG where TAG_NAME = '" + tagName + "') )";

		var objRowset = g_db.SQLQuery(sql, '');
		while (!(objRowset.EOF)){
			var guid = objRowset.GetFieldValue(0);
			var gooId = objRowset.GetFieldValue(1);
			mapObj[gooId] = guid;

			objRowset.MoveNext();
		}
		try{
			objRowset.Close();
		}catch(err){}
	}

	function _createGooIdGUIDMapTest(mapObj){
		if (!g_db)
			return;
		var sql = "select DOCUMENT_GUID,PARAM_VALUE from WIZ_DOCUMENT_PARAM where PARAM_NAME='CALENDAR_GOOEVENTID'";

		var objRowset = g_db.SQLQuery(sql, '');
		while (!(objRowset.EOF)){
			var guid = objRowset.GetFieldValue(0);
			var gooId = objRowset.GetFieldValue(1);
			mapObj[gooId] = guid;

			objRowset.MoveNext();
		}
		try{
			objRowset.Close();
		}catch(err){}
	}

	function _object2Array(obj){
		var array = [];
		for (key in obj){
			array.push([key, obj[key]]);
		}
		return array;
	}
	function _isDeletedGoogleEvent(googleEventId){
		if (!g_db)
			return;
		var googleEventIds = getGoogleDeleteEventMeta();
		return (googleEventIds.indexOf(googleEventId) != -1);
	}
	// function _getWizEventColor(googleEventColorId){
	// 	var colorRGB = "D5F8DD";
	// 	if (!g_googleColorEntry || (!g_googleCalendarListEntry))
	// 		return colorRGB;
	// 	if (googleEventColorId){
	// 		colorRGB = g_googleColorEntry.event[googleEventColorId].background;
	// 		colorRGB = colorRGB.replace('#', '');
	// 	}else {
	// 		colorRGB = g_googleCalendarListEntry.backgroundColor;
	// 		colorRGB = colorRGB.replace('#', '');
	// 	}

	// 	return colorRGB;
	// }
	var WIZ_GOOGLE_CALENDAR_TAG = "     gcal";
	function makeGoogleEventTag(GoogleEventSummary){
		return GoogleEventSummary + WIZ_GOOGLE_CALENDAR_TAG;
	}
	function _getGoogleEventTag(organizer){
		return organizer ? makeGoogleEventTag(organizer.displayName): "";
	}
	var g_eventColorIdGoogle2Wiz = [0, 2, 4, 10, 8, 6, 7, 3, 11, 1, 5, 9];
	var g_eventColorIdWiz2Google = [0, 9, 1, 7, 2, 10, 5, 6, 4, 11, 3, 8];
	function adjustEnd(start, end){
		if (end > start){
			return end;
		}
		if (end == start){
			var adjustEnd = _s2d(start);
			adjustEnd.setMinutes(adjustEnd.getMinutes() + 1);
			return _d2s(adjustEnd);
		}
		var startArray = start.split('');
		var endArray = end.split('');
		if (startArray.length != endArray.length){
			toLog("In function adjustEnd, startArray.length == endArray.length. It's a bug.");
			var adjustEnd = _s2d(start);
			return _d2s(adjustEnd.setDate(adjustEnd.getDate() + 1));
		}
		for (var i = 0; i < startArray.length && i < endArray.length; i ++){
			if (endArray[i] < startArray[i]){

				var adjustEnd = _s2d(start);
				if (0 <= i && i <= 3){// year
					adjustEnd.setFullYear(adjustEnd.getFullYear() + 1);
				}else if (5 <= i && i <= 6){// month
					adjustEnd.setMonth(adjustEnd.getMonth() + 1);
				}else if (8 <= i && i <= 9){// date
					adjustEnd.setDate(adjustEnd.getDate() + 1);
				}else if (11 <= i && i <= 12){// hour
					adjustEnd.setHours(adjustEnd.getHours() + 1);
				}else if (14 <= i && i <= 15){// minute
					adjustEnd.setMinutes(adjustEnd.getMinutes() + 1);
				}else if (17 <= i && i <= 18){// second
					adjustEnd.setSeconds(adjustEnd.getSeconds() + 1);
				}
				return _d2s(adjustEnd);
			}
		}
	}
	function _getWizEventObj(googleEventRes){
		var wizEventObj = {};
		var start = googleEventRes.start.date ? 
					_gooDate2DateStr(googleEventRes.start.date) : 
					_dateTime2DateStr(googleEventRes.start.dateTime);
		var end;
		if (googleEventRes.end.date){
			end = _reviseEndDate(googleEventRes.end.date);
		}else {
			end = _dateTime2DateStr(googleEventRes.end.dateTime);
		}
		
		wizEventObj.start = start;
		wizEventObj.end = adjustEnd(start, end);
		wizEventObj.title = googleEventRes.summary ? googleEventRes.summary : g_loc_notitle;
		wizEventObj.color = getColorValue(googleEventRes.colorId);
		wizEventObj.colorId = googleEventRes.colorId ? g_eventColorIdGoogle2Wiz[googleEventRes.colorId] : 0;
		wizEventObj.content = googleEventRes.description ? googleEventRes.description : '';
		wizEventObj.tag = _getGoogleEventTag(googleEventRes.organizer);

		var googleRRule = _parseGooRecurrence(googleEventRes.recurrence);
		wizEventObj.rptRule = googleRRule.rptRule;
		wizEventObj.rptEnd = googleRRule.rptEnd;
		wizEventObj.remind = _parseGooReminders(googleEventRes.reminders);
		wizEventObj.updated = _dateTime2DateStr(googleEventRes.updated);

		return wizEventObj;

	}
	function logObject(obj, objName){
		try{
			if (objName){
				toLog("{// Start log " + objName + " obj.");
			}
			if (typeof(obj) != "object"){
				toLog(obj.toString());
				return;
			}
			for (var name in obj){
				if (typeof(obj[name]) == "object"){
					toLog("{// Start log child obj. " + name + ": ");
					logObject(obj[name]);
					toLog("}// Stop.");
				}else {
					toLog(name + ": " + obj[name]);
				}
			}
			if (objName){
				toLog("{// Stop");
			}
		}catch(err){
			toLog("function logObject has bug.");
			return;
		}
	}
	function _createOrModifyWizEvents(events){
		// TODO: 这个函数需要修改 改成 _createOrModifyGoogleEvents一样
		if (!events)
			return;
		// toLog("_createOrModifyWizEvents start, event count = " + events.length);
		for (var i = 0; i < events.length; i++) {
			// TODO： 换成两个函数
			try{
				var wizEventResource = _getWizEventObj(events[i]);
			}catch(err){
				toLog("_getWizEventObj failed.");
				toLog("error events[i] start: ");
				for (var name in events[i]){
					toLog("events[i]." + name + " = " + events[i][name]);
				}
				toLog("error events[i] end.");
				continue;
			}
			var guid = _getGuidFromGoogleId(events[i].id);
			if (guid){
				var doc = _docFromGUID(guid);
				if (!doc)
					continue;
				g_app.DoEvents();
				// TODO:
				var modifyDate = doc.DateModified;
				var tempDate = new Date(modifyDate);
				if (tempDate.getTime() < 
					_s2d(_dateTime2DateStr(events[i].updated)).getTime())
				{
					pushSyncInfo(g_loc_updatewizevent + g_loc_colon + wizEventResource.title);
					g_app.DoEvents();
					try{
						wizUpdateEvent(doc, wizEventResource);
					}catch(err){
						toLog("Update wiz event failed. wizUpdateEvent");
					}
					g_app.DoEvents();
				}
			}else {
				wizEventResource.id = events[i].id;
				if (!_isDeletedGoogleEvent(events[i].id)){
					pushSyncInfo(g_loc_createwizevent + g_loc_colon + wizEventResource.title);
					g_app.DoEvents();
					try{
						wizCreateFullEventTest(wizEventResource);
					}catch(err){
						toLog("Create wiz event failed. wizCreateFullEventTest, e: " + err);
						toLog("error wiz event resource start: ");
						for (var name in wizEventResource){
							toLog("wizEventResource." + name + " = " + wizEventResource[name] + ";");
						}
						toLog("error wiz event resource end.");
					}
					g_app.DoEvents();	
				}
			}	
			//
			try {
				g_app.DoEvents();
				//window.external.WriteLog("my log");
			}
			catch (err){
			}
		}
		// toLog("_createOrModifyWizEvents end.");
	}
	function _invalidGoogleEvent(id, gooIdMap){
		return !(gooIdMap[id]);
	}
	function _createGooIdMap(events, gooIdMap, value){
		for (var i = 0; i < events.length; i++) {
			if (events[i].id){
				gooIdMap[events[i].id] = value;
			}
		};
	}
	function _removeInvalidWizEvents(events, tag){
		var eventIdMap = {};
		_createGooIdGUIDMap(eventIdMap, tag);
		var gooIdMap = {};
		if (events)
			_createGooIdMap(events, gooIdMap, true);
		for (var key in eventIdMap) {
			var gooEventId = key;
			var wizEventId = eventIdMap[key];
			if (_invalidGoogleEvent(gooEventId, gooIdMap)){
				var doc = g_db.DocumentFromGUID(wizEventId);
				if (!doc){
					continue;
				}
				pushSyncInfo(g_loc_deletewizevent + g_loc_colon + doc.Title);
				g_app.DoEvents();
				wizDeleteEvent(wizEventId);
			}
		}
	}
	function _updateWizCalendar(events){
		if (events)
			_createOrModifyWizEvents(events);
		// TODO: 删除有问题。
	}
	
	//////////////////////////////////////////////////////////////////
	
	function _validGoogleEvent(id, idMap){
		return idMap[id];
	}
	function _createGooEventUpdateMap(events, gEventUpdateMap){
		if (!events)
			return;
		for (var i = 0; i < events.length; i++) {
			// toLog("summary: " + events[i].summary + ", updated: " + events[i].updated);
			gEventUpdateMap[events[i].id] = events[i].updated;
		};
	}
	function _getGoogleUntilStr(wizRptEnd){
		return (wizRptEnd.substr(0, 10)).replace(/-/g, '');
	}
	function _getGoogleRRuleVal(wizRptRule){
		var ruleValArray;
		if (wizRptRule == "EveryWeekday"){
			ruleValArray = [1, 2, 3, 4, 5];
		}else {
			ruleValArray = (wizRptRule.replace(/[^0-9]/ig, '')).split('');	
		}
		
		var ruleVal = '';

		for (var i = 0; i < ruleValArray.length; i++) {
			ruleVal += g_wizDay2GooByDay[ruleValArray[i]] + ',';
		}
		ruleVal = ruleVal.substr(0, ruleVal.length - 1);
		return ruleVal;
	}
	function getBaseRepeatRuleVal(baseRule){
		if (typeof(g_wizRptRule2GooRule) != "object"){
			return;
		}
		return g_wizRptRule2GooRule[baseRule];
	}
	function _getGoogleRRule(recurArray, wizRptRule, wizRptEnd){
		var rRule = 'RRULE:';
		// 
		if (!wizRptRule)
			return;
		var baseRule = wizRptRule.replace(/[0-9]/ig, '');
		var baseRuleVal = getBaseRepeatRuleVal(baseRule);
		if (!baseRuleVal){
			return;
		}
		rRule += "FREQ=" + baseRuleVal;
		var ruleVal = _getGoogleRRuleVal(wizRptRule);
		rRule += (ruleVal? ";BYDAY=" + ruleVal : "");
		if (wizRptEnd){
			rRule += ';' + "UNTIL=" + _getGoogleUntilStr(wizRptEnd);
		}
		// 
		recurArray.push(rRule);
	}
	function _getGoogleReminders(googleOldEvent, wizEvent){

		var reminders = googleOldEvent.reminders;
		if (!(reminders) || !(wizEvent.remind))
			return;
		if (!(reminders.overrides))
			reminders.overrides = [];
		if (reminders.useDefault == true){
			reminders.useDefault = false;
			reminders.overrides = reminders.overrides.concat(g_gooEventEntryResource.defaultReminders);
		}
		if (wizEvent.remind != '-1')
			reminders.overrides.push({"method": "popup", "minutes": (Number(wizEvent.remind) / 60)});
		return reminders;
	}
	// TODO: 修改改成只修改需要修改的项,包括函数内部用到googleOldEventObj的子函数。
	function changeDateTimeOffset(dateTime){
		var date = new Date(dateTime);
		date.setHours(date.getHours() - 8);
		var dateStr = _d2s(date);
		return dateStr.substr(0, 10) + 'T' + 
			   dateStr.substr(11) + "Z";
	}
	function _getGoogleEventObj(wizEventObj, googleOldEventObj){
		var googleEventObj = {};
		googleEventObj.summary = wizEventObj.title;
		var start = _2GoogleEventStartTime(wizEventObj.start, 
										wizEventObj.end);
		googleEventObj.start = start;
		var end = _2GoogleEventEndTime(wizEventObj.start, 
										wizEventObj.end);
		googleEventObj.end = end;
		googleEventObj.description = wizEventObj.content;
		var recur = [];
		_getGoogleRRule(recur, wizEventObj.rptRule, wizEventObj.rptEnd);
		
		if (recur.length != 0 && googleEventObj.start.dateTime){
			googleEventObj.start.dateTime = changeDateTimeOffset(googleEventObj.start.dateTime);
			googleEventObj.start.timeZone = "UTC";
			googleEventObj.end.dateTime = changeDateTimeOffset(googleEventObj.end.dateTime);
			googleEventObj.end.timeZone = "UTC";
		}
		// 
		googleEventObj.recurrence = recur;
		if (googleOldEventObj && (googleOldEventObj.colorId)){
			googleEventObj.colorId = googleOldEventObj.colorId;
		}
		// 
		if (googleOldEventObj)
			googleEventObj.reminders = _getGoogleReminders(googleOldEventObj, wizEventObj);

		if (wizEventObj.colorId && wizEventObj.colorId != 0){
			googleEventObj.colorId = g_eventColorIdWiz2Google[wizEventObj.colorId];
		}

		return googleEventObj;
	}
	function getGoogleCalendarTag(tagSet){
		if (tagSet.indexOf(WIZ_GOOGLE_CALENDAR_TAG) == -1){
			return undefined;
		}
		var tagArray = tagSet.split(';');
		for (var i in tagArray){
			if (tagArray[i].indexOf(WIZ_GOOGLE_CALENDAR_TAG) != -1){
				return tagArray[i];
			}
		}
	}
	function _getCalendarIdForUpdate(eventResource){
			if (eventResource && eventResource.organizer)
				return eventResource.organizer.email;
			var eventTag = getGoogleCalendarTag(eventResource.tag);
			if (!eventTag)
				return g_calendarDefaultId;
			var calendarId = getGoogleCalendarIdMeta(eventResource.tag);
			if (!calendarId)
				return g_calendarDefaultId;
			return calendarId;
	}
	function _updateGoogleEvent(gooEventId, googleOldEvent, wizEventResource, callback){
		if (!wizEventResource)
			return;
		var calendarId = _getCalendarIdForUpdate(wizEventResource);
		var _update = function(resp){
			var sequence = resp.sequence;
			
			var googleEventRes = _getGoogleEventObj(wizEventResource, googleOldEvent);
			googleEventRes.sequence = sequence;

			var getUpdateAjaxUrl = function(googleEventId, calendarId){
				var urlBase = g_urlBase + "calendar/v3/calendars/";
				return urlBase +  encodeURIComponent(calendarId) + "/events/" + googleEventId + "?key=" + g_apiKey;
			}
			var url = getUpdateAjaxUrl(gooEventId, calendarId);
			pushSyncInfo(g_loc_updategoogleevent + g_loc_colon + wizEventResource.title);
		    $.ajax({
				url: url,
				type: "PUT",
				error: function(jqXHR, errorMsg){
					callback(wizEventResource, errorMsg, false);
				},
				success: function(resp){
					if (!(resp.error))
						callback(wizEventResource, resp, true);
					else {
						callback(wizEventResource, resp, false);
					}
				},
				data: JSON.stringify(googleEventRes),
				contentType: "application/json",
				headers: {
					Authorization: "Bearer " + g_accessToken
				}
		    }).done();
		}
		var getEventSequenceAjaxUrl = function(googleEventId, calendarId){
			var url = g_urlBase + "calendar/v3/calendars/";
			return url + encodeURIComponent(calendarId) + "/events/" + googleEventId + "?key=" + g_apiKey + "&access_token=" + g_accessToken + "&fields=sequence";
		}
		var url = getEventSequenceAjaxUrl(gooEventId, calendarId);
		$.ajax({
			url: url,
			type: 'GET',
			success: function(resp){
				if (!(resp.error))
					_update(resp);
				else {
					callback(wizEventResource, resp);
				}
			},
			error: function(jqXHR, errorMsg){
				callback(wizEventResource, errorMsg);
			}
		}).done();
	}
	// TODO: 当所有http请求失败后，打印url，和数据。
	var g_resource;
	function logSyncErrorMessage(){
		if (!g_resource){
			toLog("g_resource is invalid.");
			return;
		}
		logObject(g_resource);
		g_resource = undefined;
	}
	function setResourceForLog(res){
		g_resource = res;
	}
	function _createGoogleEvent(eventResource, callback){

		var googleEventRes = _getGoogleEventObj(eventResource);
		var calendarId = _getCalendarIdForUpdate(eventResource);
		var handleInsertEventResponse = function(resp, calendarId){
			if (!g_db)
				return;
			if (!eventResource)
				return;
			var doc = g_db.DocumentFromGUID(eventResource.guid);
			if (!doc)
				return;
			setParamValue(doc, "CALENDAR_GOOEVENTID", resp.id);
			var tag = getTagNameByGoogleCalendarId(calendarId);
			if (!tag){
				toLog("_createGoogleEvent get Google tag failed.");
			}else {
				var wizTag = makeWizTag(doc, tag);
				if (wizTag){
					doc.SetTagsText2(wizTag, "Calendar");
				}else {
					toLog("_createGoogleEvent handleInsertEventResponse wizTag failed.");
				}
			}
		}
		var getInsertAjaxUrl = function(calendarId){
			var urlBase = g_urlBase + "calendar/v3/calendars/";
			return urlBase + encodeURIComponent(calendarId) + "/events" + "?key=" + g_apiKey;
		}
		pushSyncInfo(g_loc_creategoogleevent + g_loc_colon + eventResource.title);
		
		setResourceForLog(googleEventRes);
		var url = getInsertAjaxUrl(calendarId);
	    $.ajax({
			url: url,
			type: "POST",
			error: function(jqXHR, errorMsg){
				toLog("Insert event error :" + errorMsg);
				toLog(url);
				logSyncErrorMessage();
				callback(eventResource, errorMsg);
			},
			success: function(resp){
				handleInsertEventResponse(resp, calendarId);
				callback(eventResource, null);
			},
			data: JSON.stringify(googleEventRes),
			contentType: "application/json",
			headers: {
				Authorization: "Bearer " + g_accessToken
			}
	    }).done();
	}
	function _createGoogleEventMap(events){
		var eventMap = {};
		for (var i = 0; i < events.length; i++) {
			eventMap[events[i].id] = events[i];
		};
		return eventMap;
	}
	function _createOrModifyGoogleEvents(events, callback){
		if (events){
			// TODO： 不清楚 需要修改，找到更好的方法
			var eventIdMap = {};
			_createGooIdGUIDMapTest(eventIdMap);
			var gEventUpdateMap = {};
			_createGooEventUpdateMap(events, gEventUpdateMap);
			var googleEventMap = _createGoogleEventMap(events);

			var eventIdArray = _object2Array(eventIdMap);
			function errorMessage(errMsg){
				toLog("Can't update google event: " + errMsg);
			}
			function modifyNextEvent(){
				if (eventIdArray.length == 0){
					_insertGoogleEvent();
					return;
				}
				var idObj = eventIdArray.pop();
				var googleEventId = idObj[0];
				var wizEventId = idObj[1];

				var doc = _docFromGUID(wizEventId);
				if (!doc){
					modifyNextEvent();
				}
				var wizEventMdfy = new Date(doc.DateModified);
				if (gEventUpdateMap[googleEventId]){
					var gooEventUpd = _s2d(_dateTime2DateStr(gEventUpdateMap[googleEventId]));
					// toLog("WizModify: " + wizEventMdfy);
					// toLog("Google Update: " + gooEventUpd);
					if (wizEventMdfy.getTime() > gooEventUpd.getTime()){
						var wizEventResource = _eventObject(_newPseudoDoc(doc));
						_updateGoogleEvent(googleEventId, googleEventMap[googleEventId], wizEventResource, function(eventResource, resp, bSuccessed){
							if (!bSuccessed){
								errorMessage(eventResource.title);
							}
							if (resp && resp.updated){
								doc.DateModified = _dateTime2DateStr(resp.updated);
							}else {
								toLog("unknown failed after _updateGoogleEvent.");
							}
							modifyNextEvent();
						});
					}else {
						modifyNextEvent();
					}
				}else {
					modifyNextEvent();
				}
			}
			modifyNextEvent();
		}
		//
		function _insertGoogleEvent(){
			var wizEvents = [];
			var start = new Date();
			start.setMonth(start.getMonth() - 3);
			_getAllOriginalEvent(wizEvents, _d2s(start));
			//
			function createNextEvent() {
				if (wizEvents.length == 0){
					// 	
					callback();
					return;
				}
				//
				var nextEvent = wizEvents.pop();
				//
				if (!nextEvent.googleEventId) {
					var doc = _docFromGUID(nextEvent.guid);
					if (doc) {
						nextEvent.content = getDocText(doc);
						nextEvent.tag = doc.TagsText;
					}
					_createGoogleEvent(nextEvent, function(eventResource, err) {
							if (err)
							{
								toLog("Can't create event on google calendar: " + eventResource.title + "\n\n" + err.toString());
							}
							//
							createNextEvent();
						}
					);
				}else {
					createNextEvent();
				}
			}
			createNextEvent();
		}
		//
	}
	// TODO：删除多帐号event还没做好。
	function getDeleteGoogleCalendarId(tagVal){
		return getGoogleCalendarIdMeta(tagVal);
	}
	function _removeInvalidGoogleEvents(callback){
		// 
		if (!g_db)
			return;
		var googleEventIds = getGoogleDeleteEventMeta();
		if (!googleEventIds){
			callback();
			return;
		}
		var idArray = googleEventIds.split(';');
		var getDeleteAjaxUrl = function(googleEventId, calendarId){
			var urlBase = g_urlBase + "calendar/v3/calendars/";
			return urlBase + encodeURIComponent(calendarId) + "/events/" + googleEventId + "?key=" + g_apiKey +"&access_token=" + g_accessToken;
		}
		function deleteGoogleEvent(googleEventId, calendarId, callback){
			var url = getDeleteAjaxUrl(googleEventId, calendarId);
			// TODO: upload delete google event;
			$.ajax({
				url: url,
				type: 'DELETE',
				error: function(jqXHR, errorMsg){
					callback(googleEventId, errorMsg);
				},
				success: function(resp){
					if (!(resp.error)){
						callback(googleEventId, null);
					}else {
						callback(googleEventId, resp);
					}
				}
			}).done();			

		}
		function deleteNextEvent(){
			if (idArray.length == 0){
				callback();
				return;
			}
			var metaVal = idArray.pop();
			var calendarId = getDeleteGoogleCalendarId(metaVal.substr(0, metaVal.indexOf(':')));
			var googleEventId = metaVal.substr(metaVal.indexOf(':') + 1);

			deleteGoogleEvent(googleEventId, calendarId, function(eventId, err){
				if (err){
					toLog("Can't delete google event id: " + eventId);
				}
				deleteNextEvent();
			});
		}
		// 
		resetGoogleDeleteEventMeta();

		// 
		deleteNextEvent();
	}
	function _updateGoogleCalendar(events, callback){
		_createOrModifyGoogleEvents(events, function(){
			//
			_removeInvalidGoogleEvents(function(){
				callback();
			});
		});
	}
	function _getGoogleTimeMax(visEnd){
		var end = new Date(visEnd);
		end.setDate(end.getDate() - 1);
		return end;
	}
	function _getGoogleTimeMin(visStart){
		var start = new Date(visStart);
		start.setDate(start.getDate() - 1);
		return start;
	}
	function syncCompleted(){
		toLog("Sync google calendar end.");
		wizUpdateLayout();
		wizRenderAllEvent();
		document.title = g_loc_googlecalendarsyncsucceeded;
		hiddenBubbleBg();
		pushSyncInfo(g_loc_googlecalendarsyncsucceeded);
		setTimeout(function(){ document.title = g_loc_calendar; hiddenSyncBubble();}, 500);
	}
	
	function _getGoogleEvents(handleListEventResponse, callback){
		if (!g_calendarId)
			return;
		var m_events = [];
		var getEventsWithPageToken = function(url, pageToken){
			var baseUrl = url;
			var url = baseUrl + "&pageToken=" + pageToken;
			$.ajax({
				url: url,
				type: 'GET',
				success: function(resp){

					if (!(resp.error)){
						if (resp.items){
							m_events = m_events.concat(resp.items);
						}
						if (resp.nextPageToken){
							getEventsWithPageToken(baseUrl, resp.nextPageToken);
						}else {
							handleListEventResponse(m_events, callback);
						}
					}else {
						toLog("get event list error1: " + resp.error.code);
					}
				},
				error: function(jqXHR, errorMsg){
					toLog("get event list error2: " + errorMsg);
				}
			}).done();

		}
		var listEventsCallBack = function(){
			if (!g_cal){
				g_cal = $('#calendar');
			}
			if (!g_cal)
				return;	
			var timeMin = new Date();
			timeMin.setMonth(timeMin.getMonth() - 3);

			timeMin = _date2DateTime(timeMin);
			// timeMax = _date2DateTime(timeMax);

			var getEventListAjaxUrl = function(timeMin){
				var urlBase = g_urlBase + "calendar/v3/calendars/";
				return urlBase + encodeURIComponent(g_calendarId) + "/events?key=" + g_apiKey + "&access_token=" + g_accessToken + 
						"&timeMin=" + timeMin;
			}
			var url = getEventListAjaxUrl(encodeURIComponent(timeMin));
			$.ajax({
				url: url,
				type: 'GET',
				success: function(resp){	
					if (!(resp.error)){
						// 
						g_gooEventEntryResource = resp;
						// 
						if (resp.items){
							m_events = m_events.concat(resp.items);
						}
						if (resp.nextPageToken){
							getEventsWithPageToken(url, resp.nextPageToken);
						}else {
							handleListEventResponse(m_events, callback);
						}
					}else {
						toLog("get event list error3: " + resp.error.code);
					}
				},
				error: function(jqXHR, errorMsg){
					if (JSON && JSON.parse){
						try{
							var errObj = JSON.parse(jqXHR.responseText);
							if (errObj)
								handleListEventResponse(errObj, callback);
						}catch(err){
							toLog("listEventsCallBack() JSON.parse throw.");
							toLog("jqXHR.responseText: " + jqXHR.responseText);
							toLog("url: " + url);
						}
					}else {
						toLog("get event list error4: " + errorMsg);
					}
				}
			}).done();
		}
		listEventsCallBack();
	}
	function getGoogleCalendarColor(){
		if (!g_calendarId)
			return;
		var getColorsAjaxUrl = function(){
			var urlBase = g_urlBase + "calendar/v3/colors?key=";
			return urlBase + g_apiKey + "&access_token=" + g_accessToken;
		}
		var url = getColorsAjaxUrl();
		$.ajax({
			url: url,
			type: 'GET',
			success: function(resp){
				if (!(resp.error))
					g_googleColorEntry = resp;
				else {
					toLog("get Colors error: " + resp.error.code);
				}
			},
			error: function(jqXHR, errorMsg){
				toLog("get colors error: ", errorMsg);
			}
		}).done();		
	}
	function cloneGoogleCalendarIds(googleCalendarIds){
		var ids = [];
		for (var i = 0; i < googleCalendarIds.length; i ++){
			ids.push(googleCalendarIds[i].id);
		}
		return ids;
	}
	var eventsForUpdateGoogle = [];
	function handleListEventResponseWizCalendar(events, callback){
		if (events){
			if (events.length != 0)
				eventsForUpdateGoogle = eventsForUpdateGoogle.concat(events);
			//
			if (events.length != 0){
				var tag = _getGoogleEventTag(events[0].organizer);
				setGoogleCalendarIdMeta(tag, g_calendarId);
			}
			//
			_updateWizCalendar(events);
			var tagName = getTagNameByGoogleCalendarId(g_calendarId);
			if (tagName){
				_removeInvalidWizEvents(events, tagName);
			}
		}

		callback();
	}
	function handleAllCalendarId(){
		var events = eventsForUpdateGoogle;
		_updateGoogleCalendar(events, function() {
			syncCompleted();
		});
	}
	function getDefaultGoogleCalendarId(handle){
    	var getUserInfoAjaxUrl = function(accessToken){
    		var urlBase = g_urlBase + "oauth2/v1/userinfo?access_token=";
    		return urlBase + accessToken;
    	}
		var url = getUserInfoAjaxUrl(g_accessToken);
		$.ajax({
			url: url,
			type: 'GET',
			success: function(resp){
				if (!(resp.error)){
						g_calendarDefaultId = resp.email;
						// setCookie("WizGoogleId", g_calendarDefaultId);
						setDefaultGoogleCalendarIDToDb(g_calendarDefaultId);
						handle();
					}else {
					toLog("get UserInfo error: " + resp.error.code);
				}
			},
			error: function(jqXHR, errorMsg){
				toLog("get user info. error: ", errorMsg);
			}
		}).done();
	}
	// function setCalendarListEntry(entry, calendarId){
	// 	for (var i = 0; i < entry.length; i ++){
	// 		if (calendarId == entry[i].id){
	// 			g_googleCalendarListEntry = entry[i];
	// 			break;
	// 		}
	// 	}
	// }
	function testIsSync(id){
		if (id.indexOf("group.v.calendar.google.com") != -1){
			return false;
		}else {
			return true;
		}
	}
	function getChooseIdsHtml(){
		var html = "<div id='chooseGoogleCalendarId'>" + 
						"<div id='cGC-main'>" +
							"<div id='cGC-idContainer'>" +  
							"</div>" + 
							"<div id='cGC-button'>" + 
								"<input id='cGC-persist' type='checkbox'/><label for='cGC-persist'>记住选择</label>" + 
								"<span id='cGC-checkAll' class='fc-button fc-button-content'>全选</span>" +
								"<span id='cGC-discard' class='fc-button fc-button-content'>取消</span>" +  
								"<span id='cGC-submit' class='fc-button fc-button-content'>确定</span>" +  
							"</div>" + 
						"</div>" + 
				   "</div>";
		
		return html;
	}
	function getChosenIdsFromDb(){
		var ids;
		try{
			ids = getMeta("GOOGLECALENDAR", "CHOSENCALENDARID");
		}catch(err){
			toLog("Get chosen ids from database throw a exception.");
			return;
		}
		return ids;
	}
	function setChosenIdsToDb(ids){
		try {
			setMeta("GOOGLECALENDAR", "CHOSENCALENDARID", ids);
		}catch(err){
			toLog("Set chosen ids to database throw a exception.");
		}
	}
	function isPersist(id, persistIds){
		if (!persistIds){
			return false;
		}
		if (persistIds.indexOf(id) != -1){
			return true;
		}else {
			return false;
		}
	}
	function cancelBubble($main){
		hiddenBubbleBg();
		$main.css("visibility", "hidden");
	}
	var g_selectedGoogleCalendars;
	function setSelectedGoogleCalendars(calendars){
		g_selectedGoogleCalendars = calendars;
	}
	function getSelectedGoogleCalendars(){
		return g_selectedGoogleCalendars;
	}
	function getSummaryFromListEntry(id, listEntry){
		for (var i = 0; i < listEntry.length; i ++){
			if (listEntry[i].id == id){
				return listEntry[i].summary;
			}
		}
		return;
	}
	function saveGoogleCalendarIdAndSummary(listEntry, selectedIds){
		clearGoogleCalendarIdMeta();
		for (var i = 0; i < selectedIds.length; i ++){
			var summary = getSummaryFromListEntry(selectedIds[i], listEntry);
			if (!summary){
				toLog("saveGoogleCalendarIdAndSummary get summary error.");
				continue;
			}else {
				setGoogleCalendarIdMeta(makeGoogleEventTag(summary), selectedIds[i]);
			}
		}

	}
	function filterAndOrPersistCalendarIds(listEntry, callback){
		// 取得bubble跟节点jquery对象
		$main = $("#chooseGoogleCalendarId");
		// 判断对象是否存在，不存在就创建一个
		if ($main.length == 0){
			// 	获取html代码
			var html = getChooseIdsHtml();
			// 	插入到页面代码中
			$(document.body).append(html);
			// 	取得bubble根节点jquery对象
			$main = $("#chooseGoogleCalendarId");
			// 	阻断页面的mousedown事件冒泡。
			$main.mousedown(function(e){
				stopBubble(e);
				return true;
			});
		}
		// 删除所有ids的checkbox父节点的所有儿子节点。
		$container = $("#cGC-idContainer");
		$container.children().remove();
		$container.html("");
		//
		// 读取数据库中的ids。
		var ids = getChosenIdsFromDb();
		// 根据listEntry初始化页面。
		for (var i = 0; i < listEntry.length; i ++){
			var childHtml = "<input type='checkbox'" + 
							" value='" + listEntry[i].id + "'" + 
							(isPersist(listEntry[i].id, ids) ? (" checked='true'"): '')+ 
							"/>" + listEntry[i].summary + "</br>";
			$container.append(childHtml);
		}
		// 根据数据库中的ids与listEntry，判断“记住选择”的状态。
		var persisted = false;
		for (var i = 0; i < listEntry.length; i ++){
			if (isPersist(listEntry[i].id, ids)){
				persisted = true;
			}
		}
		// 	设置记住选择被选中
		$persist = $("#cGC-persist");
		$persist.attr("checked", persisted);

		// //
		// 初始化“全选”click事件处理函数。
		$checkAll = $("#cGC-checkAll");
		$checkAll.unbind('click').bind('click', function(){
			// 	把所有的id都设为选中状态
			$container.children("input").each(function(){
				$(this).attr("checked", true);
			});
		});
		// //
		// 初始化“取消”click事件处理函数。
		$discard = $("#cGC-discard");
		$discard.unbind('click').bind('click', function(){
			// 	调用取消bubble操作的子程序
			cancelBubble($main);
			// 	调用回调函数。返回undefined。
			callback(undefined);
		});
		// //
		// 初始化“确定”click事件处理函数。
		$submit = $("#cGC-submit");
		$submit.unbind('click').bind('click', function(){
			// 	根据checkbox的选中状态获得需要同步的ids。
			var chosenIds = [];
			$container.children("input").each(function(){
				if ($(this).attr("checked") == "checked"){
					chosenIds.push($(this).attr("value"));
				}
			});
			// 	如果记住选择被选中，重置数据库中的ids；否则，删除数据库中的ids。
			var persistIds = chosenIds.join(';');
			setSelectedGoogleCalendars(persistIds);
			if ($persist.attr("checked")){
				setChosenIdsToDb(persistIds);
			}
			saveGoogleCalendarIdAndSummary(listEntry, chosenIds);
			// 	调用取消bubble操作的子程序
			cancelBubble($main);
			// 	调用回调函数，返回选择的ids数组。
			callback(chosenIds);
		});

		// 使页面背景变灰。
		setBubbleBg();
		// 取得bubble现在在页面中心对应的坐标。
		var center = getBubbleCenterCoordinate($main);
		// 显示bubble页面。
		$main.css({"visibility": "visible", "top": center.top, "left": center.left});
	}
	function getGoogleCalendarIds(){
		var ids = getSelectedGoogleCalendars();
		if (ids){
			return ids.split(';');
		}
		var ids = getChosenIdsFromDb();
		if (ids){
			return ids.split(';');
		}
		return;
	}

	function wizGoogleCalendarSync(googleCalendarListEntry){
		// must be [].
		eventsForUpdateGoogle = [];
		//
		if (!googleCalendarListEntry){
			toLog("wizGoogleCalendarSync googleCalendarListEntry is Invalid.");
			return;
		}
		getGoogleCalendarColor();
		//
		function SyncStart(ids){
			
			function syncNextCalendar(){
				if (ids.length == 0){
					getDefaultGoogleCalendarId(handleAllCalendarId);
					return;
				}
				g_calendarId = ids.pop();
				// setCalendarListEntry(googleCalendarListEntry, g_calendarId);
				_getGoogleEvents(handleListEventResponseWizCalendar, function(){
					syncNextCalendar();
				});
				//
			}
			if (!ids){
				syncCompleted();
				return;
			}else {
				syncNextCalendar();
			}
		}
		var ids = getGoogleCalendarIds();
		if (!ids){
			filterAndOrPersistCalendarIds(googleCalendarListEntry, SyncStart);
		}else {
			SyncStart(ids);
		}
	}
	var g_clientId = "269882143566.apps.googleusercontent.com";
	var g_scope = "https://www.googleapis.com/auth/calendar+https://www.googleapis.com/auth/userinfo.email";
  	function setCookie(key, accessToken){
  		var expires = new Date();
  		expires.setFullYear(expires.getFullYear() + 1);
  		Cookies.set(key, accessToken, expires);
  	}
  	function getCookie(key){
  		return Cookies.get(key);
  	}  
	function getCalendarListEntry(){
		var getListAjaxUrl = function(){
			var urlBase = g_urlBase + "calendar/v3/users/me/calendarList/";
			return urlBase + "?key=" + g_apiKey + "&access_token=" + g_accessToken;
		}	
		var url = getListAjaxUrl();
		$.ajax({
			url: url,
			type: 'GET',
			success: function(resp){
				if (!(resp.error)){
					wizGoogleCalendarSync(resp.items);
				}
				else {
					toLog("success: Get CalendarList error: " + resp.error.code);
				}
			},
			error: function(jqXHR, errorMsg){
				toLog("error: Get calendarList error.");
			}
		}).done();
	}
	function wizSetWindowTitle(title){
		document.title = title;
	}
	function getAccessTokenFromCookie(){
		var accessToken = getCookie("WizGCalendarToken");
		return accessToken;
	}	
	function getAccessTokenFromDb() {
		var accessToken = getMeta("GOOGLECALENDAR", "token");
		return accessToken;
	}
	function setAccessTokenToDb(accessToken) {
		setMeta("GOOGLECALENDAR", "token", accessToken);
	}
	function getDefaultGoogleCalendarIDFromDb() {
		return getMeta("GOOGLECALENDAR", "defaultcalendarid");
	}
	function setDefaultGoogleCalendarIDToDb(id) {
		setMeta("GOOGLECALENDAR", "defaultcalendarid", id);
	}
  	function authorize(){
    	var getRedirectUri = function(){
    		var htmlName = "files/SetToken.html";
    		return g_urlBase + htmlName;
    	}
    	var getAuthUrl = function(){
    		var urlBase = "https://accounts.google.com/o/oauth2/auth";
    		var redirectUri = getRedirectUri();
    		var url = urlBase + "?scope=" + g_scope + '&' + 
    				  "state=profile&" + 
       				  "redirect_uri=" + redirectUri + '&' + 
       				  "response_type=token&" + 
       				  "client_id=" + g_clientId + '&' + 
       				  "approval_prompt=force";

       		// var accessToken = getAccessTokenFromDb();
       		// if (!accessToken){
       		// 	url += "&approval_prompt=force"; 
       		// }
       		return url;
    	}
    	var url = getAuthUrl();
    	var htmlDialogWidth = 500;
    	var htmlDialogHeight = 520;
    	try { 
    		g_app.Window.ShowHtmlDialog2(document, 'OnHtmlDialogClosed', '', url, htmlDialogWidth, htmlDialogHeight, 0, 0);
    	}
    	catch(e) {
    		var accessToken = g_app.Window.ShowHtmlDialog('', url, htmlDialogWidth, htmlDialogHeight, 0, 0);
    		OnHtmlDialogClosed(accessToken);
    	}
  	}
  	function OnHtmlDialogClosed(ret) {
  		var accessToken = ret;
  		//
    	if (!accessToken){
    		alert(g_loc_validatefail);
    		wizSetWindowTitle(g_loc_calendar);
    		hiddenSyncBubble();
    		hiddenBubbleBg();
    		return;
    	}else {
    		// setCookie("WizGCalendarToken", accessToken);
    		setAccessTokenToDb(accessToken);
    		g_accessToken = accessToken;
    		getCalendarListEntry();
    	}  		
  	}
  	function _getTokenAjaxUrl(accessToken){
  		var url = g_urlBase + "oauth2/v2/tokeninfo?access_token=";
  		return url + accessToken;
  	}
	function validateToken(accessToken){
		var url = _getTokenAjaxUrl(accessToken);

		$.ajax({
			url: url,
			type: 'GET',
			success: function (resp) {
				if (!(resp.error) && (resp.error_description != "Invalid Value")){
					getCalendarListEntry();
				}else {
					toLog("success: Get tokenInfo error: " + resp.error.code);
				}
			},
			error: function (jqXHR, errorMsg) {
				toLog("error: Get tokenInfo error: " + errorMsg);
				toLog(url);
				authorize();
			}
		}).done();
	}

	function wizSyncGoogleCalendar(){
		wizSetWindowTitle(g_loc_googlecalendarsyncstart);
		setBubbleBg();
		googleSyncPage();
		pushSyncInfo(g_loc_googlecalendarsyncstart);
		_googleCalendarSyncInitUrlBase();
		toLog("Sync google calendar start.");
		var accessToken = getAccessTokenFromDb();
		g_accessToken = accessToken;
		if (accessToken){
			validateToken(accessToken);
		}else {
			authorize();
		}
	}
	function setGoogleCalendarIds_select(listEntry){
		if (!listEntry){
			toLog("listEntry Invalid.");
			return;
		}
		filterAndOrPersistCalendarIds(listEntry, function(){
			toLog("Set Google calendar success.");
		});
		toLog("Set Google calendar end.");
	}
	function getCalendarListEntry_select(){
		var getListAjaxUrl = function(){
			var urlBase = g_urlBase + "calendar/v3/users/me/calendarList/";
			return urlBase + "?key=" + g_apiKey + "&access_token=" + g_accessToken;
		}
		var url = getListAjaxUrl();
		$.ajax({
			url: url,
			type: 'GET',
			success: function(resp){
				if (!(resp.error)){
					setGoogleCalendarIds_select(resp.items);
				}
				else {
					toLog("_select success: Get CalendarList error: " + resp.error.code);
				}
			},
			error: function(jqXHR, errorMsg){
				toLog("_select error: Get calendarList error.");
			}
		}).done();
	}	
	function authorize_select(){
    	var getRedirectUri = function(){
    		var htmlName = "files/SetToken.html";
    		return g_urlBase + htmlName;
    	}
    	var getAuthUrl = function(){
    		var urlBase = "https://accounts.google.com/o/oauth2/auth";
    		var redirectUri = getRedirectUri();
    		return urlBase + "?scope=" + g_scope + '&' + 
    				"state=profile&" + 
       				"redirect_uri=" + redirectUri + '&' + 
       				"response_type=token&" + 
       				"client_id=" + g_clientId;
    	}
    	var url = getAuthUrl();
    	var htmlDialogWidth = 500;
    	var htmlDialogHeight = 500;
    	try { 
    		g_app.Window.ShowHtmlDialog2(document, 'OnHtmlDialogClosed_ForSelect', '', url, htmlDialogWidth, htmlDialogHeight, 0, 0);
    	}
    	catch(e) {
    		var accessToken = g_app.Window.ShowHtmlDialog('', url, htmlDialogWidth, htmlDialogHeight, 0, 0);
    		OnHtmlDialogClosed(accessToken);
    	}
  	}
  	function OnHtmlDialogClosed_ForSelect(ret) {
  		var accessToken = ret;
  		//
    	if (!accessToken){
    		alert(g_loc_validatefail);
    		hiddenSyncBubble();
    		hiddenBubbleBg();
    		return;
    	}else {
    		// setCookie("WizGCalendarToken", accessToken);
    		setAccessTokenToDb(accessToken);
    		g_accessToken = accessToken;
    		getCalendarListEntry_select();
    	}  		
  	}

	function validateToken_select(accessToken){
		var url = _getTokenAjaxUrl(accessToken);
		$.ajax({
			url: url,
			type: 'GET',
			success: function (resp) {
				if (!(resp.error) && (resp.error_description != "Invalid Value")){
					getCalendarListEntry_select();
				}else {
					toLog("success: Get tokenInfo error: " + resp.error.code);
				}
			},
			error: function (jqXHR, errorMsg) {
				toLog("error: Get tokenInfo error.");
				authorize_select();
			}
		}).done();
	}
	function wizSelectCalendarsForSync(){
		toLog("wizSelectCalendarsForSync start.");
		setBubbleBg();
		_googleCalendarSyncInitUrlBase();
		var accessToken = getAccessTokenFromCookie();
		g_accessToken = accessToken;
		if (accessToken){
			validateToken_select(accessToken);
		}else {
			authorize_select();
		}
	}
////////////////////////////////////////////////////////////
//
//	misc
	function formatIntToDateString(n){
		
		return n < 10 ? '0' + n : n;
	}
	function _d2s(dt){
       	//
        var ret = dt.getFullYear() + "-" + 
	    			formatIntToDateString(dt.getMonth() + 1) + "-" + 
	    			formatIntToDateString(dt.getDate()) + " " + 
	    			formatIntToDateString(dt.getHours())+ ":" + 
	    			formatIntToDateString(dt.getMinutes()) + ":" + 
	    			formatIntToDateString(dt.getSeconds());
        return ret;
    }
	function _s2d(str){
		if (!str)
			return '';
		var date = new Date(str.substr(0, 4),
						str.substr(5, 2) - 1,
						str.substr(8, 3),
						str.substr(11, 2),
						str.substr(14, 2),
						str.substr(17, 2)
						);		
		return date;
	}
	function EVENTOBJECT(data) {
		if (!data)
			return;
		//
		var newEvent = {};
		var isAllDay = data.CALENDAR_END.indexOf("23:59:59") != -1 ? true : false;
		var bkColor = _getEventBkColor(data.CALENDAR_INFO);
		var colorId = _getEventColorIdFromInfo(data.CALENDAR_INFO);
		var remind = _getRemindFromInfo(data.CALENDAR_INFO);
		//
		newEvent.id = data.guid;
		newEvent.title = data.title;
		newEvent.start = data.CALENDAR_START;
		newEvent.end = data.CALENDAR_END;
		// newEvent.content = data.text;
		newEvent.guid = data.guid;
		newEvent.allDay = isAllDay;
		newEvent.backgroundColor = '#' + bkColor;
		newEvent.colorId = colorId;
		newEvent.borderColor = getCalendarBorderColor();
		newEvent.textColor = 'black';//TODO;
		newEvent.rptRule = data.CALENDAR_RECURRENCE;
		newEvent.rptEnd = data.CALENDAR_ENDRECURRENCE;
		newEvent.remind = remind;
		newEvent.created = data.created;
		newEvent.updated = data.updated;
		// newEvent.tag = data.tags_text;
		newEvent.googleEventId = data.CALENDAR_GOOEVENTID; 
		//
		return newEvent;

	}
	function _eventObject(pseudoDoc){
		//
		if (pseudoDoc == '')
			return '';
		var newEvent = {};
		newEvent.id = pseudoDoc.guid;
		newEvent.title = pseudoDoc.title;
		newEvent.start = pseudoDoc.start;
		newEvent.end = pseudoDoc.end;
		newEvent.content = pseudoDoc.text;
		newEvent.guid = pseudoDoc.guid;
		newEvent.allDay = pseudoDoc.allDay;
		newEvent.backgroundColor = '#' + pseudoDoc.bkColor;
		newEvent.colorId = pseudoDoc.colorId;
		newEvent.borderColor = getCalendarBorderColor();
		newEvent.textColor = pseudoDoc.textColor;
		newEvent.rptRule = pseudoDoc.rptRule;
		newEvent.rptEnd = pseudoDoc.rptEnd;
		newEvent.remind = pseudoDoc.remind;
		newEvent.created = pseudoDoc.created;
		newEvent.updated = pseudoDoc.updated;
		newEvent.tag = pseudoDoc.tag;
		newEvent.googleEventId = pseudoDoc.googleEventId;
		
		return newEvent;
	}
	function _interDays(eventStart, eventEnd){
		var start = eventStart.substr(0, 10);
		var end = eventEnd.substr(0, 10);

		start = start.split('-');
		end = end.split('-');
		var startDate = new Date(start[0], parseInt(start[1] - 1), start[2]);
		var endDate = new Date(end[0], parseInt(end[1] - 1), end[2]);		
		var interTime = endDate.getTime() - startDate.getTime();
		var interDays = (interTime)/86400000 + 1;
		
		return interDays
	}
	function _getUrlParam(name) {
	    var reg = new RegExp("[?&]" + name + "=([^?&]*)[&]?", "i");
	    var match = location.search.match(reg);
	    return match == null ? "" : match[1];
	}
	function _removeStrPx(str){
		if (!str)
			return;
		if (str.indexOf("px") != -1){
			str = str.replace("px", "");
		}
		return Number(str);
	}
	function wizCreateDatepicker($obj, callback){
		var defaultHandle = function(date){
			var dateArr = date.split('-');
			wizChangeDate(dateArr);
		}
		var selectHandle = callback ? callback : defaultHandle;
		$obj.datepicker({
			showOtherMonths: true,
            selectOtherMonths: true,
			showWeek: false,
            firstDay: g_firstDay,
			autoSize: false,
			dateFormat: "yy-mm-dd",
			dayNamesMin: [g_loc_dtpicker_daynameshort_0, g_loc_dtpicker_daynameshort_1, 
			g_loc_dtpicker_daynameshort_2, 
			g_loc_dtpicker_daynameshort_3, 
			g_loc_dtpicker_daynameshort_4, 
			g_loc_dtpicker_daynameshort_5, 
			g_loc_dtpicker_daynameshort_6],
			monthNames: [g_loc_monthnameshort_1, g_loc_monthnameshort_2, g_loc_monthnameshort_3, g_loc_monthnameshort_4, g_loc_monthnameshort_5, g_loc_monthnameshort_6, g_loc_monthnameshort_7, g_loc_monthnameshort_8, g_loc_monthnameshort_9, g_loc_monthnameshort_10, g_loc_monthnameshort_11, g_loc_monthnameshort_12],
			weekHeader: g_loc_dtpicker_weekheader,
			navigationAsDateFormat: true,
			showMonthAfterYear: true,
			yearSuffix: g_loc_year,
			onSelect: selectHandle
		});
	}

	function canSyncGoogleCalendar(){
		if (document.location.href.indexOf("file:///") == -1){
			return true;
		}else {
			return false;
		}
	}

////////////////////////////////////////////////////////////
//
//	Init
	$(document).ready(function(){
		var date = new Date();
		var d = date.getDate();
		var m = date.getMonth();
		var y = date.getFullYear();
		var isFirst = true;
		
		var calendar = $('#calendar').fullCalendar({
			header: {
				left: 'prev,next,today',
				center: 'title',
				right: 'month,agendaWeek,agendaDay'
			},
			titleFormat:{
   				month: g_loc_titleformat_month,
    			week: g_loc_titleformat_week,
    			day: g_loc_titleformat_day
			},
			defaultView: wizGetView(),
			timeFormat: {
				month: '',
				week: 'H:mm{ - H:mm}',
				day: 'H:mm{ - H:mm}'
			},
			axisFormat: 'H(:mm)',
			buttonText: {
				today: g_loc_button_today,
				month: g_loc_button_month,
				week: g_loc_button_week,
				day: g_loc_button_day
			},
			firstHour: 8,
			monthNames:[g_loc_monthname_1, g_loc_monthname_2, g_loc_monthname_3, g_loc_monthname_4, g_loc_monthname_5, g_loc_monthname_6, g_loc_monthname_7, g_loc_monthname_8, g_loc_monthname_9, g_loc_monthname_10, g_loc_monthname_11, g_loc_monthname_12],
			monthNamesShort:[g_loc_monthnameshort_1, g_loc_monthnameshort_2, g_loc_monthnameshort_3, g_loc_monthnameshort_4, g_loc_monthnameshort_5, g_loc_monthnameshort_6, g_loc_monthnameshort_7, g_loc_monthnameshort_8, g_loc_monthnameshort_9, g_loc_monthnameshort_10, g_loc_monthnameshort_11, g_loc_monthnameshort_12],
			dayNames:[g_loc_dayname_0, g_loc_dayname_1, g_loc_dayname_2, g_loc_dayname_3, g_loc_dayname_4, g_loc_dayname_5, g_loc_dayname_6],
			dayNamesShort:[g_loc_daynameshort_0, g_loc_daynameshort_1, g_loc_daynameshort_2, g_loc_daynameshort_3, g_loc_daynameshort_4, g_loc_daynameshort_5, g_loc_daynameshort_6],
			aspectRatio: 1.0,
			selectable: true,
			selectHelper: true,
			allDayText: g_loc_allday,
			// 第一天是周一还是周天，与datepicker必须相同。
			firstDay: g_firstDay,
			//slotMinutes: 10,
			select: function(startDate, endDate, allDay, jsEvent, view){
				var doc = wizCreateEvent(startDate, endDate, allDay, jsEvent);
			},
			editable: true,
			eventSources: [],
			eventResize: function(event, dayDelta, minuteDelta, revertFunc, jsEvent, ui, view){
				if (event.id){
					//
					wizUpdateDocResize(event, dayDelta);
					
				}else {
					revertFunc();
				}
			},
			eventDragStart: function(event, jsEvent, ui, view) {

			},
			dragOpacity:{
				"month": .5,
				"agendaWeek": 1,
				"agendaDay": 1
			},
			eventDrop: function(event, dayDelta, minuteDelta, allDay, revertFunc){
				if (event.id){
					//
					wizUpdateDocDrop(event, dayDelta, minuteDelta, allDay);
				
				}else {
					revertFunc();
				}
			},
			eventDragStop: function(event, jsEvent, ui, view){
				// wizOnWindowResize();
			},
			viewDisplay: function(view){
				// 应该改成reRendarEvent
				wizOnWindowResize("changeView");
				wizSetView(view.name);	
				wizRenderAllEvent();
				// $(this).fullCalendar("rerenderEvents");
				// The html elements' coordinates error when FullCalendar's viewDisplay callback first invoke.
				if (!isFirst){
					wizRenderWeekNumber(view);
				}else {
					isFirst = false;
				}
			},
			eventClick: function(calEvent, jsEvent, view) {
				wizEditEvent(calEvent, jsEvent, view);
			},
			showChineseCalendar: function(date){
				return wizGetChineseDate(date);
			},
			eventMouseover: function(event, jsEvent, view){
				if (jsEvent.target && !(jsEvent.target.title)){
					jsEvent.target.title = event.title;
				}
			}
		});// end fullCalendar construction
		$('.fc-button-effect').remove();
	});// end ready
	$(document).ready(function(){
		
		function datePickerClick(){
			var main;
			var htmlStr = '<div id="bubbledp" style="z-index:180;position: absolute;visibility:hidden"></div>';
			$(document.body).append(htmlStr);

			main = $("#bubbledp");
			wizCreateDatepicker(main);
			main.mousedown(function(e){
				stopBubble(e);
				return true;
			});
			main.css({left: 0, top: 0});
			$(document.body).mousedown(function(){ main.css("visibility", "hidden");});
			return main;
		}
		function tagsFilterClick(){
			var main;
			var htmlStr = '<div id="bubbletag" style="z-index:180;position:absolute;width: 200px;visibility:hidden">' +
			'<select class="wiztag" id="wizTag" size="10"></select>' + '</div>';
			$(document.body).append(htmlStr);
			main = $("#bubbletag");
			main.mousedown(function(e){
				stopBubble(e);
				return true;
			});
			main.css({left: 0, top: 0})

			$(document).mousedown(function(){ main.css("visibility", "hidden");});
			return main;
		}
		$(".fc-content").css("marginTop", "5%");
		$(".fc-header").addClass("header-container");
		$(".fc-header-left").css("width", "15%");
		$('.fc-header-center').css("width", "100%");
		var $parent = $(".fc-header > tbody > tr");
		//屏蔽 google 同步
		//$parent.append("<td id='fc-header-googlesync'><span class='fc-button sync-btn-ct' id='goosync'><span class='fc-button-content'>" + g_loc_syncgooglecalendar + "</span></span></td>");
		//$parent.append("<td id='fc-header-options'><span class='fc-button sync-btn-ct' id='calendarOptions'><span id='option-content' class='fc-button-content'></span></span></td>");

		$(".fc-header-left").append("<span class='fc-button datepicker-ct'><span id='datepicker' class='fc-button-content'>" + g_loc_minicalendar + "</span></span>");
		$(".fc-header-left").append("<span class='fc-button'><span id='tagsfilter' class='fc-button-content'>" + g_loc_tag + "</span></span>");

		$(".fc-header-center").append("<div id='gidChange' style='display:none'><span id='googleId'></span><span id='googleIdLable'></span></div>");

		if (!canSyncGoogleCalendar()){
			$("#goosync").addClass("fc-state-disabled");
			$("#goosync").css("color", "#999");
		}else {
			$('#goosync').click(wizSyncGoogleCalendar);	
		}

		// 
		datePickerClick();
		tagsFilterClick();
		$('#wizTag').click(function(){
			var index = $(this)[0].selectedIndex;
			if (index != -1){
				var tag = $(this)[0].options[index].value;
				wizFilterEventTags(tag);
			}
		});
		$("#datepicker").click(function(){
			//
			$("#bubbletag").css("visibility", "hidden");
			var dp = $("#bubbledp");
			var offset = $(this).parent().offset();
			var height = $(this).parent().height();
			dp.css({top: offset.top + height + 2, left: offset.left});
			if (dp.css("visibility") == "visible")
				dp.css("visibility", "hidden");
			else
				dp.css("visibility", "visible");
		}).mousedown(function(){
			return false;
		});
		$("#tagsfilter").click(function(){

			//
			$("#bubbledp").css("visibility", "hidden");
			//
			var tag = $("#bubbletag");
			var offset = $(this).parent().offset();
			var height = $(this).parent().height();
			tag.css({top: offset.top + height + 2, left: offset.left});
			if (tag.css("visibility") == "visible")
				tag.css("visibility", "hidden");
			else 
				tag.css("visibility", "visible");
		}).mousedown(function(){
			return false;
		});

		$(".fc-content").css("marginTop", 0);
		$('.fc-header').css({'border-left': '0', 'border-right': '0'});

		$("#gidChange").click(function(){
			// wizChangeGoogleIdPage($(this));

			// $(this).css("display", "none");
		});
		$("#calendarOptions").click(function(){
			PopupWizOptionsBubble($(this));
		});


	});
	var g_eventInterval;
	function getEventInterval(){
		return g_eventInterval;
	}
	function setEventInterval(interval){
		g_eventInterval = interval;
	}
	$(document).ready(function(){
		g_calendarMain = $('#wizmain');
		g_fullCreate = $('#fc-main');
		g_fullCreate.css("display", "none");

		$fc_title = $('#fc-title');
		$fc_beg = $('#fc-beg');
		$fc_beg2 = $('#fc-beg2');
		$fc_end = $('#fc-end');
		$fc_end2 = $('#fc-end2');
		// $fc_color = $('#fc-color');
		$fc_content = $('#fc-content');
		$fc_cancel = $('#fc-cancel');
		$fc_save = $('#fc-save');
		$fc_allDchk = $('#fc-dp-alld');
		$fc_rpt = $('#fc-dp-rpt');
		$fc_tagVal = $('#fc-tagVal');
		$fc_rptModify = $('#fc-rpt-modf');
		$fc_giveup = $('#fc-giveup');
		$fc_delete = $('#fc-delete');
		$fc_remind = $('#fc-remind');
		var _fcInit = function(){
				g_rptRule = '';
				g_rptSummary = '';
				g_rptEnd = '';
				g_rptFlag = '';
				g_fcDoc = '';
		}
		var _fcRelease = function(){
				g_rptRule = '';
				g_rptSummary = '';
				g_rptEnd = '';
				g_rptFlag = '';
				g_fcDoc = '';
		}
		$('#fc-back').click(function(){ 
			g_fullCreate.css("display", "none");
			g_calendarMain.css("display", "block");
			_fcRelease();
			
		});
		$fc_cancel.click(function(){
			g_fullCreate.css("display", "none");
			g_calendarMain.css("display", "block");
			_fcRelease();
		});
		$fc_delete.click(function(){
			g_fullCreate.css("display", "none");
			g_calendarMain.css("display", "block");
			if (g_fcDoc){
				wizDeleteEvent(g_fcDoc.GUID);
			}
			_fcRelease();
		});
		$fc_giveup.click(function(){
			g_fullCreate.css("display", "none");
			g_calendarMain.css("display", "block");
			_fcRelease();
		});
		$fc_save.click(function() {
			var title = $fc_title.val();
			// var color = $fc_color.val().substr(1);
			var colorId = getCurrentColorId();
			var color = getColorValue(colorId).substr(1);


			// TODO: 创建之后，不要render所有事件，这时候应该只添加跟这个日历有关的事件
			// 可以加一个函数，getDocEvents(doc);
			var beg;
			var end;
			if ($fc_allDchk.attr("checked") == "checked"){
				beg = $fc_beg.val() + ' 00:00:00';
				end = $fc_end.val() + ' 23:59:59';
			}else {
				beg = $fc_beg.val() + ' ' + $('#fc-beg2')[0].value + ':00';
				end = $fc_end.val() + ' ' + $('#fc-end2')[0].value + ':00';
			}
			var eventContent = $fc_content[0].value;
			var remindVal = $fc_remind.val();
			var eventTag = $fc_tagVal.val();
			var docForRender;
			docForRender = wizCreateFullEvent(g_fullCreateFlag, g_fcDoc, beg, end, title, color, g_rptRule, g_rptEnd, eventContent, remindVal, eventTag, colorId);

			g_fullCreate.css("display", "none");
			g_calendarMain.css("display", "block");

			_renderDocEvent(docForRender);
			_fcRelease();
			wizUpdateLayout();

		});
		setEventInterval(0);
		wizCreateDatepicker($fc_beg, function(){
			var begStr = $fc_beg.val() + " 00:00:00";
			var begObj = _s2d(begStr);
			var endObj = new Date(begObj);
			var interval = getEventInterval();
			endObj.setDate(endObj.getDate() + interval);
			var endStr = _d2s(endObj);
			$fc_end.val(endStr.substr(0, 10));

		});
		wizCreateDatepicker($fc_end, function(){
			var begStr = $fc_beg.val() + " 00:00:00";
			var endStr = $fc_end.val() + " 00:00:00";
			var interval = _interDays(begStr, endStr);
			setEventInterval(interval - 1);
		});
		// $fc_color.each(function() {
		// 	$(this).miniColors({
		// 		change: function(hex, rgb) {
				
		// 			$fc_color.css('backgroundColor', hex);
		// 		},
		// 		opacity: $(this).hasClass('opacity'),
		// 		triggerPosition: $(this).attr('data-triggerPosition')
		// 	});
			
		// });
		var chkForm = function(){
			var beg = $fc_beg.val() + ' ' + $('#fc-beg2')[0].value + ':00';
			var end = $fc_end.val() + ' ' + $('#fc-end2')[0].value + ':00';
			
			if ($fc_title[0].value && (_s2d(beg).getTime() < _s2d(end).getTime()))
				$fc_save[0].disabled = false;
			else 
				$fc_save[0].disabled = true;
		}
		// $fc_color.miniColors('value', '#D5F8DD');
		$fc_title.mouseout(function(){ chkForm(); });
		$fc_beg.mouseout(function(){ chkForm(); });
		$fc_end.mouseout(function(){ chkForm(); });
		$fc_beg2.change(function(){ chkForm(); });
		$fc_end2.change(function(){ chkForm(); });

		$fc_allDchk.change(function(){
			if ($(this).attr("checked") == "checked"){
				
				$fc_beg2.css('display', 'none');
				$fc_end2.css('display', 'none');
			}else {	
				$fc_beg2.css('display', 'inline');
				$fc_end2.css('display', 'inline');
			}
		});

		$fc_rpt.change(function(){
			if ($(this).attr('checked') == 'checked'){
				if (g_rptSummary != ''){
					$('#fc-rpt-lb').html(g_loc_repeat + g_loc_colon);
					$('#fc-rpt-value').css("display", "inline");
					$fc_rptModify.css("display", "inline");
				}else {
					var beg = $fc_beg.val();
					
					setBubbleBg();
					setRepeatRule(beg, "create");
				}
			}else {
				$('#fc-rpt-lb').html(g_loc_repeat + "...");
				$('#fc-rpt-value').css("display", "none");
				$fc_rptModify.css("display", "none");
				g_rptRule = '';
				g_rptSummary = '';
				g_rptEnd = '';
				g_rptFlag = '';
			}
		});
		$fc_rptModify.click(function(){
			var beg = $fc_beg.val();
			setBubbleBg();
			setRepeatRule(beg, "modify");
		});

		$fc_rptModify.mouseover(function(){
			$(this).css("text-decoration", "underline");
		}).mouseout(function(){
			$(this).css("text-decoration", "none");
		});



		// 
		// 初始化颜色框的显示效果、鼠标移动效果、用户单击操作、数据记录。
		(function InitColorSquare(){

			// 根据日历颜色初始化颜色数组第0项的颜色值。
			var calendarColor = getCalendarColor();
			g_colorItems[0].colorValue = calendarColor;
			

			for (var i = 0; i < g_colorCount + 1; i ++){
				// 设置所有颜色框的背景色、边框色为一样颜色。
				$colorSquare = $("#fc-color" + i);
				$colorSquare.css("backgroundColor", g_colorItems[i].colorValue);
				if (i == 0){
					$colorSquare.css("borderColor", getCalendarBorderColor());
				}else {
					$colorSquare.css("borderColor", g_colorItems[i].colorValue);	
				}
				
				// 设置所有颜色框title。
				$colorSquare.attr("title", g_colorItems[i].colorName);
				// 设置所有颜色框鼠标移入边框颜色变成黑色、鼠标移出边框颜色编程原来的颜色。
				$colorSquare.unbind("mouseover").bind("mouseover", function(){
					$(this).css("borderColor", "black");

				}).unbind("mouseout").bind("mouseout", function(){
					var index = $(this).attr("index");
					var originalColor = g_colorItems[index].colorValue;
					if (index == 0){
						originalColor = getCalendarBorderColor();
					}
					
					$(this).css("borderColor", originalColor);
				});

				// 设置所有颜色框单击操作，
							
				$colorSquare.unbind("click").bind("click", function(){
					// 取消前一个选择的颜色框的选中状态
					var prevColorId = getCurrentColorId();
					$prevColorSquare = $("#fc-color" + prevColorId);
					$prevColorSquare.children(".fc-to-select").removeClass("ecs-selected");
					
					// 设置当前颜色框为选中状态
					$(this).children(".fc-to-select").addClass("ecs-selected");
					
					// 记录当前颜色id
					var curColorId = $(this).attr("index");	
					setCurrentColorId(curColorId);				
				});
			}

		})();

		(function addContent(){
			$("#fc-back").attr("title", g_loc_backtocalendar);
			$("#fc-back").html(g_loc_back);
			$fc_save.html(g_loc_save);
			$fc_cancel.html(g_loc_cancel);
			$fc_giveup.html(g_loc_discard);
			$fc_delete.html(g_loc_delete);
			$("#fc-loc-to").html(g_loc_to);
			$("#fc-loc-allday").html(g_loc_create_allday);
			$("#fc-rpt-lb").html(g_loc_repeat + "...");
			$fc_rptModify.html(g_loc_modify);
			$("#fc-loc-details").html(g_loc_details);
			$("#fc-loc-description").html(g_loc_description);
			$("#fc-loc-eventcolor").html(g_loc_eventcolor);
			$("#fc-loc-reminders").html(g_loc_reminders);
			$("#fc-loc-tag").html(g_loc_tag);
		})();

		$("#fc-tag-selectVal").click(function(){
			if (this.selectedIndex >= 0){
				document.getElementById('fc-tagVal').value = this.options[this.selectedIndex].value;
			}
		});
	});
	$(document).ready(function(){
		
		$(window).resize(function(){
			wizOnWindowResize();
		});
		wizSetMouseWhellEvent();
		wizOnWindowResize();

		$(window).resize(function(){
			// like $(window).afterResize().
			var timer;
			clearTimeout(timer);
    		timer = setTimeout(wizRenderWeekNumber, 300);
		});
	});
	$(document).ready(function(){
	});