AnchorGrid = function(width){
	
	var anchorHTML = document.createElement('div');
	anchorHTML.id = "Anchor";
	anchorHTML.style.left = "0px";
	var anchorController = new Array();		//store the grid information	
	//set the class for anchorHTML		
	var width = width;
	
	this.getAnchorHTML = function(){
		return anchorHTML;
	};
	this.getAnchorController = function(){
		return anchorController;
	};
	this.insertFrontChild = function(Grid){
		anchorController.unshift(Grid);
		var newChild = Grid.getGridHTML();
		var newChildText = document.createElement('div');
		newChild.appendChild(newChildText);
		var firstNode = anchorHTML.firstChild;
		while(firstNode && firstNode.nodeType != 1){
			firstNode = firstNode.nextSibling;
		}
		if (firstNode!=null) {
			
			var oldFirstChild = firstNode;
			var oldLeft = parseInt(oldFirstChild.style.left,10);
			var newLeft = oldLeft - width;			
			newChild.className = "grid";
			newChild.style.left = newLeft + "px";
			if(Grid.getMajorGridText()!=null){
				var majorDiv = document.createElement('div');
				majorDiv.className = "major";
				majorDiv.innerHTML = Grid.getMajorGridText();
				newChild.appendChild(majorDiv);
			}
			newChildText.innerHTML = Grid.getGridText();
			anchorHTML.insertBefore(newChild,firstNode); 	//anchorHTML.childNodes.unshift not recognised!
		}else {
			
			newChild.className = "grid";
			newChild.style.left = "0px";
			newChildText.innerHTML = Grid.getGridText();
			if(Grid.getMajorGridText()!=null){
				var majorDiv = document.createElement('div');
				majorDiv.className = "major";
				majorDiv.innerHTML = Grid.getMajorGridText();
				newChild.appendChild(majorDiv);
			}
			anchorHTML.appendChild(newChild);
		}
	};
	this.insertBackChild = function(Grid){
		anchorController.push(Grid);
		var newChild = Grid.getGridHTML();
		var newChildText = document.createElement('div');
		newChild.appendChild(newChildText);
		var lastNode = anchorHTML.lastChild;
		while(lastNode && lastNode.nodeType != 1){
			lastNode = lastNode.nextSibling;
		}
		if (lastNode != null) {			
			var oldLastChild = lastNode;
			var oldLeft = parseInt(oldLastChild.style.left,10);
			var newLeft = oldLeft + width;
			newChild.className = "grid";
			newChild.style.left = newLeft + "px";
			if(Grid.getMajorGridText()!=null){
				var majorDiv = document.createElement('div');
				majorDiv.className = "major";
				majorDiv.innerHTML = Grid.getMajorGridText();
				newChild.appendChild(majorDiv);
			}
			newChildText.innerHTML = Grid.getGridText();			
		}else {			
			newChild.className = "grid";
			newChild.style.left = "0px";
			if(Grid.getMajorGridText()!=null){
				var majorDiv = document.createElement('div');
				majorDiv.className = "major";
				majorDiv.innerHTML = Grid.getMajorGridText();
				newChild.appendChild(majorDiv);
			}
			newChildText.innerHTML = Grid.getGridText();
		}		
		anchorHTML.appendChild(newChild); 	//anchorHTML.childNodes.unshift not recognised!
	};
	this.removeFrontChild = function(){
		var firstNode = anchorHTML.firstChild;
		while(firstNode && firstNode.nodeType != 1){
			firstNode = firstNode.nextSibling;
		}
		anchorHTML.removeChild(firstNode);
		anchorController.shift();
	};
	this.removeBackChild = function(){
		
		var lastNode = anchorHTML.lastChild;
		while(lastNode && lastNode.nodeType != 1){
			lastNode = lastNode.nextSibling;
		}
		anchorHTML.removeChild(lastNode);
		anchorController.pop();
	};	
	this.setLeft = function(left){
		anchorHTML.style.left = left+"px";
	};	
	this.clear = function(){
		while(anchorHTML.childNodes.length >= 1){
			anchorHTML.removeChild(anchorHTML.firstChild);
		}
		anchorHTML.style.left = "0px";
		while(anchorController.length!=0){
			anchorController.pop();
		}		
	};

};
/**
 * ownerName - Owner of timewall
 * eventId - Event Id
 * all dates i.e. eventStartDt, eventEndDt,... - JS format
 */
EventObject = function(ownerId,mood,eventDetails,order,detailedBalloon,timeWall,photoPopup,ajaxUrl,isPublic,todayDate,viewerIsOwner,viewerId,isGroup,pastLabels,openDirectPicId,pk){	
	var ankhEffects = new AnkhEffects();
	//order states the position of this EventObject in the eventData object in the summary balloon object
	var ajaxUrl = ajaxUrl;
	var that = this;
	var tabContainer;
	//Participants' descriptions
	var expansionAnimationTime = 500;		//500ms
	var expansionIteration = 10;
	
	var labelsPlaceHolder;		//used as a placeholder to display labels
	
	//Navigation variables of Pictures
	var picInARow = 3;
	var numOfPicRows = 3;
	var picNavigationCurrentPage = 1;	
	var pictureNavigation;					//picture HTML navigation control container
	var picNavigationBar;					//picture HTML navigation object
	var picturePlaceHolder;					//picture HTML place holder for photos
			
	//Navigation variables of Participants
	var participantNavigation;
	var participantNavigationBar;
	var participantsInAPage = 5;
	var participantNavigationCurrentPage = 1;
	var participantPlaceHolder;
		
	//Navigation variables of Comments
	var commentNavigation;
	var commentNavigationBar;
	var commentsInAPage = 5;
	var commentNavigationCurrentPage = 1;
	var commentPlaceHolder;	
	
	//Navigation variables of Videos
	var videoNavigation;
	var videoNavigationBar;
	var videoPlaceHolder;
	var videoNavigationCurrentPage = 1;
	
	//Used by Photo Virtual Popup
	var timeWall = timeWall;
	var photoPopup = photoPopup;
	var currentPic;
	var defaultPopupTop = timeWall.getTimeWallContainerHeight() - 20;
	var defaultPopupLeft = (AnkhUsefulMethods.getViewPort().width - 800)/2 + 100;

	//Array lists to store the participant, pictures and commments
	var participantList = new Array();
	var participantWithDescList = new Array();	
	var picList = new Array();
	var friendsCommentsList = new Array();
	var videoList = new Array();
	
	var ankhDate = new AnkhDate();
	var todayDate = todayDate;
	var mood = mood;
	var eventId = eventDetails.eventId;
	var eventStartDt = ankhDate.mysqlTimeStampToDate(eventDetails.eventStartDt);
	var eventEndDt = ankhDate.mysqlTimeStampToDate(eventDetails.eventEndDt);
	var eventPic_s = eventDetails.eventPic_s;
	var eventPic_m = eventDetails.eventPic_m;
	var userDescription = eventDetails.userDescription;
	var userTitle = eventDetails.userTitle;
	var userPic = eventDetails.ownerPic_thumbnail;
	var userLastUpdateDt = ankhDate.mysqlTimeStampToDate(eventDetails.userLastUpdateDt);
	var userMood = eventDetails.userMood;
	var userRole = eventDetails.userRole;
	var userName = eventDetails.userName;
	var ownerPic = eventDetails.ownerPic_thumbnail;
	var creatorTitle = eventDetails.creatorTitle;
	var creatorPic = eventDetails.creatorPic_s;
	var creatorDescription = eventDetails.creatorDescription;
	var creatorMood = eventDetails.creatorMood;
	var creatorName = eventDetails.creatorName;
	var creatorGender = eventDetails.creatorGender;
	var privacy = eventDetails.privacy.toLowerCase();
	var creatorId = eventDetails.creatorId;
	var creatorLastUpdateDt = ankhDate.mysqlTimeStampToDate(eventDetails.creatorLastUpdateDt);
	var ownerId = ownerId;
	var viewerIsParticipant = eventDetails.viewerIsParticipant;			//boolean variable to show edit caption to participant	
	var inviterId = eventDetails.userId;
	var inviterGender = eventDetails.userGender;
	var ownerName = eventDetails.userName;
	var labels = eventDetails.labels;
	var pastLabels = pastLabels;	
	if(viewerIsOwner == 1){
		ownerName = "You";	
	}	
	var detailedBalloon = detailedBalloon;
	 
	var stripHTML = /<\S[^><]*>/g;			//Regular expression tag to be used to strip
	
	var rte;					//initialising RTE
	var ajaxLoaderImgPic = new AnkhAJAXLoader("");
	ajaxLoaderImgPic.style.position = "relative";
	ajaxLoaderImgPic.style.top = "80px";
	ajaxLoaderImgPic.style.left = "185px";
	
	var ajaxLoaderImgVideo = new AnkhAJAXLoader("");
	ajaxLoaderImgVideo.style.position = "relative";
	ajaxLoaderImgVideo.style.top = "80px";
	ajaxLoaderImgVideo.style.left = "185px";
		
	var ajaxLoaderImgParticipant = new AnkhAJAXLoader("");
	ajaxLoaderImgParticipant.style.position = "relative";
	ajaxLoaderImgParticipant.style.top = "80px";
	ajaxLoaderImgParticipant.style.left = "185px";
	
	var ajaxLoaderImgComment = new AnkhAJAXLoader("");
	ajaxLoaderImgComment.style.position = "relative";
	ajaxLoaderImgComment.style.top = "30px";
	ajaxLoaderImgComment.style.left = "185px";	
					
	var groupListHeader;
	var groupList;
	var participantPreviewListHeader;
	var participantPreviewList;		
	
	//Creating Summary Event HTML
	var summaryEventTblStructure = new GenericTable(1,2);
	summaryEventTblStructure.Table.style.width = "555px";
	summaryEventTblStructure.Table.className = "SummaryBalloonContentTbl";
	var summaryEventContainer = document.createElement('div');
	summaryEventTblStructure.getCell(0,0).style.verticalAlign = "top";
	summaryEventTblStructure.getCell(0,1).style.verticalAlign = "top";
	summaryEventTblStructure.getCell(0,1).style.width = "130px";
	summaryEventTblStructure.insertIntoCell(0,0,summaryEventContainer);

	var eventTitleHeader = document.createElement('span');
	eventTitleHeader.className ="eventTitle"
	eventTitleHeader.innerHTML = userTitle;	
	summaryEventContainer.appendChild(eventTitleHeader);

	var eventDate = document.createElement('span');
	if(eventEndDt - eventStartDt == 0){		//if event lies within the same date, then only display one date		
		eventDate.innerHTML = ", "+ankhDate.getDMY(eventStartDt," ");
	}else{
		eventDate.innerHTML = ", "+ankhDate.getDMY(eventStartDt," ")+" - "+ankhDate.getDMY(eventEndDt," ");
	}
	
	eventDate.className = "eventDate";
	summaryEventContainer.appendChild(eventDate);
		
	var eventDescription = document.createElement('div');
	if(userDescription == ""){
		eventDescription.innerHTML = ownerName + "&nbsp;did not say anything...";		
	}else{
		eventDescription.innerHTML = ownerName+"&nbsp;say: \""+userDescription.replace(/<br>/gi, '\n').replace(stripHTML, '').substr(0,240)+" ... \"";		
	}
	eventDescription.className = "eventDescription";		
	summaryEventContainer.appendChild(eventDescription);
			
	var eventEditDate = document.createElement('span');
	eventEditDate.className = "eventEditDate";
	eventEditDate.innerHTML = "edited "+ankhDate.compareWithToday(userLastUpdateDt,todayDate);
	eventDescription.appendChild(eventEditDate);

	if(labels.length > 0){
		var labelsParts = new Array();				
		labelsParts[0] = document.createElement('span');
		labelsParts[0].id = "LabelHeader";
		labelsParts[0].innerHTML = "Labels: ";		 
		for(var i = 0;i <labels.length;i++){				
			var link = new AnkhLink(labels[i],null,null,null,true);			
			labelsParts.push(link);
			if(i < labels.length - 2){
				labelsParts.push(", ");	
			}else if(i == labels.length - 2){				
				labelsParts.push("&nbsp;and ");				
			}						
			for(var j = 0; j < pastLabels.length;j++){				 
				if(labels[i] == pastLabels[j]['value']){
					link.type = pastLabels[j]['type'];
					break;
				}
			}
			EventUtil.addEventHandler(link,"click",function(){
				timeWall.setFilterValue(EventUtil.getEvent().target.innerHTML);
			});
		}						
		var labelsSentence = new AnkhDivBuilder(labelsParts);
		labelsSentence.className = "labelsSentence";
		eventDescription.appendChild(labelsSentence);					
	} 
		

	var linkContainer = document.createElement('div');
	linkContainer.className = "LinkContainer";	
	summaryEventContainer.appendChild(linkContainer);
	
	if(viewerIsOwner){
		var eventPrivacy = document.createElement('span');
		eventPrivacy.className = "eventPrivacy";
		eventPrivacy.innerHTML = "Viewable by "+privacy;
		linkContainer.appendChild(eventPrivacy);
	}
	
	var linkToDetailedBalloon = new AnkhLink("more info");		
	linkToDetailedBalloon.order = order;
	linkContainer.appendChild(linkToDetailedBalloon);
	
	var eventImg = document.createElement('img');
	eventImg.src = eventPic_s;	
	summaryEventTblStructure.insertIntoCell(0,1,eventImg);
	
	this.getDetailedEventHTML = function(){		
		participantList = new Array();
		participantWithDescList = new Array();	
		picList = new Array();
		friendsCommentsList = new Array();		
		var detailedBalloonStructure = new GenericTable(4,2);	
		detailedBalloonStructure.Table.style.width = "580px";	
		detailedBalloonStructure.Table.cellPadding = 0;
		detailedBalloonStructure.Table.cellSpacing = 1;
		for(var i = 0;i < detailedBalloonStructure.TBody.childNodes.length;i++){			
			detailedBalloonStructure.TBody.childNodes[i].vAlign = "top";	
		}
		
		
		if(isGroup){			
			var inviterVersion = document.createElement('div');
			inviterVersion.id = "InviterVersion";
			inviterVersion.innerHTML = "Inviter's version ";
			detailedBalloonStructure.insertIntoCell(0,0,inviterVersion);						
			
			var inviterDescContainer = document.createElement('div');	
			inviterDescContainer.className = "DescriptionContainer";
			detailedBalloonStructure.insertIntoCell(0,0,inviterDescContainer);
			var inviterPicControl = new FriendControl(userPic,userName,"Profile.php?id="+inviterId+"&eId="+eventId,56);
			inviterPicControl.id = "InviterPicControl";
			inviterDescContainer.appendChild(inviterPicControl);
			
			var inviterMoodControl = document.createElement('div');		
			inviterMoodControl.id = "InviterMood";			
			inviterMoodControl.innerHTML = AnkhUsefulMethods.genderStr(inviterGender).noun+ " feels: ";
			inviterDescContainer.appendChild(inviterMoodControl);
			var inviterMoodTxt = document.createElement('span');
			inviterMoodTxt.style.fontWeight = "bold";
			inviterMoodTxt.style.color = timeWall.getMoodsTranslation(userMood).colour;
			inviterMoodTxt.innerHTML = timeWall.getMoodsTranslation(userMood).Description;
			inviterMoodControl.appendChild(inviterMoodTxt);			
			var inviterDate = document.createElement('span');
			inviterDate.id = "InviterDate";			
			inviterDate.innerHTML = "edited " +ankhDate.compareWithToday(userLastUpdateDt,todayDate);

			inviterMoodControl.appendChild(inviterDate);			
			var inviterDesc = document.createElement('div');			
			inviterDesc.innerHTML = userDescription;
			inviterDescContainer.appendChild(inviterDesc);	
		}else{						
			var userDescriptionCtrl = document.createElement('div');		
			userDescriptionCtrl.className = "DescriptionContainer";
			if(AnkhUsefulMethods.trim(userDescription) != ""){			
				if(viewerIsOwner == 1){
					userDescriptionCtrl.innerHTML = "<b>"+ownerName+"</b> say: "+userDescription;
				}else{							
					userDescriptionCtrl.innerHTML = "<b>"+ownerName+"</b> says: "+userDescription;
				}			
			}else{			
				userDescriptionCtrl.innerHTML = "<b>"+ownerName+"</b> did not say anything ... ";
				if(viewerIsOwner){
					var writeYourVersion = new AnkhLink("write your version",null,"EditEventDetails.php?eId="+eventId);		
					userDescriptionCtrl.appendChild(writeYourVersion);
				}			
			}
			detailedBalloonStructure.insertIntoCell(0,0,userDescriptionCtrl);
		}		
		detailedBalloonStructure.getCell(0,1).rowSpan = "4";			
		var eventPic = document.createElement('img');		
		eventPic.src = eventPic_s;
		detailedBalloonStructure.insertIntoCell(0,1,eventPic);
		if(viewerIsOwner == 1){			
			var changeCoverPhoto = new AnkhLink("change cover",null,"EditEventPhotos.php?eId="+eventId+"&changeCover");		
			changeCoverPhoto.style.fontSize = "11px";
			changeCoverPhoto.style.display = "block";
			detailedBalloonStructure.insertIntoCell(0,1,changeCoverPhoto);
		}						
		
		var instruction = document.createElement('div');
		instruction.innerHTML = "Event link:";	
		instruction.style.fontSize = "10px";			
		detailedBalloonStructure.insertIntoCell(0,1,instruction);			
		var eventUrlTxtBox = new AnkhInputAutoSelect("EventUrl","http://www.mytimewall.com/Profile.php?id="+ownerId+"&eventId="+eventId);
		eventUrlTxtBox.style.width = "110px";
		eventUrlTxtBox.style.fontSize = "10px";
		detailedBalloonStructure.insertIntoCell(0,1,eventUrlTxtBox);
		
		
		//Draw Group
		groupListHeader = document.createElement('div');		
		groupListHeader.id = "GroupListHeader";
		detailedBalloonStructure.insertIntoCell(0,1,groupListHeader);		
		
		groupList = document.createElement('div');
		groupList.id = "GroupList";		
		detailedBalloonStructure.insertIntoCell(0,1,groupList);
				
		participantPreviewListHeader = document.createElement('div');
		participantPreviewListHeader.innerHTML = "They were there";
		participantPreviewListHeader.id = "ParticipantPreviewListHeader";
		detailedBalloonStructure.insertIntoCell(0,1,participantPreviewListHeader);				
		
		participantPreviewList = document.createElement('div');
		participantPreviewList.id = "ParticipantPreviewList";		
		detailedBalloonStructure.insertIntoCell(0,1,participantPreviewList);
		if (userRole != 1 && creatorId != "") {			//only display value if the current user is not the author.
			detailedBalloonStructure.getCell(1,0).style.paddingTop = "20px";
			var creatorVersion = document.createElement('div');
			creatorVersion.id = "CreatorVersion";
			creatorVersion.innerHTML = "Creator's version ";
			detailedBalloonStructure.insertIntoCell(1,0,creatorVersion);						
			
			var creatorDescContainer = document.createElement('div');
			creatorDescContainer.className = "DescriptionContainer";	
			detailedBalloonStructure.insertIntoCell(1,0,creatorDescContainer);
			var creatorPicControl = new FriendControl(creatorPic,creatorName,"Profile.php?id="+creatorId+"&eventId="+eventId,56);
			creatorPicControl.id = "CreatorPicControl";
			creatorDescContainer.appendChild(creatorPicControl);
			
			var creatorMoodControl = document.createElement('div');		
			creatorMoodControl.id = "CreatorMood";			
			creatorMoodControl.innerHTML = AnkhUsefulMethods.genderStr(creatorGender).noun+ " feels: ";
			creatorDescContainer.appendChild(creatorMoodControl);
			var creatorMoodTxt = document.createElement('span');
			creatorMoodTxt.style.fontWeight = "bold";
			creatorMoodTxt.style.color = timeWall.getMoodsTranslation(creatorMood).colour;
			creatorMoodTxt.innerHTML = timeWall.getMoodsTranslation(creatorMood).Description;
			creatorMoodControl.appendChild(creatorMoodTxt);
			
			var creatorDateText = ankhDate.compareWithToday(creatorLastUpdateDt,todayDate);
			var creatorDate = document.createElement('span');
			creatorDate.id = "CreatorDate";			
			creatorDate.innerHTML = "edited " +creatorDateText;
			creatorMoodControl.appendChild(creatorDate);
			
			var creatorDesc = document.createElement('div');			
			creatorDesc.innerHTML = creatorDescription;
			creatorDescContainer.appendChild(creatorDesc);			
		}
		
		detailedBalloonStructure.getCell(2,0).style.paddingTop = "10px";
		//Draw Labels - Row 2
		if(labels.length > 0){
			var labelsParts = new Array();				
			labelsParts[0] = document.createElement('span');
			labelsParts[0].id = "LabelHeader";
			labelsParts[0].innerHTML = "Labels: "; 
			for(var i = 0;i <labels.length;i++){			
				var link = new AnkhLink(labels[i],null,null,null,true);			
				labelsParts.push(link)
				if(i < labels.length - 2){
					labelsParts.push(", ");	
				}else if(i == labels.length - 2){
					labelsParts.push("&nbsp;and ");
				}	
				for(var j = 0; j < pastLabels.length;j++){
					if(labels[i] == pastLabels[j]['value']){
						link.type = pastLabels[j]['type'];
						break;
					}
				}
				EventUtil.addEventHandler(link,"click",function(){
					timeWall.setFilterValue(EventUtil.getEvent().target.innerHTML);
				});				
			}					
			labelsPlaceHolder = new AnkhDivBuilder(labelsParts);
			labelsPlaceHolder.className = "labelsPlaceHolder";
			detailedBalloonStructure.insertIntoCell(2,0,labelsPlaceHolder);					
		}else{						
			labelsPlaceHolder = document.createElement('div');
			labelsPlaceHolder.className = "labelsPlaceHolder";
			detailedBalloonStructure.insertIntoCell(2,0,labelsPlaceHolder);		
		}											
		
		//Draw row 3
		detailedBalloonStructure.getCell(3,0).style.paddingTop = "10px";
		
		var tabHeadersTxt = new Array("Photos","Other descriptions","Comments","Videos");
		tabContainer = new TabContainer(tabHeadersTxt,detailedBalloonStructure.getCell(3,0));	
		tabContainer.getTabHeaderContainer().style.fontSize = "11px";	
		for(var i = 0;i < tabHeadersTxt.length;i++){
			tabContainer.getTabHeader(i).style.paddingLeft = "2px";
			tabContainer.getTabHeader(i).style.paddingRight = "2px";
		}
		var tabContents = tabContainer.getContentArray();
		
		var pictureContainer = document.createElement('div');
		pictureContainer.className = "DetailedBalloonTabContainer";		
		tabContents[0].appendChild(pictureContainer);
		
		pictureNavigation = new GenericTable(1,2);
		pictureNavigation.Table.id = "PictureNavigation"; 		
		pictureNavigation.getCell(0,1).style.textAlign = "right";
		pictureNavigation.getCell(0,1).style.marginRight = "10px";		
		pictureContainer.appendChild(pictureNavigation.Table);
		 
		picturePlaceHolder = document.createElement('div');				
		pictureContainer.appendChild(picturePlaceHolder);
		pictureContainer.appendChild(ajaxLoaderImgPic);
		
		var participantContainer = document.createElement('div');
		participantContainer.className = "DetailedBalloonTabContainer";
		tabContents[1].appendChild(participantContainer);	
		
		participantNavigation = new GenericTable(1,2);		
		participantNavigation.Table.id = "ParticipantNavigation";
		participantNavigation.getCell(0,1).style.textAlign = "right";
		participantNavigation.getCell(0,1).style.marginRight = "10px";
		participantContainer.appendChild(participantNavigation.Table);	
		participantPlaceHolder = document.createElement('div');
		participantContainer.appendChild(participantPlaceHolder);	
		participantContainer.appendChild(ajaxLoaderImgParticipant);		
					
		var commentContainer = document.createElement('div');
		commentContainer.className = "DetailedBalloonTabContainer";
		tabContents[2].appendChild(commentContainer);	
			
		var RTEContainer = document.createElement('div');			
		commentContainer.appendChild(RTEContainer);
		commentNavigation = document.createElement('div');
		commentNavigation.style.textAlign = "right";
		commentNavigation.style.marginRight = "10px";
		commentContainer.appendChild(commentNavigation);
		commentPlaceHolder = document.createElement('div');
		commentContainer.appendChild(commentPlaceHolder);
		commentContainer.appendChild(ajaxLoaderImgComment);
		
		var videoContainer = document.createElement('div');
		videoContainer.className = "DetailedBalloonTabContainer";
		tabContents[3].appendChild(videoContainer);	
		
		videoNavigation = new GenericTable(1,2);		
		videoNavigation.Table.id = "VideoNavigation";
		videoNavigation.getCell(0,1).style.textAlign = "right";
		videoNavigation.getCell(0,1).style.marginRight = "10px";
		videoContainer.appendChild(videoNavigation.Table);	
		videoPlaceHolder = document.createElement('div');
		videoContainer.appendChild(videoPlaceHolder);	
		videoContainer.appendChild(ajaxLoaderImgVideo);	
		
		if(!isPublic){
			var openLink = new AnkhLink("I want to say something",function x(){rte.activateDesignMode();}); 
			openLink.style.marginLeft = "5px";
			RTEContainer.appendChild(openLink);
		}
		var innerCommentsContainer = document.createElement('div');
		innerCommentsContainer.style.marginLeft = "5px";		
		RTEContainer.appendChild(innerCommentsContainer);
		rte = new AnkhTextEditor(that.saveComments,"SupportControls/RichTextEditor/",innerCommentsContainer,400,150,true,null,"",false,"Say");
		rte.setVisible(false);
		that.retrievePicList();
		that.retrieveVideoList();
		that.retrieveParticipantsList();
		that.retrieveComments();
			
		return detailedBalloonStructure.Table;
	};
	
	this.retrieveVideoList = function(){
		videoList = new Array();
		ajaxLoaderImgVideo.style.visibility = "visible";
		ajaxLoaderImgVideo.style.display = "block";
		var method = "getEventVideos";				
		var parameterObj = {method:method,eventId: eventId,ownerId:ownerId,pk:pk};		
		new AnkhAjax(ajaxUrl,"get",parameterObj,that.retrieveVideoListComplete,ajaxLoaderImgVideo);
	};
	
	this.retrieveVideoListComplete = function(transport){
		var result = transport.responseText.evalJSON(true);		
		if (eventId == result.eventId) {
			
			AnkhUsefulMethods.removeAll(videoPlaceHolder);			
			tabContainer.getTabHeader(3).innerHTML += "&nbsp;("+result.Videos.length+")";		
			for (var i = 0; i < result.Videos.length; i++) {				
				videoList.push(result.Videos[i]);				
			}

			ajaxLoaderImgVideo.style.visibility = "hidden";
			ajaxLoaderImgVideo.style.display = "none";			
			that.displayVideo();
		}
	};
	
	this.displayVideo = function(){						
		if (videoList.length == 0) {
			var noVideoIndicater = document.createElement('div');
			noVideoIndicater.innerHTML = "No videos have been shared";
			noVideoIndicater.style.marginLeft = "5px";
			videoPlaceHolder.appendChild(noVideoIndicater);
		}
		else {			
			videoNavigationBar = new NavigationBar(videoList.length,1,that.switchVideoPage);			
			var numOfVideos = videoList.length;
			if(videoList.length > 1){			//if more than the allowed pictures in a page, then show navigation bar
				videoNavigation.insertIntoCell(0,1,videoNavigationBar.getHTML(videoNavigationCurrentPage));					
			}						
			var structure = new GenericTable(1, 1);			
			videoPlaceHolder.appendChild(structure.Table);				
			var initial = (videoNavigationCurrentPage - 1);			
			
			
			var addDate = ankhDate.mysqlTimeStampToDate(videoList[initial]['lastUpdateDt']);
			var addDateTxt = ankhDate.getMDY(addDate," ");
			var videoDate = document.createElement('div');
			videoDate.innerHTML = addDateTxt;
			videoDate.className = "videoDate";
			structure.insertIntoCell(0,0,videoDate);
					
			var addedByParts = new Array();
			addedByParts[0] = "Added by: ";
			addedByParts[1] = new AnkhLink(videoList[initial]['ownerName'],null,"Profile.php?id="+videoList[initial]['ownerId']);
			var addedBy = new AnkhDivBuilder(addedByParts);
			addedBy.className = "videoAddedBy";						
			structure.insertIntoCell(0,0,addedBy);
																								
			var videoImgContainer = document.createElement('div');
			videoImgContainer.innerHTML = videoList[initial]['embedCode'];														
			structure.insertIntoCell(0,0,videoImgContainer);				
			
		}
	};
	
	/**
	 * Purpose: Used to switch between video pages
	 */
	this.switchVideoPage = function(){	
		videoNavigationCurrentPage = parseInt(EventUtil.getEvent().target.innerHTML,10);
		AnkhUsefulMethods.removeAll(videoNavigation.getCell(0,1));
		AnkhUsefulMethods.removeAll(videoPlaceHolder);
		that.displayVideo();
		EventUtil.getEvent().preventDefault();
	};

	//AJAX call to retrieve Pic List for this event
	this.retrievePicList = function(){		
		ajaxLoaderImgPic.style.visibility = "visible";
		ajaxLoaderImgPic.style.display = "block";
		var method = "getEventPics";		
		var parameterObj = {method:method,eventId: eventId,ownerId:ownerId,pk:pk};		
		new AnkhAjax(ajaxUrl,"get",parameterObj,that.retrievePicListComplete,ajaxLoaderImgPic);
	};
	/**
	 * Purpose: this is called when retrievePicList is completed
	 */
	this.retrievePicListComplete = function(transport){			
		var result = transport.responseText.evalJSON(true);								
		if (eventId == result.eventId) {
			AnkhUsefulMethods.removeAll(picturePlaceHolder);			
			tabContainer.getTabHeader(0).innerHTML += "&nbsp;("+result.Pictures.length+")";					
			picList = result.Pictures;
			ajaxLoaderImgPic.style.visibility = "hidden";
			ajaxLoaderImgPic.style.display = "none";			
			that.displayPic();
		}
	};
	/**
	 * Purpose: Used to display pictures in the detailed balloon
	 */
	this.displayPic = function(){				
		if (picList.length == 0) {
			var noPictureIndicater = document.createElement('div');
			noPictureIndicater.innerHTML = "Opps! No pictures have been uploaded";
			noPictureIndicater.style.marginLeft = "5px";
			picturePlaceHolder.appendChild(noPictureIndicater);
		}
		else {			
			picNavigationBar = new NavigationBar(picList.length,picInARow*numOfPicRows,that.switchPicPage);			
			var numOfPics = picList.length;
			if(picList.length > picInARow * numOfPicRows){			//if more than the allowed pictures in a page, then show navigation bar
				pictureNavigation.insertIntoCell(0,1,picNavigationBar.getHTML(picNavigationCurrentPage));
				numOfPics = picInARow * numOfPicRows;	
			}						
			var structure = new GenericTable(Math.ceil(numOfPics / picInARow), picInARow);			
			picturePlaceHolder.appendChild(structure.Table);	
			
			var initial = (picNavigationCurrentPage - 1) * picInARow * numOfPicRows;
			var currentMax = initial + picInARow * numOfPicRows;
			for (var i =  initial; i < picList.length; i++) {				
				if(i == currentMax){
					break;
				}						
				var rowNum = Math.floor((i - initial) / picInARow);
				var colNum = (i - initial) % picInARow;
				structure.getCell(rowNum,colNum).className = "Picture";				
				var picImgContainer = document.createElement('div');									
				var caption = "";
				if(AnkhUsefulMethods.trim(picList[i].caption) != ""){
					caption = ankhEffects.getPreviewMsg(picList[i].caption,70).msgWithDots;
				}
				var picImg = new FriendControl(picList[i].src_s,null,null,null,null,null,null,{align:"left",content:caption,padding:2,width:124});					
				picImg.large = picList[i].src_l;								
				picImgContainer.appendChild(picImg);													
				if(photoPopup == null){					// for about page	
					picImg.style.cursor = "default";
				}else{									// for profile pages													
					EventUtil.addEventHandler(picImg,"click",that.displayClickedPhoto);									
				}	
				structure.insertIntoCell(rowNum,colNum,picImgContainer);								
			}
			if(openDirectPicId){
				that.displaySelectedPhoto(openDirectPicId);
			}
		}
	};
	
	that.displayClickedPhoto = function(){
		currentPic = EventUtil.getEvent().target.parentNode.parentNode.large;		//gets the grand-parentNode of the existing <img> of FriendControl
		that.displayOriginalPhoto();
	};
	
	that.displaySelectedPhoto = function(value){
		for (var i = 0; i < picList.length; i++) {
			if(picList[i].picId == value){
				currentPic = picList[i]['src_l'];
				break;
			}
		}	
		that.displayOriginalPhoto();
	};
	
	/**
	 * Purpose: Load Photo when the virtual popup box is first initialised
	 */
	this.displayOriginalPhoto = function(){						
		var index = 0;
		for (var i = 0; i < picList.length; i++) {
			if(picList[i].src_l == currentPic){
				index = i;
				break;
			}
		}					
		photoPopup.setEventHandleNextNPrev(that.loadPrevPhoto,that.loadNextPhoto);		
		var lastUpdateDt = ankhDate.getMDY(ankhDate.mysqlTimeStampToDate(picList[index].lastUpdateDt)," ");
		var photoNum = index + 1;
		var countTxt = "Photo: <b>"+photoNum+"</b> of "+ picList.length;
		var ownerNm;		
		if(picList[index]['ownerId'] == viewerId){
			ownerNm = "You";			
		}else{
			ownerNm = picList[index].ownerName;			
		}		
		if(picList.length == 1){						
			photoPopup.show(currentPic,defaultPopupLeft,defaultPopupTop,false,ownerNm,picList[index],photoNum,picList.length,viewerIsParticipant,eventId,picList[index]['ownerId']);			
		}else{					
			photoPopup.show(currentPic,defaultPopupLeft,defaultPopupTop,true,ownerNm,picList[index],photoNum,picList.length,viewerIsParticipant,eventId,picList[index]['ownerId']);
		}				
	};		
	
	/**
	 * Purpose: Used to switch between pic pages
	 */
	this.switchPicPage = function(){	
		picNavigationCurrentPage = parseInt(EventUtil.getEvent().target.innerHTML,10);
		AnkhUsefulMethods.removeAll(pictureNavigation.getCell(0,1));
		AnkhUsefulMethods.removeAll(picturePlaceHolder);
		that.displayPic();
		EventUtil.getEvent().preventDefault();
	};
	/**
	 * Purpose: Load Previous Photo when the "Previous" button is clicked on the virtual popup
	 */
	this.loadPrevPhoto = function(){
		var popupTop = timeWall.getTimeWallContainerHeight() - 100;
		for (var i = 0; i < picList.length; i++) {
			if(picList[i].src_l == currentPic){
				var nextPicIndex = 0;
				if(i == 0){
					nextPicIndex = picList.length - 1;
				}else{
					nextPicIndex = i - 1;
				}
				currentPic = picList[nextPicIndex].src_l;
				var ownerNm;				
				if(picList[nextPicIndex]['ownerId'] == viewerId){
					ownerNm = "You";
				}else{
					ownerNm = picList[nextPicIndex].ownerName;					
				}				
				var caption = picList[nextPicIndex].caption;				
				var photoNum = nextPicIndex + 1;												
				photoPopup.show(currentPic,defaultPopupLeft,defaultPopupTop,true,ownerNm,picList[nextPicIndex],photoNum,picList.length,viewerIsParticipant,eventId,picList[nextPicIndex]['ownerId']);								
				break;
			}
		}
		
	};
	/**
	 * Purpose: Load Next Photo when the "Next" button is clicked on the virtual popup
	 */
	this.loadNextPhoto = function(){		
		for (var i = 0; i < picList.length; i++) {
			if(picList[i].src_l == currentPic){
				var nextPicIndex = (i + 1) % picList.length;
				currentPic = picList[nextPicIndex].src_l;
				var ownerNm;
				
				if(picList[nextPicIndex]['ownerId'] == viewerId){
					ownerNm = "You";					
				}else{
					ownerNm = picList[nextPicIndex].ownerName;					
				}				
				
				var photoNum = nextPicIndex + 1;												
				photoPopup.show(currentPic,defaultPopupLeft,defaultPopupTop,true,ownerNm,picList[nextPicIndex],photoNum,picList.length,viewerIsParticipant,eventId,picList[nextPicIndex]['ownerId']);			
				break;
			}
		}
		
	};
	/**
	 * Purpose: AJAX call to retrieve Participant List for this event
	 */
	this.retrieveParticipantsList = function(){
		var method = "getEventParticipants";		
		var parameterObj = {method:method,ownerId:ownerId,eventId: eventId,pk:pk};
		new AnkhAjax(ajaxUrl,"get",parameterObj,that.retrieveParticipantsListComplete,ajaxLoaderImgParticipant);
	};
	/**
	 * Purpose: Called when participant list has been retrieved
	 */
	this.retrieveParticipantsListComplete = function(transport){		
		var result = transport.responseText.evalJSON(true);				
		if (eventId == result.eventId) {			
			AnkhUsefulMethods.removeAll(participantPlaceHolder);			
			var totalParticipants = result.withDescription.length;
			tabContainer.getTabHeader(1).innerHTML += "&nbsp;("+totalParticipants+")";	
			detailedBalloon.setParticipant(viewerIsParticipant);																			
			if(result['groups'].length == 0){
				groupListHeader.innerHTML = "";
				groupListHeader.style.display = "none";
				groupList.style.display = "none";
			}else if(result['groups'].length == 1){
				groupListHeader.innerHTML = "Part of this group";				
			}else if(result['groups'].length > 1){
				groupListHeader.innerHTML = "Part of these groups";				
			}						
			for(var i = 0;i < result['groups'].length;i++){	
				var toolTipContent = {width:56,content:result['groups'][i]['groupNm']};
				var groupPic = new FriendControl(result['groups'][i]['thumbnail'],"","Group.php?id="+result['groups'][i]['groupId']+"&eventId="+eventId,null,null,null,null,toolTipContent);				
				groupPic.style.cssFloat = "left";
				groupPic.style.styleFloat = "left";
				groupList.appendChild(groupPic);
			}
			
			if(result.loginUserIsParticipant){				
																				
				var uploadMorePhotos = new AnkhLink("upload more",null,"NewEventPhotos.php?eId="+eventId+"&uploadMore");
				uploadMorePhotos.style.marginLeft = "5px";		
				uploadMorePhotos.style.fontSize = "11px";		
				pictureNavigation.insertIntoCell(0,0,uploadMorePhotos);			
								
				var addCaption = new AnkhLink("add caption",null,"EditEventPhotos.php?eId="+eventId+"&AddCaption");
				addCaption.style.marginLeft = "10px";
				addCaption.style.fontSize = "11px";
				pictureNavigation.insertIntoCell(0,0,addCaption);	
				
				var tagYourFriends = new AnkhLink("tag your friends",null,"EditEventPhotos.php?eId="+eventId+"&TagFriends");
				tagYourFriends.style.marginLeft = "10px";
				tagYourFriends.style.fontSize = "11px";
				pictureNavigation.insertIntoCell(0,0,tagYourFriends);														
				
				if(result['groups'].length >= 1){
					var addMore = new AnkhLink("add",null,"EditEventParticipants.php?eId="+eventId+"&previewAddPart");					
					addMore.style.marginLeft = "5px";
					addMore.style.fontSize = "11px";
					groupListHeader.appendChild(addMore);
				}
				
				if(labels.length > 0){
					var addLabel = new AnkhLink("modify",null,"EditEventDetails.php?eId="+eventId);					
					addLabel.style.fontSize = "11px";
					addLabel.style.marginLeft = "10px";
					labelsPlaceHolder.appendChild(addLabel);		
				}else{
					var addLabel = new AnkhLink("Add first label",null,"EditEventDetails.php?eId="+eventId);					
					addLabel.style.fontSize = "11px";					
					labelsPlaceHolder.appendChild(addLabel);
				}
				
				var addMore = new AnkhLink("add",null,"EditEventParticipants.php?eId="+eventId+"&previewAddPart");				
				addMore.style.marginLeft = "5px";
				addMore.style.fontSize = "11px";
				participantPreviewListHeader.appendChild(addMore);
				
				var addOthers = new AnkhLink("add others",null,"EditEventParticipants.php?eId="+eventId+"&previewAddOthers");				
				addOthers.style.marginLeft = "5px";
				addOthers.style.fontSize = "11px";
				participantNavigation.insertIntoCell(0,0,addOthers);
				
				var shareVideos = new AnkhLink("share videos",null,"EditEventVideos.php?eId="+eventId+"&connectVideo");				
				shareVideos.style.marginLeft = "5px";
				shareVideos.style.fontSize = "11px";
				videoNavigation.insertIntoCell(0,0,shareVideos);			
			}
			var toolTipContent = {width:56,content:ownerName};
			var ownerPicControl = new FriendControl(ownerPic,"","Profile.php?id="+inviterId+"&eventId="+eventId,null,null,null,null,toolTipContent);
			ownerPicControl.style.cssFloat = "left";
			ownerPicControl.style.styleFloat = "left";			
			participantPreviewList.appendChild(ownerPicControl);
			if(creatorId != ""){
				var toolTipContent = {width:56,content:creatorName};
				var creatorPreviewPic = new FriendControl(creatorPic,"","Profile.php?id="+creatorId+"&eventId="+eventId,null,null,null,null,toolTipContent);
				creatorPreviewPic.style.cssFloat = "left";
				creatorPreviewPic.style.styleFloat = "left";
				participantPreviewList.appendChild(creatorPreviewPic);
			}
			for (var i = 0; i < result.withDescription.length; i++) {
				var participant = result.withDescription[i];
				participant['withDescription'] = true;
				participant['descriptionPreview'] = result.withDescription[i].description.replace(/<br>/gi, '\n').replace(stripHTML, '').substr(0, 120);
				participantList.push(participant);
				participantWithDescList.push(participant);
				/*Adding the Participants Preview box */								
				var toolTipContent = {width:56,content:participant['name']};
				var friendControl = new FriendControl(participant.participantPic_s,"","Profile.php?id="+participant.participantId+"&eventId="+eventId,null,null,null,null,toolTipContent);
				friendControl.style.cssFloat = "left";
				friendControl.style.styleFloat = "left";
				participantPreviewList.appendChild(friendControl);	
			}
			for (var i = 0; i < result.withoutDescription.length; i++) {
				var participant = result.withoutDescription[i];
				participant['withDescription'] = false;
				participant['descriptionPreview'] = result.withoutDescription[i].description.replace(/<br>/gi, '\n').replace(stripHTML, '').substr(0, 120);				
				participantList.push(participant);
				/*Adding the Participants Preview box */	
				var toolTipContent = {width:56,content:participant['name']};							
				var friendControl = new FriendControl(participant.participantPic_s,"","Profile.php?id="+participant.participantId+"&eventId="+eventId,null,null,null,null,toolTipContent);
				friendControl.style.cssFloat = "left";
				friendControl.style.styleFloat = "left";
				participantPreviewList.appendChild(friendControl);	
			}
			setPhotoPopupParticipantList();
						
				
			ajaxLoaderImgParticipant.style.visibility = "hidden";
			ajaxLoaderImgParticipant.style.display = "none";
			that.displayParticipants();		
			
		}
	};	
	
	setPhotoPopupParticipantList = function(){
		var suggestedParticipants = new Array();
		if(creatorId != ""){						
			suggestedParticipants.push({friendId:creatorId,thumbnail:creatorPic,displayNm:creatorName,type:"friend"});
		}
		for(var i = 0;i < participantList.length;i++){
			var suggestedParticipant = {};
			suggestedParticipant['friendId'] = participantList[i]['participantId'];			
			suggestedParticipant['displayNm'] = participantList[i]['name'];
			suggestedParticipant['thumbnail'] = participantList[i]['participantPic_s'];
			suggestedParticipant['type'] = "friend"			
			suggestedParticipants.push(suggestedParticipant);
		}					
		photoPopup.setParticipantList(suggestedParticipants);		
	};
	
	/**
	 * Purpose: Display Participants information in HTML
	 */
	this.displayParticipants = function(){			
		if(participantWithDescList.length == 0){
			var noParticipantsIndicater = document.createElement('div');
			noParticipantsIndicater.innerHTML = "No one else has described this event.";
			noParticipantsIndicater.style.marginLeft = "5px";
			participantPlaceHolder.appendChild(noParticipantsIndicater);	
					
		}else{
								
			participantNavigationBar = new NavigationBar(participantWithDescList.length,participantsInAPage,that.switchParticipantsPage);
			var numOfParticipants = participantWithDescList.length;
			if(participantWithDescList.length > participantsInAPage){			//if more than the allowed participants in a page, then show navigation bar
				participantNavigation.insertIntoCell(0,1,participantNavigationBar.getHTML(participantNavigationCurrentPage));
				numOfParticipants = participantsInAPage;		
			}			
			var structure = new GenericTable(numOfParticipants,2);
			participantPlaceHolder.appendChild(structure.Table);
			var initial = (participantNavigationCurrentPage - 1) * participantsInAPage;				
			for (var i = initial; i < participantWithDescList.length; i++) {
				if(i == participantNavigationCurrentPage * participantsInAPage){					
					break;
				}	
				var index = i - initial;											
				structure.TBody.childNodes[index].vAlign = "top";
				structure.getCell(index,0).className = "ParticipantPreview";										
				var friendControl = new FriendControl(participantWithDescList[i].participantPic_s,participantWithDescList[i].name,"Profile.php?id="+participantWithDescList[i].participantId+"&eventId="+eventId,56);				
				structure.insertIntoCell(index,0,friendControl);
				var participantMood = document.createElement('div');		
				participantMood.className = "participantMood";							
				participantMood.innerHTML = AnkhUsefulMethods.genderStr(participantWithDescList[i].gender).noun+" feels: ";
				structure.insertIntoCell(index,1,participantMood);	
				
				var participantMoodTxt = document.createElement('span');
				participantMoodTxt.style.fontWeight = "bold";				
				participantMoodTxt.style.color = timeWall.getMoodColour(participantWithDescList[i].mood);
				participantMoodTxt.innerHTML = participantWithDescList[i].mood;
				participantMood.appendChild(participantMoodTxt);
								
				
				var participantComment = document.createElement('div');
				participantComment.className = "ParticipantCommentsPreview";										
				participantComment.innerHTML = "\""+participantWithDescList[i].descriptionPreview+"\"";
				structure.insertIntoCell(index,1,participantComment);	
				if(participantWithDescList[i].descriptionPreview != participantWithDescList[i].description){			//if no diffence, do not show "see more"
					var expansionLinkContainer = document.createElement('div');
					expansionLinkContainer.className = "ExpansionLinkContainer";						
					var expansionLink = new AnkhLink("see more",revealContent);
					expansionLink.style.fontSize = "11px";
					expansionLinkContainer.appendChild(expansionLink);
					structure.insertIntoCell(index,1,expansionLinkContainer);						
					expansionLink.expansion = participantWithDescList[i].description;
					expansionLink.contract = participantComment.innerHTML;
					expansionLink.targetDiv = participantComment;					
					expansionLink.isExpanded = false;				
				}					
											
			}
		}		
		
	};
	/**
	 * Purpose: Switch Participant page
	 */
	this.switchParticipantsPage = function(){
		participantNavigationCurrentPage = parseInt(EventUtil.getEvent().target.innerHTML,10);
		AnkhUsefulMethods.removeAll(participantNavigation.getCell(0,1));
		AnkhUsefulMethods.removeAll(participantPlaceHolder);
		that.displayParticipants();
		EventUtil.getEvent().preventDefault();
	}; 
	
	this.saveComments = function(message){
		var url = "php/timewall_write.php";
		var method = "createComment";
		rte.setVisible(false);		
		AnkhUsefulMethods.removeAll(commentNavigation);
		AnkhUsefulMethods.removeAll(commentPlaceHolder);
		ajaxLoaderImgComment.style.visibility = "visible";
		ajaxLoaderImgComment.style.display = "block";		
		var parameterObj = {method:method,eventComment: message,eventId: eventId,ownerId:ownerId,pk:pk};
		new AnkhAjax(url,"post",parameterObj,that.retrieveComments,ajaxLoaderImgComment);
	};
	
	/**
	 * Purpose: AJAX call to retrieve friends' comments regarding the events
	 */
	this.retrieveComments = function(){				
		var method = "getEventComments";		
		var parameterObj = {method:method,eventId: eventId,pk:pk};
		new AnkhAjax(ajaxUrl,"get",parameterObj,that.retrieveCommentsComplete,ajaxLoaderImgComment);
	};

	/**
	 * Purpose: Event handler when retrieveComments is completed
	 * @param {Object} transport - response from AJAX
	 */
	this.retrieveCommentsComplete = function(transport){		
		var result = transport.responseText.evalJSON(true);
		if (eventId == result.eventId) {
			friendsCommentsList.length = 0;
			tabContainer.getTabHeader(2).innerHTML = "Comments ("+result.Comments.length+")";
			var todayDate = ankhDate.mysqlTimeStampToDate(result.currentTime);
			for (var i = 0; i < result.Comments.length; i++) {
				var JSdate = ankhDate.mysqlTimeStampToDate(result.Comments[i].lastUpdateDt);
				var previewComment = result.Comments[i].comment.replace(/<br>/gi, '\n').replace(stripHTML, '').substr(0, 120);
				var comment = result.Comments[i];
				comment['lastUpdate'] = ankhDate.compareWithToday(JSdate,todayDate);
				comment['previewCommentWithDots'] =  previewComment + "...";
				friendsCommentsList.push(comment);
			}
			that.displayComments();
		}
	};

	/**
	 * Purpose : Display the comments within the tab box
	 */
	this.displayComments = function(){		
	
		AnkhUsefulMethods.removeAll(commentNavigation);
		AnkhUsefulMethods.removeAll(commentPlaceHolder);
		ajaxLoaderImgComment.style.visibility = "hidden";
		ajaxLoaderImgComment.style.display = "none";
		if (friendsCommentsList.length == 0) {
			var noCommentsIndicater = document.createElement('div');
			noCommentsIndicater.innerHTML = "Nope.. no comments ...";
			noCommentsIndicater.style.marginLeft = "5px";
			commentPlaceHolder.appendChild(noCommentsIndicater);			
		}
		else {			
			commentNavigationBar = new NavigationBar(friendsCommentsList.length,commentsInAPage,that.switchCommentsPage);
			var numOfComments = friendsCommentsList.length;			
			if(friendsCommentsList.length > commentsInAPage){			//if more than the allowed comments in a page, then show navigation bar
				commentNavigation.appendChild(commentNavigationBar.getHTML(commentNavigationCurrentPage));
				numOfComments = commentsInAPage;
			}			
			var structure = new GenericTable(numOfComments,2);
			commentPlaceHolder.appendChild(structure.Table);
			
			var initial = (commentNavigationCurrentPage - 1) * commentsInAPage;
	
			for (var i = initial; i < friendsCommentsList.length; i++) {
				if(i == commentNavigationCurrentPage * commentsInAPage){
					break;
				}

				var index = i - initial;
				structure.TBody.childNodes[index].vAlign = "top";				
				var friendControl = new FriendControl(friendsCommentsList[i].ownerPic_s,friendsCommentsList[i].ownerName,"Profile.php?id="+friendsCommentsList[i].ownerId,56);
				structure.insertIntoCell(index,0,friendControl);			
								
				var commentComment = document.createElement('div');				
				commentComment.className = "CommentsPreview";					
				structure.insertIntoCell(index,1,commentComment);		
				
				var expansionLinkContainer = document.createElement('div');
				expansionLinkContainer.className = "ExpansionLinkContainer";
				structure.insertIntoCell(index,1,expansionLinkContainer)
												
				var commentDate = document.createElement('div');
				commentDate.innerHTML = friendsCommentsList[i].lastUpdate;
				commentDate.className = "CommentDate";
				structure.insertIntoCell(index,1,commentDate);																												
				if(friendsCommentsList[i].ownerId == viewerId){
					var delLink = new AnkhLink("Delete");
					delLink.style.fontSize = "11px";
					delLink.commentId = friendsCommentsList[i].commentId;
					structure.insertIntoCell(index,1,delLink);
					EventUtil.addEventHandler(delLink,"click",function(){
						AnkhUsefulMethods.removeAll(commentNavigation);
						AnkhUsefulMethods.removeAll(commentPlaceHolder);
						ajaxLoaderImgComment.style.visibility = "visible";
						ajaxLoaderImgComment.style.display = "block";
						var url = "php/timewall_write.php";
						var method = "removeComment";		
						var parameterObj = {method:method,commentId:EventUtil.getEvent().target.commentId,pk:pk};
						new AnkhAjax(url,"post",parameterObj,that.retrieveComments,ajaxLoaderImgComment);													
						
					});
				}
				
			 	if(friendsCommentsList[i].comment != friendsCommentsList[i].previewComment){			//if different, show "see more"
			 		commentComment.innerHTML = "\""+friendsCommentsList[i].previewCommentWithDots+"\"";									 	
					
					var expansionLink = new AnkhLink("see more",revealContent);
					expansionLink.style.fontSize = "11px";
					expansionLinkContainer.appendChild(expansionLink);											
					expansionLink.expansion = friendsCommentsList[i].comment;
					expansionLink.contract = commentComment.innerHTML;
					expansionLink.targetDiv = commentComment;					
					expansionLink.isExpanded = false;																															
				}else{
					commentComment.innerHTML = "\""+friendsCommentsList[i].previewComment+"\"";	
				}																																
			}
		}		
	};
	
	/**
	 * Purpose: To navigate the comments pages
	 */
	this.switchCommentsPage = function(){
		commentNavigationCurrentPage = parseInt(EventUtil.getEvent().target.innerHTML,10);
		AnkhUsefulMethods.removeAll(commentNavigation);
		AnkhUsefulMethods.removeAll(commentPlaceHolder);
		that.displayComments();
		EventUtil.getEvent().preventDefault();
	};
	/**
	 * Purpose: Used to reveal and hide content
	 */
	revealContent = function(target){
		var expansionLink = target;
		var targetDiv = expansionLink.targetDiv;		
		if (expansionLink.isExpanded) {
			expansionLink.isExpanded = false;
			expansionLink.innerHTML = "see more";
			ankhEffects.contract(10, targetDiv, expansionLink.contract, 500,16);			
		}
		else {
			expansionLink.isExpanded = true;
			expansionLink.innerHTML = "reduce";
			ankhEffects.expand(10, targetDiv, expansionLink.expansion, 500);
		}
	};
	this.getLabels = function(){
		return labels;
	};
	
	this.getDetailedBalloonHTML = function(){
		return detailedBalloonHTML;
	};
	this.getSummaryEventHTML = function(){
		return summaryEventTblStructure.Table;
	};

	this.getLinkToDetailedBalloon  = function(){
		return linkToDetailedBalloon;
	};
	
	this.getEventId = function(){
		return eventId;
	};
	this.getEventStartDt = function(){
		return eventStartDt;
	};
	this.getEventEndDt = function(){
		return eventEndDt;
	};
	this.getUserTitle = function(){
		return userTitle;
	};
	this.getBalloonMood = function(){
		return mood;
	};
	this.getUserRole = function(){
		return userRole;
	};
	this.getUserLastUpdateDt = function(){
		return userLastUpdateDt;
	};
	this.getTodayDate = function(){
		return todayDate;
	};
	this.getPrivacy = function(){
		return privacy;
	};
	this.getOwnerName = function(){
		return ownerName;
	};
	this.getEventPic = function(){
		return eventPic_s;
	};
};
Grid = function(startdate,enddate,gridText,majorGridText,minorGranularity) //Note: Grid's startdate != GroupEvent's startdate
{
	var groupEventContainer = new Array();		
	var startDate = startdate;
	var endDate = enddate;	
	var gridText = gridText;
	var theMajorGridText = null;	
	if (minorGranularity == "year" && gridText=="Jan") {
		theMajorGridText = majorGridText;
	}
	else if (minorGranularity == "month" && gridText=="Jan") {
		theMajorGridText = majorGridText;
	}
	else if(minorGranularity == "month" && gridText=="1") {
		theMajorGridText = majorGridText;
	}
	else if(minorGranularity == "day" && gridText=="1") {
		theMajorGridText = majorGridText;
	}
	
	var gridHTML = document.createElement('div');
	gridHTML.id = "gridHTML";
	this.getGridHTML = function(){
		return gridHTML;
	};
	this.addGroupEvent = function(groupEvent){
		groupEventContainer.push(groupEvent);		
		gridHTML.appendChild(groupEvent.getGroupEventPicHTML());		
	};
	this.removeAllGroupEvents = function(){
		groupEventContainer = new Array();			
		while(gridHTML.lastChild.className == "event"){
			gridHTML.removeChild(gridHTML.lastChild);			
		}		
	} ;
	
	this.getGroupEventContainer = function(){
		return groupEventContainer;
	};	
	this.getStartDate = function(){
		return startDate;
	};
	this.getEndDate = function(){
		return endDate;
	};
	this.getGridText = function(){
		return gridText;
	};
	this.getMajorGridText = function(){
		return theMajorGridText;
	};
}
GroupEvent = function(ownerId,details,top,summaryballoon,moodObjects,zoomLvl,displayToolTipHandler,hideToolTipHandler,label,type,timewall){

	var ankhDate = new AnkhDate();
	var that = this;
	var mood = details['mood'];
	var eventCount = details['total'];
	var title = details['title'];
	var actualDt = details['actualDt'];
	var imgsrc = details['imgsrc'];	
	var eventId = details['eventId'];	
	var actualDt = ankhDate.mysqlTimeStampToDate(actualDt);
	var startdate = ankhDate.mysqlTimeStampToDate(details['startDt']);
	var enddate = ankhDate.mysqlTimeStampToDate(details['endDt']);	
	var label = label;
	var type = type;
	var timewall = timewall;
	
	var ankhEffects = new AnkhEffects();	
	var groupEventPicHTML = document.createElement('div');
	groupEventPicHTML.className = "event";			
	groupEventPicHTML.style.top = top+"px";			
					
	if(eventCount > 1){
		var countHTML = document.createElement('div');
		countHTML.className = "eventCount";
		countHTML.style.backgroundColor = moodObjects[mood]['countColour'];
		countHTML.innerHTML = eventCount;	
		groupEventPicHTML.appendChild(countHTML);	
			
		var eventBg = document.createElement('div');
		eventBg.className = "eventBg_Multiple";
		eventBg.style.borderLeft = "7px solid "+moodObjects[mood]['darkColour'];		
		eventBg.style.borderTop = "6px solid "+moodObjects[mood]['darkColour'];		
		groupEventPicHTML.appendChild(eventBg);
		
		var eventBg2 = document.createElement('div');
		eventBg2.className = "eventBg_Multiple2";
		eventBg2.style.border = "3px solid "+moodObjects[mood]['colour'];					
		groupEventPicHTML.appendChild(eventBg2);
			
		if(imgsrc){
			var eventIcon = document.createElement('img');
			eventIcon.src = imgsrc;		
			var ratio = 65 / eventIcon.width ;		
			eventIcon.width = 65;				
			if(eventIcon.height && isIE){								
				eventIcon.style.height = eventIcon.height * ratio + "px";			
			}	
			eventIcon.style.border = "1px solid "+moodObjects[mood]['colour'];			
			eventIcon.id = "eventIcon_Multiple";
			groupEventPicHTML.appendChild(eventIcon);
		}else{
				
			var eventIcon = document.createElement('div');									
			eventIcon.style.border = "1px solid "+moodObjects[mood]['colour'];			
			eventIcon.id = "eventIcon_Words_Multiple";
			groupEventPicHTML.appendChild(eventIcon);
				
			var eventTxt = document.createElement('div');
			eventTxt.id = "eventTxt_Multiple";
			eventTxt.style.background = moodObjects[mood]['lightColour'];
			eventTxt.innerHTML = ankhEffects.getPreviewMsg(title,20).msgWithDotsWODblQuote;
			eventIcon.appendChild(eventTxt);
		}
	}else{
		var eventBg = document.createElement('div');
		eventBg.className = "eventBg";
		eventBg.style.border = "4px solid "+moodObjects[mood]['colour'];
		groupEventPicHTML.appendChild(eventBg);
		if(imgsrc){
			var eventIcon = document.createElement('img');
			eventIcon.src = imgsrc;		
			var ratio = 70 / eventIcon.width ;		
			eventIcon.width = 70;				
			if(eventIcon.height && isIE){								
				eventIcon.style.height = eventIcon.height * ratio + "px";			
			}					
			eventIcon.id = "eventIcon";
			groupEventPicHTML.appendChild(eventIcon);
		}else{
			var eventIcon = document.createElement('div');															
			eventIcon.id = "eventIcon_Words";
			groupEventPicHTML.appendChild(eventIcon);
			
			var eventTxt = document.createElement('div');
			eventTxt.id = "eventTxt";
			eventTxt.style.background = moodObjects[mood]['lightColour'];
			eventTxt.innerHTML = ankhEffects.getPreviewMsg(title,30).msgWithDotsWODblQuote;
			eventIcon.appendChild(eventTxt);
		}
	}
	
	init = function(){		
		EventUtil.addEventHandler(eventIcon,"click",openBalloon);
		EventUtil.addEventHandler(eventIcon,"mouseover",function x(){
				var anchorLeft = parseInt(groupEventPicHTML.parentNode.parentNode.style.left);				
				var gridLeft = parseInt(groupEventPicHTML.parentNode.style.left);
				var iconTop = parseInt(groupEventPicHTML.style.top);
				
				var toolTipTop = iconTop + 60;
				var currentLeft = anchorLeft + gridLeft;
				var moodTxt = moodObjects[mood]['Description'];
				var count = eventCount - 1;								
				var displayDt = ankhDate.getMDY(actualDt," ");			
				displayToolTipHandler(currentLeft,toolTipTop,moodTxt,title,count,displayDt,imgsrc);
			});
		EventUtil.addEventHandler(eventIcon,"mouseout",hideToolTipHandler);
	};

	this.getGroupEventPicHTML = function(){
		return groupEventPicHTML;
	};

	openBalloon = function(){		
		if(!timewall.isTimeWallMoving()){
			hideToolTipHandler();			
			var target = eventIcon.parentNode;							//Target = Div container of the image
			var gridX = parseInt(target.parentNode.style.left,10);		//X coordinates of the grid
			var imageY = parseInt(target.style.top,10);					//Y coordinates of the event image
			var anchorLeft = parseInt(target.parentNode.parentNode.style.left,10);
			if(eventCount > 1){									
				summaryballoon.init(ownerId,startdate,enddate,mood,label,type);
				summaryballoon.draw(gridX,imageY,anchorLeft);
			}else{			
				timewall.scrollTo(actualDt,eventId,ownerId,mood,null,true);
			}	
			EventUtil.getEvent().preventDefault();	
			EventUtil.getEvent().stopPropagation();				
		}			
	};
	
	init();
};
/*
 * Purpose: To emulate a real world object movement
 * Input:
 * travelDistance - distance of the kinematics movement, e.g. 1/2 of total distance
 * initialVelocity - normally 0
 * travelTime - total travel period of kinematics movement, e.g. 1/2 of total travel time
 */
Kinematics = function(travelDistance,initialVelocity,travelTime){
	var velocity = initialVelocity;
	var distance = 0;
	var acceleration;		

	//Method used to get subsequent Kinematics object
	this.getNext = function(travelInterval){
		distance = findDistanceMoved(velocity,acceleration,travelInterval);
		velocity = findFinalVelocity(velocity,acceleration,travelInterval);
	};
	this.getAcceleration = function(){
		return acceleration;
	};
	this.getVelocity = function(){
		return velocity;
	};
	this.getDistance = function(){
		return distance;
	};
	this.setAcceleration = function(value){
		acceleration = value;
	};
	//method used to find the required acceleration/decceleration given required travel distance, initial speed and time
	findRequiredAcceleration = function(travelDistance, initialSpeed, travelTime){
		return 2 * travelDistance / (travelTime * travelTime) - 2 * (initialSpeed / travelTime);
	};
	//method used to find required final velocity given initial velocity, acceleration and traveltime
	findFinalVelocity = function(initialVelocity, acceleration, travelTime){
		return initialVelocity + acceleration * travelTime;
	};
	//method used to find distance moved given initial velocity, acceleration and traveltime
	findDistanceMoved = function(initialVelocity, acceleration, travelTime){
		return initialVelocity * travelTime + acceleration * (travelTime * travelTime) / 2;
	};

	
	acceleration = findRequiredAcceleration(travelDistance,velocity,travelTime);
};/**
 * Purpose: Draw the left panel on the TimeWall
 * @param {Object} parent
 * @param {Object} timeWall
 * @param {Object} panelData - {labels:"",events:"",lastUpdatedEvents:""}
 * @param {Boolean} viewerIsOwner
 * @param {Int} ownerId
 * @param {Object} anchorgrid
 * @param {Int} gridNum
 * @param {String} moodBarImg
 * @param {Int} panelWidth
 * @param {String} userName
 */
Panel = function(parent,timeWall,panelData,viewerIsOwner,ownerId,anchorgrid,gridNum,moodBarImg,panelWidth,userName){	
		
	var that = this;
	var ankhDate = new AnkhDate();
	var panelRows = 10;
	var maxLastUpdates = 12;
	var ankhEffects = new AnkhEffects();	
	var previousFilterValue = "Show All";
	var previousFilterType = "Show All";
	var panelObjects = new Array();	
	var filterBox;
	var eventResults;
	var panelNavigation;
	
	var pastLabels = panelData['labels'];	
		
	var leftPanel = document.createElement('div');
	leftPanel.id = "LeftPanel";
	leftPanel.style.left = "0px";
	parent.appendChild(leftPanel);
	var leftTbl = new GenericTable(1,2);
	leftTbl.Table.cellPadding = "0";
	leftTbl.Table.cellSpacing = "0";
	leftPanel.appendChild(leftTbl.Table);	
	var moodBar = new AnkhSprite(moodBarImg,43,500,{x:90,y:0});
	leftTbl.insertIntoCell(0,1,moodBar);
					
	var panel = document.createElement('div');
	panel.id = "Panel";
	panel.className = "open";
	leftTbl.insertIntoCell(0,0,panel);
	
	var panelTop = document.createElement('div');
	panel.appendChild(panelTop);
	var panelMiddle = document.createElement('div');
	panel.appendChild(panelMiddle);
	var panelBottom = document.createElement('div');
	panelBottom.id = "PanelBottom";
	panel.appendChild(panelBottom);					
	var panelOpen = true;
		
	this.initPanel = function(){
		var closeBtn = new AnkhSprite(moodBarImg,33,24,{x:0,y:330},{x:0,y:354},{x:0,y:354});
		closeBtn.className = "panelButtons";		
		moodBar.appendChild(closeBtn);
		var openBtn = new AnkhSprite(moodBarImg,33,24,{x:0,y:282},{x:0,y:306},{x:0,y:306});
		openBtn.className = "panelButtons";		
		moodBar.appendChild(openBtn);
	
		closeBtn.style.visbility = "visible";
		closeBtn.style.display = "block";
		openBtn.style.visbility = "hidden";
		openBtn.style.display = "none";
		
		EventUtil.addEventHandler(closeBtn,"click",function(){
			panelOpen = false;
			panel.style.overflow = "hidden";	
			timeWall.closePanel();
			ankhEffects.moveRight(-panelWidth,300,10,function(distance){
				leftPanel.style.left = parseInt(leftPanel.style.left,10) + distance + "px";										 
			},function(){
				leftPanel.style.left = -panelWidth +"px";
				panel.style.overflow= "auto";
				panel.className = "close";					
			});					
			closeBtn.style.visbility = "hidden";
			closeBtn.style.display = "none";
			openBtn.style.visbility = "visible";
			openBtn.style.display = "block";
			EventUtil.getEvent().stopPropagation();
		});
		EventUtil.addEventHandler(openBtn,"click",function(){
			panelOpen = true;	
			panel.style.overflow = "hidden";
			ankhEffects.moveRight(panelWidth,300,10,function(distance){
				leftPanel.style.left = parseInt(leftPanel.style.left,10) + distance + "px";										
			},function(){
				leftPanel.style.left = "0px";
				panel.style.overflow = "auto";
				panel.className = "open";
				timeWall.openPanel();
			});					
			closeBtn.style.visbility = "visible";
			closeBtn.style.display = "block";
			openBtn.style.visbility = "hidden";
			openBtn.style.display = "none";
			EventUtil.getEvent().stopPropagation();
		});
					
	
		for(var i = 0; i < pastLabels.length;i++){
			pastLabels[i]['Value'] = pastLabels[i]['type'];
			pastLabels[i]['InnerHTML'] = pastLabels[i]['value'];
		}
			
		filterBox = new AnkhSelect(pastLabels,"FilterBox","Show All");	
		EventUtil.addEventHandler(filterBox,"change",confirmFilterBox);
		panelTop.appendChild(filterBox);		
		
		EventUtil.addEventHandler(panel,"mousedown",function x(){EventUtil.getEvent().stopPropagation()});
		EventUtil.addEventHandler(panel,"mouseover",function x(){EventUtil.getEvent().stopPropagation()});
		EventUtil.addEventHandler(panel,"mouseout",function x(){EventUtil.getEvent().stopPropagation()});
		EventUtil.addEventHandler(panel,"mousewheel",panelPreventScroll);
		that.drawPanel();
		
	};
	
	this.drawPanel = function(){	
		
		AnkhUsefulMethods.removeAll(panelMiddle);			
		panelObjects = new Array();
		var outWindowsArray = new Array();				
		eventResults = document.createElement('div');
		eventResults.id = "EventResults";		
		panelMiddle.appendChild(eventResults);																		
										
		var events = panelData['events'];
		var lastUpdatedEvents = panelData['lastUpdatedEvents'];
		var displayOtherDates = true;
		
		var windowDates = timeWall.getPanelWindowDates();
		var panelWindowStart = windowDates.start;
		var panelWindowEnd = windowDates.end;
		
		if(previousFilterValue != "Show All"){			
			if(previousFilterType == "updates"){
				for(var i = 0;i < lastUpdatedEvents.length;i++){
					if(i < maxLastUpdates){
						var testEvent = events[lastUpdatedEvents[i]['eventId']];
						testEvent['displayOtherDates'] = false;
						if(testEvent['eventStartDt'] - panelWindowStart >= 0 && panelWindowEnd - testEvent['eventStartDt'] > 0){
							panelObjects.push(testEvent);															 		
						}else{
							if(displayOtherDates){
								testEvent['displayOtherDates'] = true;
								displayOtherDates = false;	
							}
							outWindowsArray.push(testEvent);
						}
					}				
				}					
			}else{						//if not updates
				for(var i in events){		
					events[i]['displayOtherDates'] = false;									
					if(hasLabel(events[i],previousFilterValue,previousFilterType)){
						if(events[i]['eventStartDt'] - panelWindowStart >= 0 && panelWindowEnd - events[i]['eventStartDt'] > 0){													
							panelObjects.push(events[i]);											
						}else{
							if(displayOtherDates){
								events[i]['displayOtherDates'] = true;
								displayOtherDates = false;	
							}													
							outWindowsArray.push(events[i]);							
						}	
					}																							
				}
			}		
		}else{						//if Show All is selected						
			for(var i in events){							
				events[i]['displayOtherDates'] = false;							
				if(events[i]['eventStartDt'] - panelWindowStart >= 0 && panelWindowEnd - events[i]['eventStartDt'] > 0){																
					panelObjects.push(events[i]);		
				}else{					
					if(displayOtherDates){
						events[i]['displayOtherDates'] = true;
						displayOtherDates = false;	
					}					
					outWindowsArray.push(events[i]);
				}																										
			}
		}
			
		panelObjects = panelObjects.concat(outWindowsArray);						
		var panelContent = document.createElement('div');
		panelMiddle.appendChild(panelContent);
		var totalEvents = panelObjects.length;		
		drawPanelPage(1,totalEvents,panelContent,panelWindowStart,panelWindowEnd);				
		panelNavigation = new NavigationBar(totalEvents,panelRows,function(){
			drawPanelPage(EventUtil.getEvent().target.innerHTML,totalEvents,panelContent,panelWindowStart,panelWindowEnd);
			panelBottom.appendChild(panelNavigation.getHTML(EventUtil.getEvent().target.innerHTML));	
		});
		panelBottom.appendChild(panelNavigation.getHTML(1));					
	};
	
	drawPanelPage = function(pageNum,totalEvents,parent,panelWindowStart,panelWindowEnd){
		panel.scrollTop = "0px";
		AnkhUsefulMethods.removeAll(panelBottom);
		var start = (pageNum - 1) * panelRows + 1;
		var end = pageNum * panelRows;
		if(end > panelObjects.length ){
			end = panelObjects.length;
		}
		var startingIndex = start - 1;		

		if(totalEvents == 0){
			if(previousFilterValue == "Show All"){
				if(viewerIsOwner){
					var eventResultsParts = new Array();
					eventResultsParts[0] = "You do not have any events. Click ";
					eventResultsParts[1] = new AnkhLink("here",null,"AddEvent.php");
					eventResultsParts[2] = "&nbsp;to add your first event";
					eventResults.appendChild(new AnkhDivBuilder(eventResultsParts));
				}else{
					eventResults.innerHTML = userName+" does not have any events.";
				}				
			}else{
				eventResults.innerHTML = "No matched events<p/>The label - "+previousFilterValue+" - did not match any of the events. ";
			}			
		}else{
			eventResults.innerHTML = "Results: <b>"+start+" - "+end+"</b> of "+totalEvents;
		}
		AnkhUsefulMethods.removeAll(parent);
		var count = 0;
		if(panelObjects.length > 0){
			var rows = panelRows;
			if(panelObjects.length - startingIndex < rows){
				rows = panelObjects.length - startingIndex;
			}
			var panelTblStructure = new GenericTable(rows,1);
			panelTblStructure.Table.style.width = "180px";
			panelTblStructure.Table.cellPadding = "0";
			panelTblStructure.Table.cellSpacing = "0";
			parent.appendChild(panelTblStructure.Table);
			
			if(startingIndex == 0 && !panelObjects[0]['displayOtherDates']){
				var eventsWithinWindowTxt = document.createElement('div');
				eventsWithinWindowTxt.id = "EventsWithinWindowTxt";
				eventsWithinWindowTxt.innerHTML = "<b>"+previousFilterValue+"</b> events in this view";
				panelTblStructure.insertIntoCell(0,0,eventsWithinWindowTxt);					
			}
							
			for(var i = startingIndex;i < panelObjects.length;i++){					
				if(count >= panelRows){
					return;
				}				
				
				if(panelObjects[i]['displayOtherDates']){
					var otherRange = document.createElement('div');
					otherRange.id = "OtherRange";
					otherRange.innerHTML = "Out of this view";
					panelTblStructure.insertIntoCell(i - startingIndex,0,otherRange);
				}
										
				var previewContainer = document.createElement('div');
				previewContainer.className = "previewContainer";			
				panelTblStructure.insertIntoCell(i - startingIndex,0,previewContainer);			
				var moodColor = timeWall.getMoodsTranslation([panelObjects[i]['mood']]).colour;
				var previewDt = document.createElement('div');
				previewDt.className = "previewDt";
				previewDt.style.color = moodColor;
				
				previewDt.innerHTML = ankhDate.getDMY(panelObjects[i]['eventStartDt']," ");
				previewContainer.appendChild(previewDt);
								
				var title = new AnkhLink(panelObjects[i]['eventTitle'],null,null,null,true,{mouseover:"#5E6F61",mouseout:"#5E6F61"});			
				previewContainer.appendChild(title);
				title.data = panelObjects[i];
				EventUtil.addEventHandler(title,"click",function(){
					var data = EventUtil.getEvent().target.data;
					timeWall.scrollTo(data['eventStartDt'],data['eventId'],ownerId,data['mood']);
				});
				
				var previewContent = document.createElement('div');
				previewContent.className = "previewContent";
				previewContainer.appendChild(previewContent);
				
				if(panelObjects[i]['src_xs']){
					var pic = new FriendControl(panelObjects[i]['src_xs'],null,null,null,60);
					pic.style.cursor = "pointer";
					pic.data = panelObjects[i];
					EventUtil.addEventHandler(pic,"click",function(){
						var data = EventUtil.getEvent().target.parentNode.parentNode.data;
						timeWall.scrollTo(data['eventStartDt'],data['eventId'],ownerId,data['mood']);
					});
					pic.style.cssFloat = "right";
					pic.style.styleFloat = "right";
					pic.style.marginLeft = "5px";					
					previewContent.appendChild(pic);
				}
																				
				var description = document.createElement('div');
				description.className = "description";
				if(panelObjects[i]['eventPreview'] != ""){
					if(viewerIsOwner == 1){
						description.innerHTML = "You say: "+panelObjects[i]['eventPreview'];	
					}else{
						description.innerHTML = userName+" says: "+panelObjects[i]['eventPreview'];
					}					
				}else{
					if(viewerIsOwner == 1){
						description.innerHTML = "You did not say anything";
					}else{
						description.innerHTML = userName+" did not say anything";
					}					
				}			
				previewContent.appendChild(description);						
										
				var labels = panelObjects[i]['labels'];
				if(labels.length > 0){
					var labelsParts = new Array();				
					labelsParts[0] = document.createElement('span');			
					labelsParts[0].innerHTML = "Labels: "; 
					for(var j = 0;j <labels.length;j++){			
						var link = new AnkhLink(labels[j],function(target){							
							that.setFilterValue(target.innerHTML);							
						},null,null,true);			
						labelsParts.push(link)
						if(j < labels.length - 2){
							labelsParts.push(", ");	
						}else if(j == labels.length - 2){
							labelsParts.push("&nbsp;and ");
						}						
					}
					var labelsSentence = new AnkhDivBuilder(labelsParts);
					labelsSentence.className = "labelsSentence";
					previewContainer.appendChild(labelsSentence);
				}
				count += 1;
				
			}
		}		
	};
	
	confirmFilterBox = function(){
		var selectedOption = filterBox.options[filterBox.selectedIndex];
		var filterValue = selectedOption.innerHTML;
		var filterType = selectedOption.value;
		if(filterValue != ""){
			if(filterType != previousFilterType || filterValue != previousFilterValue){
				previousFilterValue = filterValue;
				previousFilterType = filterType;			
				var anchorController = anchorgrid.getAnchorController();									
				for(var i = 0;i < anchorController.length;i++){
					anchorController[i].removeAllGroupEvents();				
				}
				var balloons = timeWall.getBalloons();
				var eventObj = balloons['detailed'].getEventObj();
				if(eventObj){
					if(!AnkhUsefulMethods.isInArray(eventObj.getLabels(),filterValue) &&
						eventObj.getPrivacy().toUpperCase() != filterValue.toUpperCase()){
						balloons['summary'].resetPosition();		
						balloons['detailed'].resetPosition();					
					}			
				}else{
					balloons['summary'].resetPosition();		
					balloons['detailed'].resetPosition();	
				}
				drawGroupedEvents(anchorController[0].getStartDate(),gridNum);			//start from the first div of the current chart
				that.drawPanel();
			}
		}
	};
	
	this.setFilterValue = function(value){
		for(var i = 0;i < filterBox.options.length;i++){
			if(filterBox.options[i].innerHTML == value){
				filterBox.selectedIndex	= i;
				break;
			}
		}		
		confirmFilterBox();
	};
	
	panelPreventScroll = function(){									
			if (isIE) {
				delta = -EventUtil.getEvent().wheelDelta / 120;			
			}
			else {
				if (isKHTML) {
					delta = -EventUtil.getEvent().wheelDelta / 120;
				}
				else if (isOpera) {
						delta = EventUtil.getEvent().wheelDelta / 120;
				}
				else { //for firefox
					delta = EventUtil.getEvent().detail / 3;
				}
			}		
			EventUtil.getEvent().stopPropagation();
			if (panel.scrollHeight > timeWall.getTimeWallHeight()) { //only if balloon has a scroll bar
				if (delta < 0) { //scroll up								
					var minScrollTop = parseInt(Math.abs(delta)*15 / 100 * timeWall.getTimeWallHeight(),10);
					if (panel.scrollTop == 0) { //reach the top									
						EventUtil.getEvent().preventDefault();
					}
					else if (isIE && panel.scrollTop <= minScrollTop) {
						panel.scrollTop = 0;
						EventUtil.getEvent().preventDefault();
					}							
				}
				else if (delta > 0) { //scroll down					
					var temp = panel.scrollHeight - panel.scrollTop - timeWall.getTimeWallHeight();					
					if (temp <= 0) {
						EventUtil.getEvent().preventDefault();
					}				
					else if (isIE && temp  <= Math.abs(delta) * 15 / 100 * timeWall.getTimeWallHeight()) {
						panel.scrollTop = panel.scrollHeight - timeWall.getTimeWallHeight();
						EventUtil.getEvent().preventDefault();
					}
				}
			}		
		};
	
	
	
	hasLabel = function(eventObj,label,type){
		switch(type){
			case "privacy": if(eventObj['privacy'] == label){
								return true;
							}
							break;
			case "custom": 	for(var i = 0;i < eventObj['labels'].length; i++){
								if(eventObj['labels'][i] == label){
									return true;
								}
							}
							break;		
			default: break;
		}
		
		return false;
	};	
	this.getPreviousFilterValue = function(){
		return previousFilterValue;
	};
	this.getPreviousFilterType = function(){
		return previousFilterType;
	};
	this.isPanelOpen = function(){
		return panelOpen;
	};
	
};TerminatingBand = function(timeWallWidth){
	var bandStartDate;
	var bandEndDate;
	var bandMinLeft;		//min. left of the terminating band
	var terminatingBandHTML = document.createElement('div');
	var terminatingBandLabel = document.createElement('div');
	terminatingBandLabel.innerHTML = "Today";
	terminatingBandHTML.id = "TerminatingBand";
	terminatingBandHTML.appendChild(terminatingBandLabel);
	
	this.setBandDates = function(startDate,endDate){
		bandStartDate = startDate;
		bandEndDate = endDate;	
	};
	this.getTerminatingBandHTML = function(){
		return terminatingBandHTML;
	};
	this.setBandMinLeft = function(value){
		bandMinLeft = value - timeWallWidth/2;
	};	
	this.getBandMinLeft = function(){
		return bandMinLeft;
	};
	this.isExceeded = function(date){
		if(date > bandStartDate){
			return date - bandStartDate;
		}
		return 0;	
	};
	this.setLeftAutoCorrection = function(value){
		if (value < bandMinLeft) {
			terminatingBandHTML.style.left = bandMinLeft + "px";
			return value - bandMinLeft;
		}
		else{
			terminatingBandHTML.style.left = value + "px";
			return null;
		}
	};
	this.getLeft = function(){
		return parseInt(terminatingBandHTML.style.left,10);
	};
};
/**
 * Purpose - Create TimeWall
 * @param {Object} ownerObj - {fullNm:"Cheong Dewei",userId:"10",sex:"m"}
 * @param {Int} viewerId - viewer's id
 * @param {Date} latestEventDate - owner's latest event date in MYSQL date format
 * @param {Object} parent - parent object
 * @parem {Object} photoPopup - photopopup object
 * @param {String} ajaxUrl - url of the timewall_json 
 * @param {Boolean} isPublic - true -> if public
 * @param {Boolean} viewerIsOwner - true -> is owner
 * @param {Array} moodList - list of moods
 * @param {Array} FAQQuestions - list of FAQs
 * @param {Object} timeWallSetting - {"lastZoomLevel":1,"nextWindowAnchorPoint":"2007-03-01","totalEventCount":"18","totalViewableEventCount":"18","bgs":["wallimage/wall photo bg.jpg"],selectedBg:1,"scroll":true}
 * @param {Object} panelData - {labels:"",events:"",lastUpdatedEvents:""}
 */
TimeWall = function(ownerObj,viewerId,parent,photoPopup,ajaxUrl,isPublic,viewerIsOwner,moodList,FAQQuestions,timeWallSetting,panelData,isGroup){			
	var addEventBtnIncl = false;
	
	if(!isPublic && viewerIsOwner && !isGroup){	
		addEventBtnIncl = true;	
	}	
	var that = this;	
	var moods = 6;
	var gridWidth = 80;	
	var panelWidth = 200;
	
	var panelWindowStart, panelWindowEnd;
	var rootDir = "TimeWallv7/";
	var ankhDate = new AnkhDate();
	var zoomLevel = timeWallSetting['lastZoomLevel'];
	var latestEventDate = timeWallSetting['nextWindowAnchorPoint'];	
	var canSeeEvents = timeWallSetting['totalViewableEventCount'];
	var totalEvents = timeWallSetting['totalEventCount'];
	var pk = timeWallSetting['pk'];
	var backgrounds = timeWallSetting['bgs'];
	var selectedBackground = timeWallSetting['selectedBg'];
	var pastLabels = panelData['labels'];
	
	var ownerId = ownerObj['userId'];
	var userName = ownerObj['fullNm'];
	var ownerGender = ownerObj['sex'];	
	
	var isMember = false;
	var isGroup = false;	
	if(ownerObj['memberType'] != null){
		isGroup = true;	
		if( ownerObj['memberType'] >= 1){
			isMember = true;
		}
	}	 	
	
	//Variables to control the TimeWall grid structure
	var gridNum = Math.ceil(AnkhUsefulMethods.getViewPort().width/gridWidth) * 3; // total number of Divs for this view port's width
	var timeWallWidth = 960;
	var timeWallHeight = 500;
	var startingDiv;						//order of the starting Div at y-axis
	var divIndexFromLatestEvent = 8;		//visible start of window is 10 index from latestEventDate 
		
	//Used by the scrolling feature of TimeWall
	var activated = false;
	var timeWallMoving = false;
	var preX = 0;
	var cumulativeDistanceMoved = 0;
	//button scrolling variables
	var btnScrollAnimationTravelTime = 300;		//300ms
	var btnScrollIteration = 10;	
	
	//external scrolling variables
	var externalScrollAnimationTravelTime = 1000;
	var externalScrollIteration = 20;
	
	//cumulative number of Divs to be added or removed. When <= -1, add grid on the left side. When >= 1, add grid on the right side.
	var numOfDivToBeAdded = 0;	
			
	//Used by the zooming feature of TimeWall
	var zoomActivated = false;
	
	//Settings Objects defining the TimeWall
	var granularity = new Array();
	granularity.push({majorGridType:"month",minorGrid:1,minorGridType:"day"},
					 {majorGridType:"month",minorGrid:0.25,minorGridType:"month"},
					 {majorGridType:"month",minorGrid:0.5,minorGridType:"month"},
					 {majorGridType:"year",minorGrid:1,minorGridType:"month"},
					 {majorGridType:"year",minorGrid:0.5,minorGridType:"year"},
					 {majorGridType:"year",minorGrid:1,minorGridType:"year"});
	
	var image = new Object();
	if (isIE && !isMinIE7) {
		image['pic'] = rootDir + "wallimage/8.png";	
	}else{
		image['pic'] = rootDir + "wallimage/32.png";
	}	
	image['majorDisplayImage'] = rootDir + "wallimage/IntDisplay.png";
	image['Background'] = backgrounds[selectedBackground]['src'];
	for(var x in image){
	 	var img = new Image();
	 	img.src = image[x];		
	}
	
	var eventImage = new Object();
	eventImage['SMood1']= {img:image['pic'],width:29,height:48,normSrc:{x:55,y:456}};
	eventImage['SMood2']= {img:image['pic'],width:29,height:48,normSrc:{x:55,y:408}};
	eventImage['SMood3']= {img:image['pic'],width:29,height:48,normSrc:{x:55,y:360}};
	eventImage['SMood4']= {img:image['pic'],width:29,height:48,normSrc:{x:55,y:312}};
	eventImage['SMood5']= {img:image['pic'],width:29,height:48,normSrc:{x:55,y:264}};
	eventImage['SMood6']= {img:image['pic'],width:29,height:48,normSrc:{x:55,y:216}};
		 
	var moodTranslation = new Array();
	moodTranslation[0] = {Image1: ""};
	moodTranslation[1] = {Image1: eventImage['SMood1'],colour:"#6B6B6B",countColour:"#343434",darkColour:"#444444",lightColour:"#EFEFEF"};
	moodTranslation[2] = {Image1: eventImage['SMood2'],colour:"#96BBCE",countColour:"#35446c",darkColour:"#4E86A5",lightColour:"#EEF3F7"};
	moodTranslation[3] = {Image1: eventImage['SMood3'],colour:"#97C678",countColour:"#39473b",darkColour:"#649940",lightColour:"#F2F8EF"};
	moodTranslation[4] = {Image1: eventImage['SMood4'],colour:"#F8D668",countColour:"#846c1f",darkColour:"#AB8607",lightColour:"#FEF8E0"};
	moodTranslation[5] = {Image1: eventImage['SMood5'],colour:"#E2A883",countColour:"#79572b",darkColour:"#D07335",lightColour:"#FBF2EC"};
	moodTranslation[6] = {Image1: eventImage['SMood6'],colour:"#D66583",countColour:"#722828",darkColour:"#CA355F",lightColour:"#FBF0F3"};
		
	moodTranslation[0].Description = "";
	var i = 1;
	var j = moodList.length - 1;
	while(i < moodTranslation.length){
		moodTranslation[i].Description = moodList[j];	
		i ++;
		j --;
	}			 
	var numOfAjaxLoads = 0;						//used to hide the ajax loader when this variable becomes 0
	var numOfTimesManualRightScrolled = 0;		//used to set the final terminating band left location when this variable becomes 0
	var ankhEffects = new AnkhEffects();
	
	//HTML configurations
	var timeWallContainer = document.createElement('div');
	timeWallContainer.id = "TimeWallContainer";	
	
	/*FAQ*/
	if(FAQQuestions){
		var timeWallFAQ = document.createElement('div');
		timeWallFAQ.id = "TimeWallFAQ";
		timeWallContainer.appendChild(timeWallFAQ);	
		var FAQIndex = parseInt(Math.random()*100000 % FAQQuestions.length,10);			
		
		var FAQNavigate = document.createElement('div');
		FAQNavigate.id = "FAQNavigate";
		timeWallFAQ.appendChild(FAQNavigate);
		var FAQNavigateTxt = document.createElement('div');
		FAQNavigateTxt.innerHTML = "Questions";
		FAQNavigateTxt.className = "TimeWallFAQButtons";
		FAQNavigate.appendChild(FAQNavigateTxt);
		var FAQNavigateLeft = new AnkhSprite(image['pic'],16,16,{x:0,y:234},{x:17,y:234},{x:17,y:234});
		FAQNavigateLeft.style.cursor = "pointer";
		FAQNavigate.appendChild(FAQNavigateLeft);
		var FAQNavigateRight = new AnkhSprite(image['pic'],16,16,{x:0,y:250},{x:17,y:250},{x:17,y:250});
		FAQNavigateRight.style.cursor = "pointer";
		FAQNavigate.appendChild(FAQNavigateRight);
		
		var FAQtitle = new AnkhLink(FAQQuestions[FAQIndex].Title,null,"FAQ.php#"+FAQQuestions[FAQIndex].Anch);
		FAQtitle.id = "FAQTitle";
		FAQtitle.target = "_blank";		
		timeWallFAQ.appendChild(FAQtitle);
		var FAQdescription = document.createElement('span');
		FAQdescription.innerHTML = "&nbsp;- "+ankhEffects.getPreviewMsg(FAQQuestions[FAQIndex].Desc,70).msgWithDots;
		timeWallFAQ.appendChild(FAQdescription);
	}
	/*TimeWallHTML*/				
	var timeWallHTML = document.createElement('div');
	timeWallHTML.style.width = timeWallWidth + "px";			//need to have this so that terminating band can use this information
	timeWallHTML.style.height = timeWallHeight + "px";
	timeWallHTML.style.border = "2px solid #C1CCB5";
	timeWallHTML.id = "TimeWall";
	var anchorgrid = new AnchorGrid(gridWidth);
	var detailedBalloon = new DetailedBalloon(this,rootDir,isPublic,image['pic'],image['majorDisplayImage'],viewerIsOwner,isGroup,isMember,ownerId,pk);	
	var summaryBalloon = new SummaryBalloon(ownerId,userName,this,detailedBalloon,rootDir,photoPopup,ajaxUrl,image['pic'],image['majorDisplayImage'],isPublic,viewerIsOwner,viewerId,isGroup,pastLabels,pk);	
	detailedBalloon.setSummaryBalloon(summaryBalloon);
	
	var timeWallBackground = new AnkhSprite(image['Background'],1000,474,{x:0,y:0});
	timeWallBackground.id = "TimeWallBackground";
	timeWallBackground.style.backgroundRepeat = "repeat";	
	
	var zoomAnimation = new ZoomAnimation(rootDir);
	var terminatingBand = new TerminatingBand(timeWallWidth);
	
	/*Left Panel*/		
	var panel = new Panel(timeWallHTML,that,panelData,viewerIsOwner,ownerId,anchorgrid,gridNum,image['pic'],panelWidth,userName);		
						
	/* Timewall word*/
	var timeWallLogo = document.createElement('div');	
	timeWallLogo.id = "TimeWallLogoOpen";
	timeWallLogo.innerHTML = "TimeWall";
	
	var customiseLink = new AnkhLink("customise");	
	customiseLink.id = "CustomiseLink";
	timeWallLogo.appendChild(customiseLink);
	if(!viewerIsOwner){
		customiseLink.style.display = "none";	
	}
	
	var customiseLinkPopup = new GreenPopup("SupportControls/Popup/",450,"Customise your TimeWall","Done","button","");	
	
	var totalEventsDisplay = document.createElement('div');	
	totalEventsDisplay.id = "TotalEventsDisplayOpen";				
	var eventWord = "event";
	if(totalEvents > 1){
		eventWord = "events";
	}
	if(isGroup){
		if(totalEvents == 0){
			totalEventsDisplay.innerHTML = userName+" does not have any "+eventWord;
		}else if(canSeeEvents == 0){
			totalEventsDisplay.innerHTML = "You cannot see any of the "+totalEvents+" "+eventWord+" of "+userName;
		}else if(totalEvents == canSeeEvents){
			totalEventsDisplay.innerHTML = "You can see all "+totalEvents+" "+eventWord+" of "+userName;
		}else{
			totalEventsDisplay.innerHTML = "You can see "+canSeeEvents+" out of "+totalEvents+" "+eventWord+" of "+userName;
		}
	}else{
		if(viewerIsOwner){
			totalEventsDisplay.innerHTML = "You have "+totalEvents+" "+eventWord;
		}else if(totalEvents == 0){
			totalEventsDisplay.innerHTML = AnkhUsefulMethods.genderStr(ownerGender).noun +" does not have any "+eventWord;
		}else if(canSeeEvents == 0){
			totalEventsDisplay.innerHTML = "You cannot see any of "+AnkhUsefulMethods.genderStr(ownerGender).action+" "+totalEvents+" "+eventWord;
		}else if(totalEvents == canSeeEvents){
			totalEventsDisplay.innerHTML = "You can see all of "+AnkhUsefulMethods.genderStr(ownerGender).action+" "+totalEvents+" "+eventWord;
		}else{
			totalEventsDisplay.innerHTML = "You can see "+canSeeEvents+" out of "+AnkhUsefulMethods.genderStr(ownerGender).action+" "+totalEvents+" "+eventWord;
		}
	}		
	var loadingImg = new AnkhAJAXLoader("");
	loadingImg.id = "TimeWallLoadingImage";
	
	var zoomMsg = document.createElement('div');
	zoomMsg.id = "ZoomMsgOpen";		
	
	var scrollControls = document.createElement('div');
	scrollControls.id = "ScrollControls";
	var scrollLeft = new AnkhSprite(image['pic'],18,18,{x:0,y:97},{x:0,y:117},{x:0,y:137});	
	scrollLeft.id = "ScrollLeftOpen";	
	var scrollRight = new AnkhSprite(image['pic'],18,18,{x:20,y:97},{x:20,y:117},{x:20,y:137});
	scrollRight.id = "ScrollRightOpen";	

	var zoomControls = document.createElement('div');
	zoomControls.id = "ZoomControlsOpen";	
	var zoomInBtn = new AnkhSprite(image['pic'],18,18,{x:58,y:97},{x:58,y:117},{x:58,y:137});
	zoomInBtn.id = "ZoomInBtn";

	var zoomOutBtn = new AnkhSprite(image['pic'],18,18,{x:40,y:97},{x:40,y:117},{x:40,y:137});
	zoomOutBtn.id = "ZoomOutBtn";
	
	var zoomBarContainer = document.createElement('div');
	zoomBarContainer.id = "ZoomBarContainer";		
	var zoomBar;
	var zoomPreX;			//used to register the mousedown prex for zoom. This is allow for comparison onclick.
	
	var addEventArrow = new AnkhSprite(image['pic'],30,30,{x:39,y:158});
	addEventArrow.id = "AddEventArrow";
	var addEventBtn = new AnkhSprite(image['pic'],77,30,{x:1,y:0},{x:1,y:33},{x:1,y:65});	
	addEventBtn.id = "AddEventButton";	
	var ankhToolTip;			
	
	var majorDisplayHTML = document.createElement('div');
	majorDisplayHTML.id = "MajorDisplayOpen";	
	var majorDisplayImage = new AnkhSprite(image['majorDisplayImage'],53,43,{x:0,y:0});
	majorDisplayImage.id = "MajorDisplayImg";	
	var majorDisplayText = document.createElement('div');
	majorDisplayText.id = "MajorDisplayTxt";
	majorDisplayHTML.appendChild(majorDisplayImage);
	majorDisplayHTML.appendChild(majorDisplayText);
	
	/**
	 * Purpose: First method to be called to initialise timewall
	 * @param {DateTime} latestEventDate - 24th div JSdate from 0px. 
	 */		
	init = function(latestEventDate){
		createCustomisePopup();
		var summaryBalloonHTML = summaryBalloon.getSummaryBalloonHTML();
		var detailedBalloonHTML = detailedBalloon.getDetailedBalloonHTML();
		var terminatingBandHTML = terminatingBand.getTerminatingBandHTML();
		var anchorgridHTML = anchorgrid.getAnchorHTML();
		var zoomAnimationHTML = zoomAnimation.getAnimationHMTML();
				
		timeWallContainer.appendChild(timeWallHTML);	
		timeWallHTML.appendChild(timeWallBackground);		
		timeWallHTML.appendChild(majorDisplayHTML);
		timeWallHTML.appendChild(anchorgridHTML);				
		timeWallHTML.appendChild(timeWallLogo);
		timeWallHTML.appendChild(totalEventsDisplay);			
		ankhToolTip = new AnkhToolTip(timeWallHTML,150);
		timeWallHTML.appendChild(zoomMsg);				
		timeWallHTML.appendChild(zoomAnimationHTML);
		parent.appendChild(timeWallContainer);
		
		if (isIE && !isMinIE7) {					//to give IE6 some time to cache the sprites
			window.setTimeout(function x(){	
			if (addEventBtnIncl) {
				timeWallHTML.appendChild(addEventBtn);
				timeWallHTML.appendChild(addEventArrow);				
			}				
			timeWallHTML.appendChild(loadingImg);
			scrollControls.appendChild(scrollLeft);
			scrollControls.appendChild(scrollRight);
			timeWallHTML.appendChild(scrollControls);
			
			zoomControls.appendChild(zoomInBtn);
			zoomControls.appendChild(zoomBarContainer);	
			zoomControls.appendChild(zoomOutBtn);			
			timeWallHTML.appendChild(zoomControls);
			timeWallHTML.appendChild(terminatingBandHTML);
			timeWallHTML.appendChild(detailedBalloonHTML);
			timeWallHTML.appendChild(summaryBalloonHTML);},500);
		}else{
			if (addEventBtnIncl) {
				timeWallHTML.appendChild(addEventBtn);
				timeWallHTML.appendChild(addEventArrow);
			}	
			timeWallHTML.appendChild(loadingImg);
			scrollControls.appendChild(scrollLeft);
			scrollControls.appendChild(scrollRight);
			timeWallHTML.appendChild(scrollControls);
			
			zoomControls.appendChild(zoomInBtn);
			zoomControls.appendChild(zoomBarContainer);	
			zoomControls.appendChild(zoomOutBtn);			
			timeWallHTML.appendChild(zoomControls);
			timeWallHTML.appendChild(terminatingBandHTML);
			timeWallHTML.appendChild(detailedBalloonHTML);
			timeWallHTML.appendChild(summaryBalloonHTML);
		}

		startingDiv = Math.floor((gridNum - parseInt(AnkhUsefulMethods.getStyle(timeWallHTML,"Width"),10)/gridWidth)/2);
		
		
		var JSLatestEventDate = ankhDate.mysqlTimeStampToDate(latestEventDate);	
		initDraw(JSLatestEventDate,divIndexFromLatestEvent);
		panel.initPanel();								
		initButtons();		
		initScroll();
		initZoom();				
	};	
	/**
	 * Purpose: Draw the fundamentals of the time wall, fundamentals include the following:
	 * 		1.Calculate the 0px starting point
	 * 		2.Draw the grids based on 0px starting date
	 * 		3.Initialise Terminating Band
	 * 		4.Update Major Display
	 * @param {DateTime} latestEventDate - divCountFromYAxisth div JSdate from 40px. 
	 * @param {Int} divIndexFromLatestEvent - number of div to subtract from latesteventdate to find the window start date
	 */
	initDraw = function(latestEventDate,divIndexFromLatestEvent){				
		var roundedDownStartDate = ankhDate.roundDownToFirstDay(latestEventDate,granularity[zoomLevel].minorGridType,granularity[zoomLevel].minorGrid);		
		var startDate = ankhDate.subtractDaysFormat(roundedDownStartDate,divIndexFromLatestEvent *granularity[zoomLevel].minorGrid,granularity[zoomLevel].minorGridType);																	
		drawEventsOnGrid(startDate);		
		initTerminatingBand(startDate);
		updateMajorDisplay();
	};
	
	drawEventsOnGrid = function(startDate){
		numOfDivToBeAdded = 0;
		anchorgrid.clear();
		var chartFirstDate = drawGrids(startDate,startingDiv,gridNum - startingDiv);	
		drawGroupedEvents(chartFirstDate,gridNum);
	};		
	
	initButtons = function(){
		if(FAQQuestions){
			EventUtil.addEventHandler(FAQNavigateLeft,"click",moveFAQDown);
			EventUtil.addEventHandler(FAQNavigateRight,"click",moveFAQUp);
		}
		EventUtil.addEventHandler(customiseLink,"mousedown",function x(){EventUtil.getEvent().stopPropagation()});
		EventUtil.addEventHandler(customiseLink,"click", function(){customiseLinkPopup.showInCenterofBrowser();});
		EventUtil.addEventHandler(scrollLeft,"mousedown",function x(){EventUtil.getEvent().stopPropagation()});
		EventUtil.addEventHandler(scrollLeft,"mouseover",function x(){EventUtil.getEvent().stopPropagation()});
		EventUtil.addEventHandler(scrollLeft,"mouseout",function x(){EventUtil.getEvent().stopPropagation()});
		EventUtil.addEventHandler(scrollLeft,"click",manualScrollLeftEnd);				
		EventUtil.addEventHandler(scrollRight,"mousedown",function x(){EventUtil.getEvent().stopPropagation()});
		EventUtil.addEventHandler(scrollRight,"mouseover",function x(){EventUtil.getEvent().stopPropagation()});
		EventUtil.addEventHandler(scrollRight,"mouseout",function x(){EventUtil.getEvent().stopPropagation()});
		EventUtil.addEventHandler(scrollRight,"click",manualScrollRightEnd);				
		EventUtil.addEventHandler(zoomInBtn,"click",manualZoomInEnd);				
		EventUtil.addEventHandler(zoomOutBtn,"click",manualZoomOutEnd);		
		
		if (addEventBtnIncl) {
			EventUtil.addEventHandler(addEventBtn, "click", goToAddEventPage);			
		}		
	};
	
	/**
	 * Purpose: Create the popup to allow user to customise his TimeWall
	 */
	createCustomisePopup = function(){		
		var customiseLinkPopupContent = customiseLinkPopup.getContent();
		var message = document.createElement('div');
		message.innerHTML = "Choose any background for your TimeWall.";
		customiseLinkPopupContent.appendChild(message); 
		
		var popupTbl = new GenericTable(Math.ceil(backgrounds.length/2),2);
		customiseLinkPopupContent.appendChild(popupTbl.Table);
		
		var chkBoxList = new Array();
		for(var i = 0;i < backgrounds.length;i++){
			var thumbnail = new FriendControl(backgrounds[i]['thumbnail']);
			thumbnail.style.cursor = "pointer";		
			popupTbl.insertIntoCell(Math.floor(i/2),i%2,thumbnail);
			var chkBox = new AnkhCheckBox("popup",i,i);
			chkBox.assignedValue = i;			
			thumbnail.chkBox = chkBox;
			popupTbl.insertIntoCell(Math.floor(i/2),i%2,chkBox);
			popupTbl.insertIntoCell(Math.floor(i/2),i%2,"Choose me");
			chkBoxList.push(chkBox);
			if(i == selectedBackground){
				chkBox.checked = true;
			}				
			EventUtil.addEventHandler(thumbnail,"click",function (){
				for(var j = 0;j < chkBoxList.length;j++){
					chkBoxList[j].checked = false;
				}		
				EventUtil.getEvent().target.parentNode.parentNode.chkBox.checked = true;
				previewNewBg(EventUtil.getEvent().target.parentNode.parentNode.chkBox.assignedValue);			
			});
			EventUtil.addEventHandler(chkBox,"click",function (){
				for(var j = 0;j < chkBoxList.length;j++){
					chkBoxList[j].checked = false;
				}
				EventUtil.getEvent().target.checked = true;
				previewNewBg(EventUtil.getEvent().target.assignedValue);			
			});	
			
			
		}	
		customiseLinkPopup.setConfirmBtnMouseup(function(){
			var url = "php/timewall_write.php";
			var method ="setBackground";
			for(var i = 0; i < chkBoxList.length;i++){
				if(chkBoxList[i].checked){
					var ajaxParameter = {method:method,ownerId: ownerId,selectedBackground:chkBoxList[i].assignedValue,pk:pk};
					new AnkhAjax(url,"post",ajaxParameter);
					break;
				}
			}					
			customiseLinkPopup.hide();	
		},"click");				 
	};
		
	previewNewBg = function(bgIndex){
		selectedBackground = bgIndex;
		image['Background'] = backgrounds[selectedBackground]['src'];		
		timeWallBackground.style.backgroundImage = "url('" + image['Background'] + "')";		
	};
	
	
	/**
	 * Purpose: Redirect user to add event page
	 */
	goToAddEventPage = function(){
		window.location.href = "AddEvent.php";	
		EventUtil.getEvent().stopPropagation();	
	};
	
	moveFAQDown = function(){
		if(FAQIndex != 0){
			FAQIndex = (FAQIndex - 1)%FAQQuestions.length;
		}else{
			FAQIndex = FAQQuestions.length - 1;
		}
		FAQtitle.innerHTML = FAQQuestions[FAQIndex].Title;
		FAQtitle.href = "FAQ.php?#"+FAQQuestions[FAQIndex].Anch;		
		FAQdescription.innerHTML = "&nbsp;- "+ankhEffects.getPreviewMsg(FAQQuestions[FAQIndex].Desc,70).msgWithDots;
	};
	
	moveFAQUp = function(){		
		FAQIndex = (FAQIndex + 1)%FAQQuestions.length;
		FAQtitle.innerHTML = FAQQuestions[FAQIndex].Title;
		FAQtitle.href = "FAQ.php?#"+FAQQuestions[FAQIndex].Anch;		
		FAQdescription.innerHTML = "&nbsp;- "+ankhEffects.getPreviewMsg(FAQQuestions[FAQIndex].Desc,70).msgWithDots;			
	};

	/**
	 * Purpose: Initialise terminating band
	 * @param {DateTime} windowStartDate - JSDate refers to the first Div, i.e. 40px from y-axis
	 */
	initTerminatingBand = function(windowStartDate){
		var today = new Date();		
		var maxTerminatingLeft = parseInt(timeWallHTML.style.width,10);		
		terminatingBand.setBandMinLeft(maxTerminatingLeft);		
		var terminatingStartDate = ankhDate.roundUpToFirstDay(today,granularity[zoomLevel].minorGridType,granularity[zoomLevel].minorGrid);
		var terminatingEndDates = ankhDate.addDaysFormat(terminatingStartDate,granularity[zoomLevel].minorGrid,granularity[zoomLevel].minorGridType);
		terminatingBand.setBandDates(terminatingStartDate,terminatingEndDates);	
		var left = (ankhDate.divNumBetweenDates(windowStartDate,terminatingStartDate,granularity[zoomLevel].minorGridType,granularity[zoomLevel].minorGrid) + 1)* gridWidth;	//+1 to include the current div	
		terminatingBand.getTerminatingBandHTML().style.left = left+"px";	
	};
	/* Scrolling buttons */
	manualScrollLeftEnd = function(){
		var distance;
		if(panel.isPanelOpen()){
			distance = gridWidth * Math.floor((timeWallWidth - panelWidth )/gridWidth * 3 / 4);
		}else{
			distance = gridWidth * Math.floor(timeWallWidth/gridWidth * 3 / 4);
		}
				
		animatedScrollRight(distance,btnScrollAnimationTravelTime,btnScrollIteration,updateMajorDisplay);
		panel.drawPanel();		
		EventUtil.getEvent().stopPropagation();
	};

	manualScrollRightEnd = function(){						
		var distance;
		if(panel.isPanelOpen()){
			distance = gridWidth * Math.floor((timeWallWidth - panelWidth )/gridWidth * 3 / 4);
		}else{
			distance = gridWidth * Math.floor(timeWallWidth/gridWidth * 3 / 4);
		}
		distance = - distance;				
		animatedScrollRight(distance,btnScrollAnimationTravelTime,btnScrollIteration,updateMajorDisplay);
		panel.drawPanel();		
		EventUtil.getEvent().stopPropagation();
	};

	/**
	 * Purpose: Initiate scrolling with animation
	 * @param {Int} distance - total distance to be moved
	 * @param {Int} travelTime - total travel time
	 * @param {Int} Iteration - number of morphing iteration 
	 * @param {Func} endFunc - function to call when animation is over
	 */
	animatedScrollRight = function(distance,travelTime,Iteration,endFunc){
		
		var currentTerminatingBandLeft = terminatingBand.getLeft();
		if (currentTerminatingBandLeft + distance < terminatingBand.getBandMinLeft()) { //i.e. terminating band appearing before 1 div before end of TimeWall
			distance = terminatingBand.getBandMinLeft() - currentTerminatingBandLeft;
		}						
		var kinematics = new Kinematics(distance/2,0,travelTime/2);
		kinematics.residual = 0;
		animatedMoveRight(0,kinematics,travelTime,Iteration,endFunc);
		that.divMaintenance(distance);
	};

	/**
	 * Purpose: Animation capability (Helper function for animatedScrollRight)
	 * @param {Int} count - current iteration number
	 * @param {Object} kinematics - kinematics object
	 * @param {Int} travelTime - total animation time
	 * @param {Int} Iteration - number of morphing iteration
	 * @param {Func} endFunc - function to call when animation is over
	 */
	animatedMoveRight = function(count,kinematics,travelTime,Iteration,endFunc){
		if(count == Iteration){	
			detailedBalloon.resetOverflow();
			summaryBalloon.resetOverflow();		
			if(endFunc){				
				endFunc();
			}
			return;
		}
		if(count == Iteration/2){
			kinematics.setAcceleration(-kinematics.getAcceleration());			
		}
	
		kinematics.getNext(travelTime/Iteration);
		kinematics.residual += kinematics.getDistance() - parseInt(kinematics.getDistance(),10);
		
		if (kinematics.residual <= -1) {
			moveRight(parseInt(kinematics.getDistance(),10) - parseInt(kinematics.residual,10));
			kinematics.residual -= parseInt(kinematics.residual,10);
		}else{
			moveRight(parseInt(kinematics.getDistance(),10));
		}
		window.setTimeout(function(){animatedMoveRight(count+1,kinematics,travelTime,Iteration,endFunc)},travelTime/Iteration);	
	};

	/**
	 * Purpose - Method to scroll the 35th div to the exact date. Balloon is been populated again under the following conditions: 
	 * 1. if the balloon has been closed 
	 * 2. if the user has requested to view another event
	 * @param {DateTime} newDate - date to scroll to
	 * @param {Int} eventId - event id to view
	 * @param {Int} ownerId - owner id of timewall
	 * @param {Int} ownerMood - event mood to display exact event in balloon
	 * @param {Int} picId - picture id to open
	 */
	this.scrollTo = function(eventDt,eventId,ownerId,ownerMood,picId,alwaysDisplay){		
		var detailedBalloonHTML = detailedBalloon.getDetailedBalloonHTML();				
		summaryBalloon.getSummaryBalloonHTML().style.visibility = "hidden";
		summaryBalloon.getSummaryBalloonHTML().style.display = "none";		
		var viewPos = getDetailedBubbleViewPosition();
		var roundDownDate = ankhDate.roundDownToFirstDay(eventDt, granularity[zoomLevel].minorGridType, granularity[zoomLevel].minorGrid);
		
		var anchorController = anchorgrid.getAnchorController();
		var viewPosDate = anchorController[viewPos].getStartDate();
			
		var numberOfDivs = ankhDate.divNumBetweenDates(roundDownDate, viewPosDate, granularity[zoomLevel].minorGridType, granularity[zoomLevel].minorGrid);				
		var distance = numberOfDivs * gridWidth;
		
		if (Math.abs(numberOfDivs) > 100) { //if more than 100 divs are required to move to the new location, then redraw the entire chart
			moveRight(distance);
			initDraw(eventDt,10)
		}else {			
			animatedScrollRight(distance, externalScrollAnimationTravelTime, externalScrollIteration);
		}
		var updatedViewPos = 0;
		for (var i = 0; i < anchorController.length; i++) {
			if (anchorController[i].getStartDate() - roundDownDate > 0) {
				break;
			}
			updatedViewPos = i;
		}				
		var newAnchorLeft = parseInt(anchorgrid.getAnchorHTML().style.left, 10);
		var grid = anchorController[updatedViewPos].getGridHTML();
		var gridX = parseInt(grid.style.left, 10);
		var eventImgY = moodPixel(ownerMood);
						
		if (detailedBalloon.getEventId() != eventId || detailedBalloonHTML.style.visibility == "hidden" || alwaysDisplay) {		
			
			summaryBalloon.initToDisplayDetailedBalloonDirect(ownerId, anchorController[updatedViewPos].getStartDate(), anchorController[updatedViewPos].getEndDate(), ownerMood, eventId, gridX, eventImgY, newAnchorLeft,panel.getPreviousFilterValue(),panel.getPreviousFilterType(),picId);
		}			
	};
	
	/**
	 * Purpose: Return the div index which is going to display the starting position of detailed balloon
	 */
	getDetailedBubbleViewPosition = function(){
		var spot = detailedBalloon.getBubbleWidth() ;	//position of the next bubble
		if(that.isPanelOpen()){
			spot += panelWidth;
		}
		var anchorController = anchorgrid.getAnchorController();
		var anchorGridHTMLLeft = parseInt(anchorgrid.getAnchorHTML().style.left,10);
		var pos = 0;		
		for (var i = 0; i < anchorController.length; i++) {			
			var gridLeft = parseInt(anchorController[i].getGridHTML().style.left,10);
			var overallLeft = anchorGridHTMLLeft + gridLeft;
			pos = i;
			if(overallLeft > spot){				
				break;
			}					
		}
		return pos;
	};
	
	
	/**
	 * Purpose : update major display
	 */
	updateMajorDisplay = function(){
		if (zoomLevel == 0 || zoomLevel == 3) {
			var anchorController = anchorgrid.getAnchorController();
			var anchorHTML = anchorgrid.getAnchorHTML();
			var index = 0;
			var comparater = 40;
			if(panel.isPanelOpen()){
				comparater += panelWidth;
			}
			for (var i = 1 ; i < gridNum; i++) {	//iterate from 1 to gridNum to find the 0px div and get its enddate to be displayed.			
				if (anchorController[i] != null) {				
					if (parseInt(anchorHTML.style.left, 10) + parseInt(anchorController[i].getGridHTML().style.left, 10) >= comparater) {
						index = i - 1;
						break;
					}
				}
			}
			var endDate = anchorController[index].getStartDate();						
			majorDisplayHTML.style.visibility = "visible";
			majorDisplayHTML.style.display = "block";
			if(zoomLevel == 0){
				majorDisplayText.innerHTML = ankhDate.getTranslatedMonth(endDate.getMonth()) + " " + endDate.getFullYear();
			}else{
				majorDisplayText.innerHTML = endDate.getFullYear();
			}
		}else{
			majorDisplayHTML.style.visibility = "hidden";
			majorDisplayHTML.style.display = "none";
		}
	};
	/**
	 * Purpose - To draw grid
	 * @param {DateTime} windowStartDate -  JSDate at 40px from y-axis
	 * @param {Object} frontNumDiv - number of front divs to draw ahead of windowStartDate
	 * @param {Object} backNumDiv - number of back divs to draw behind windowStartDate
	 */
	drawGrids = function(windowStartDate,frontNumDiv,backNumDiv){		
		var tempDate = windowStartDate;		
		var newDate = tempDate;
		var subtractedDate;		
		if (granularity[zoomLevel].minorGrid <= 0.5) {		//exception when minorGrid = 0.5, where we need to reduce the granularity level
			var inferredMinorGranularity;
			if(granularity[zoomLevel].minorGridType=="year"){
				inferredMinorGranularity = "month";
			}
			else if(granularity[zoomLevel].minorGridType=="month"){
				inferredMinorGranularity = "day";
			}
			for (var i = 0; i < frontNumDiv; i++) {
				subtractedDate = ankhDate.subtractDaysFormat(newDate, granularity[zoomLevel].minorGrid, granularity[zoomLevel].minorGridType);								
				var displayDate = ankhDate.parseDate(inferredMinorGranularity, subtractedDate);
				var gridObj = new Grid(subtractedDate, newDate, displayDate.grid, displayDate.major, granularity[zoomLevel].minorGridType);								
				anchorgrid.insertFrontChild(gridObj);
				newDate = subtractedDate;			
				
			}
			var newDate = tempDate;
			for (var i = 0; i < backNumDiv; i++) {
				var addedDate = ankhDate.addDaysFormat(newDate, granularity[zoomLevel].minorGrid, granularity[zoomLevel].minorGridType);
				var displayDate = ankhDate.parseDate(inferredMinorGranularity, newDate);
				var gridObj = new Grid(newDate, addedDate, displayDate.grid, displayDate.major, granularity[zoomLevel].minorGridType);				
				anchorgrid.insertBackChild(gridObj);
				newDate = addedDate;
			}
		}else {			
			for (var i = 0; i < frontNumDiv; i++) {
				subtractedDate = ankhDate.subtractDaysFormat(newDate, granularity[zoomLevel].minorGrid, granularity[zoomLevel].minorGridType);
				var displayDate = ankhDate.parseDate(granularity[zoomLevel].minorGridType, subtractedDate);
				var gridObj = new Grid(subtractedDate, newDate, displayDate.grid, displayDate.major, granularity[zoomLevel].minorGridType);
				anchorgrid.insertFrontChild(gridObj);				
				newDate = subtractedDate;
			}
			var newDate = tempDate;
			for (var i = 0; i < backNumDiv; i++) {
				var addedDate = ankhDate.addDaysFormat(newDate, granularity[zoomLevel].minorGrid, granularity[zoomLevel].minorGridType);
				var displayDate = ankhDate.parseDate(granularity[zoomLevel].minorGridType, newDate);
				var gridObj = new Grid(newDate, addedDate, displayDate.grid, displayDate.major, granularity[zoomLevel].minorGridType);
				anchorgrid.insertBackChild(gridObj);
				newDate = addedDate;
			}
		}						
		return subtractedDate;
	};	
	/**
	 * Purpose: Used to draw grouped events on the timewall within the exact grid. 
	 * @param {DateTime} chartFirstDate - first date of the chart; e.g. -24th div
	 * @param {Int} numOfInterval
	 */
	drawGroupedEvents = function(chartFirstDate,numOfInterval){
		displayLoadingImg();
		var intervalLength = granularity[zoomLevel].minorGrid;
		var intervalType = granularity[zoomLevel].minorGridType;		
		var chartFirstDate = ankhDate.formatMYSQLDate(chartFirstDate);
		var anchorController = anchorgrid.getAnchorController();		
		var anchorPointFromStartIndex = startingDiv + divIndexFromLatestEvent;	
		var panelWindowStartDiv = startingDiv + Math.floor(panelWidth/gridWidth);
		var panelWindowEndDiv = panelWindowStartDiv + Math.floor((timeWallWidth - panelWidth)/gridWidth) - 1;
		panelWindowStart = anchorController[panelWindowStartDiv].getStartDate();
		panelWindowEnd =  anchorController[panelWindowEndDiv].getEndDate();
		var nextWindowAnchorPoint = ankhDate.formatMYSQLDate(anchorController[anchorPointFromStartIndex].getStartDate());	//used by the next view of the timewall to appear the way it was being left
		var method ="getGroupedEvents";
		var ajaxParameter = {method:method,ownerId: ownerId,startDt:chartFirstDate,intervalLength:intervalLength,intervalType:intervalType,numOfInterval:numOfInterval,zoomLvl:zoomLevel,nextWindowAnchorPoint:nextWindowAnchorPoint,label:panel.getPreviousFilterValue(),type:panel.getPreviousFilterType(),pk:pk};
		new AnkhAjax(ajaxUrl,"get",ajaxParameter,drawGroupedEventsCompleted,loadingImg);	
	};
	/**
	 * Purpose: This is called when AJAX query to queryGroupedEvents.php is completed. Method populate the events.
	 * @param {Object} transport - response from AJAX query
	 */
	drawGroupedEventsCompleted = function(transport){			
		var result = transport.responseText.evalJSON(true); 			
		if (result.zoomLvl == zoomLevel && result.GroupedEvents.length != 0 && panel.getPreviousFilterValue() == result.label) {			
			var gridNum = 0;
			var anchorController = anchorgrid.getAnchorController();
			for (var i = 0; i < result.GroupedEvents.length; i++) {
				var resultStart = ankhDate.mysqlTimeStampToDate(result.GroupedEvents[i].startDt);
				var resultEnd = ankhDate.mysqlTimeStampToDate(result.GroupedEvents[i].endDt);								
				for (var j = gridNum; j < anchorController.length; j++) { //start from gridNum as first index iterate through the anchor controller to find the first grid that should be painted with groupedevents
					if (anchorController[j].getStartDate() >= resultStart) {
						gridNum = j;
						break;
					}
				}				
				
				if (anchorController[gridNum] != null) {									
					if (anchorController[gridNum].getStartDate() >= resultStart && anchorController[gridNum].getEndDate() <= resultEnd) {
						var groupedEvent = result.GroupedEvents[i];															
						var groupEvent = new GroupEvent(ownerId,groupedEvent, moodPixel(groupedEvent['mood']), summaryBalloon, moodTranslation, zoomLevel,displayToolTip,hideToolTip,result.label,result.type,that);									
						anchorController[gridNum].addGroupEvent(groupEvent);									
					}				
				}				
			}
		}		
		hideLoadingImg();
	};
	/**
	 * Display Timewall's Loading Image
	 */
	displayLoadingImg = function(){
		
		numOfAjaxLoads += 1;
		loadingImg.style.visibility = "visible";
		loadingImg.style.display = "block";
	};
	/**
	 * Hide Timewall's Loading Image
	 */
	hideLoadingImg = function(){
		numOfAjaxLoads -= 1;
		if (numOfAjaxLoads == 0) {		
			loadingImg.style.visibility = "hidden";
			loadingImg.style.display = "none";
		}
	};
	/**
	 * Purpose: Initialize TimeWall Zooming capability
	 */
	initZoom = function(){		
		zoomBar = new ZoomBar(zoomBarContainer,image['pic'],dragDropZoom,zoomLevel);
		EventUtil.addEventHandler(zoomInBtn,"mouseover",function x(){zoomBar.labelContainerVisible()});
		EventUtil.addEventHandler(zoomInBtn,"mouseout",function x(){zoomBar.labelContainerInvisible()});	
		EventUtil.addEventHandler(zoomOutBtn,"mouseover",function x(){zoomBar.labelContainerVisible()});
		EventUtil.addEventHandler(zoomOutBtn,"mouseout",function x(){zoomBar.labelContainerInvisible()});				
		EventUtil.addEventHandler(timeWallHTML, "click", activateZoom);
		
		EventUtil.addEventHandler(document.body, "mousemove", deactivateZoom);		
		EventUtil.addEventHandler(timeWallHTML, "mousewheel", zoom);	
	};
	/**
	 * Purpose: Drag and drop the zoom bar to zoom in/out
	 * @param {Int} zoomLvl
	 */
	dragDropZoom = function(zoomLvl){		
		zoomLevel = zoomLvl;
		var x;
		if(that.isPanelOpen){
			x = parseInt(timeWallHTML.style.width,10)/2 + 240/2;			//240 = width of panel			
		}else{
			x = parseInt(timeWallHTML.style.width,10)/2;			
		}
		var y = parseInt(timeWallHTML.style.height,10)/2;
		zoomAnimation.zoomIn(x,y);
		drawZoom(x);	
	};
	
	/**
	 * Purpose: Manual activation upon zooming in
	 */
	manualZoomInEnd = function(){
		if (zoomLevel > 0) {
			zoomLevel -= 1;			
			dragDropZoom(zoomLevel);			
			zoomBar.moveToStopPoint(zoomLevel);
		}	
	};
	/**
	 * Purpose: Manual activation upon zooming out
	 */
	manualZoomOutEnd = function(){
		if (zoomLevel < granularity.length - 1) {
			zoomLevel += 1;
			dragDropZoom(zoomLevel);
			zoomBar.moveToStopPoint(zoomLevel);
		}
	};
	/**
	 * Purpose: Activate mouse zoom feature
	 */
	activateZoom = function(){	
		if(Math.abs(zoomPreX - EventUtil.getEvent().pageX) <= 3){
			zoomActivated = true;
			zoomMsg.innerHTML = "Rotate your mouse wheel to zoom in or out.";
			timeWallHTML.style.border = "2px solid #5E6F61";
			EventUtil.getEvent().preventDefault();
		}
	};
	/**
	 * Purpose: Deactivate mouse zoom feature
	 */
	deactivateZoom = function(){
		if (zoomActivated) {			
			var absPosTimeWallPageX = AnkhUsefulMethods.findPosX(timeWallHTML);
			var absPosTimeWallPageY = AnkhUsefulMethods.findPosY(timeWallHTML);			
			var mousePageX = EventUtil.getEvent().pageX;
			var mousePageY = EventUtil.getEvent().pageY;			
			var timeWallWidth = parseInt(timeWallHTML.style.width, 10);
			var timeWallHeight = parseInt(timeWallHTML.style.height, 10);

			if (mousePageX < absPosTimeWallPageX || mousePageX > absPosTimeWallPageX + timeWallWidth ||
			mousePageY < absPosTimeWallPageY || mousePageY > absPosTimeWallPageY + timeWallHeight) {
				that.resetZoomActivate();
			}
		}
	};
	/**
	 * Purpose: Reset mouse zoom feature
	 */
	this.resetZoomActivate = function(){
		zoomActivated = false;
		zoomMsg.innerHTML = "";
		timeWallHTML.style.border = "2px solid #C1CCB5";
	};
	
	this.closePanel = function(){
		totalEventsDisplay.id = "TotalEventsDisplayClose";			
		timeWallLogo.id = "TimeWallLogoClose";
		scrollLeft.id = "ScrollLeftClose";
		scrollRight.id = "ScrollRightClose";
		zoomControls.id = "ZoomControlsClose";	
		zoomMsg.id = "ZoomMsgClose";		
		majorDisplayHTML.id = "MajorDisplayClose";
	};
	
	this.openPanel = function(){
		totalEventsDisplay.id = "TotalEventsDisplayOpen";			
		timeWallLogo.id = "TimeWallLogoOpen";
		scrollLeft.id = "ScrollLeftOpen";
		scrollRight.id = "ScrollRightOpen";
		zoomControls.id = "ZoomControlsOpen";	
		zoomMsg.id = "ZoomMsgOpen";		
		majorDisplayHTML.id = "MajorDisplayOpen";
	};
	
	/**
	 * Purpose: Detect Mouse movement and zoom in/out accordingly for different browsers
	 */
	zoom = function(){
		var delta = 0;		
		if (zoomActivated) {			
			if (isIE) {
				delta = -EventUtil.getEvent().wheelDelta / 120;
			}
			else 
				if (isKHTML) {
					delta = -EventUtil.getEvent().wheelDelta / 120;
				}
				else 
					if (isOpera) {
						delta = EventUtil.getEvent().wheelDelta / 120;
					}
					else { //for firefox
						delta = EventUtil.getEvent().detail / 3;
					}
			/** If delta is nonzero, handle it.
			 * Basically, delta is now positive if wheel was scrolled down,
			 * and negative, if wheel was scrolled up.
			 */
			var terminatingBandLeft = parseInt(terminatingBand.getTerminatingBandHTML().style.left, 10);
			if (delta) {
				var x = EventUtil.getEvent().relativeX;							
				var y = EventUtil.getEvent().relativeY;
				if (delta < 0) { //zooming in
					zoomIntoArea(x,y,true);
				}
				else { //zooming out
					zoomIntoArea(x,y,false);
				}						
			}		
			EventUtil.getEvent().preventDefault();
			return false;
		}					
	};
	
	zoomIntoArea = function(x,y,zoomIn){
		var terminatingBandLeft = parseInt(terminatingBand.getTerminatingBandHTML().style.left, 10);
		if(zoomIn){
			if ( zoomLevel > 0 && x < terminatingBandLeft) {		
				zoomLevel -= 1;
				if(zoomLevel < 0){
					zoomLevel = 0;
				}												
				zoomBar.moveToStopPoint(zoomLevel);
				zoomAnimation.zoomIn(x, y);
				drawZoom(x);
			}
		}else{
			if( zoomLevel < granularity.length - 1 && x < terminatingBandLeft) {
				zoomLevel += 1;						
				if(zoomLevel >= granularity.length - 1){
					zoomLevel = granularity.length - 1;
				}															
				zoomBar.moveToStopPoint(zoomLevel);
				zoomAnimation.zoomOut(x, y);
				drawZoom(x);
			}
		}
	};

	 /**
	  * Purpose: Draw the next level of timewall to centralised around the x-coordiantes
	  * @param {Int} x - coordinates of next reference point; i.e. current zoom x-coordinates
	  */
	drawZoom = function(x){
		hideToolTip();
		var timeWallWidth = AnkhUsefulMethods.getStyle(timeWallHTML,"Width");
		var nearestDiv = Math.floor(x/gridWidth);
		var anchorController = anchorgrid.getAnchorController();
		var previousDate = anchorController[startingDiv - 1 +nearestDiv].getStartDate();			//previous date of x coordinates. there is always startingDiv number of Divs incl the current one before this				
		var roundDownDay = ankhDate.roundDownToFirstDay(previousDate, granularity[zoomLevel].minorGridType,granularity[zoomLevel]['minorGrid']);		
		var newWindowStartDate = ankhDate.subtractManyDays((nearestDiv - 1),roundDownDay,  granularity[zoomLevel].minorGrid, granularity[zoomLevel].minorGridType);					
		initTerminatingBand(newWindowStartDate);
		
		if(terminatingBand.getLeft() < terminatingBand.getBandMinLeft()){	//exceed terminating band left limit		
			var difference = Math.ceil((terminatingBand.getBandMinLeft() - terminatingBand.getLeft())/gridWidth);			
			newWindowStartDate = ankhDate.subtractManyDays(difference,newWindowStartDate,  granularity[zoomLevel].minorGrid, granularity[zoomLevel].minorGridType);
			initTerminatingBand(newWindowStartDate);
		}		
				
		summaryBalloon.resetPosition();		
		detailedBalloon.resetPosition();
		drawEventsOnGrid(newWindowStartDate);				
		panel.drawPanel();
		updateMajorDisplay();				
	};
	
	/**
	 * Purpose - Scrolling features
	 */
	initScroll = function(){
		//Allow user to activate scrolling of timewall within itself only
		EventUtil.addEventHandler(timeWallContainer, "mousedown", handleScrollMouseDown);		
		//Allow user to scroll and set timewall even when out of timewall
		EventUtil.addEventHandler(document, "mousemove", handleScrollMouseMove);		
		EventUtil.addEventHandler(document, "mouseup", handleScrollMouseUp);
		gripMouseCursor(false); 
	};
	
	/**
	 * Purpose: This event handler is called on mouse down to start scrolling timewall 
	 */
	handleScrollMouseDown = function() {
		activated = true;
		timeWallMoving = false;
		preX = EventUtil.getEvent().pageX;
		zoomPreX = preX;
		gripMouseCursor(true); 		
		EventUtil.getEvent().preventDefault();	
		EventUtil.getEvent().stopPropagation();		
	};
	/**
	 * Purpose: Event Handler to scroll timewall when mouse is moving
	 */
	handleScrollMouseMove = function(){		
		if(activated){
			var currentX = EventUtil.getEvent().pageX;
			var movement = currentX - preX;
			if(currentX != 0 && preX != 0){
				preX = currentX;
				var currentTerminatingBandLeft = terminatingBand.getLeft();
				if (currentTerminatingBandLeft + movement < terminatingBand.getBandMinLeft()) {	//i.e. terminating band appearing before 1 div before end of TimeWall
					movement = terminatingBand.getBandMinLeft() - currentTerminatingBandLeft;
				}	
				cumulativeDistanceMoved += movement;				
				moveRight( movement);									
			}
			timeWallMoving = true;
			hideToolTip();
			updateMajorDisplay();
			EventUtil.getEvent().stopPropagation();
			EventUtil.getEvent().preventDefault();	
		}						
		
	};		
	/**
	 * Purpose - Move Anchor, Summary Balloon, Detailed Balloon & Terminating Band right by 'distance' amount
	 * @param {Int} distance - amount of incremental distance 
	 */
	moveRight = function(distance){				
		var newD = terminatingBand.setLeftAutoCorrection(terminatingBand.getLeft()+distance);
		if(newD != null){
			distance -= newD;			
		}		
		var summaryLeft = parseInt(summaryBalloon.getSummaryBalloonHTML().style.left,10) + distance;
		summaryBalloon.setLeft(summaryLeft);			
		var detailedLeft = parseInt(detailedBalloon.getDetailedBalloonHTML().style.left,10) + distance;
		detailedBalloon.setLeft(detailedLeft);
		var newAnchorLeft = parseInt(AnkhUsefulMethods.getStyle(anchorgrid.getAnchorHTML(),"Left"),10) + distance;
		anchorgrid.setLeft(newAnchorLeft);		
		if(backgrounds[selectedBackground]['scroll']){		
			var pos = timeWallBackground.style.backgroundPosition.split(" ");
			var newX = parseInt(pos[0],10) + distance +"px";
			var newY = pos[1];
			timeWallBackground.style.backgroundPosition = newX + " "+newY;
		}	
	};
	
	/**
	 * Purpose : Used by balloon to scroll right when balloon exceeds the y-axis
	 * @param {Int} distance 
	 */
	this.balloonScrollRight = function(distance){		
		var newAnchorLeft = parseInt(AnkhUsefulMethods.getStyle(anchorgrid.getAnchorHTML(),"Left"),10) + distance;
		anchorgrid.setLeft(newAnchorLeft);
		var newTerminatingLeft = parseInt(AnkhUsefulMethods.getStyle(terminatingBand.getTerminatingBandHTML(),"Left"),10) + distance;
		terminatingBand.setLeftAutoCorrection(newTerminatingLeft);
	};
	/**
	 * Purpose: On mouse up, start div maintenance based on cumulative distance moved
	 */
	handleScrollMouseUp = function(){
		if (activated) {
			preX = 0;
			gripMouseCursor(false);
			activated = false;				
			that.divMaintenance(cumulativeDistanceMoved);
			panel.drawPanel();
			cumulativeDistanceMoved = 0;
			summaryBalloon.resetOverflow();
			detailedBalloon.resetOverflow();
		}
		EventUtil.getEvent().stopPropagation();
		EventUtil.getEvent().preventDefault();			
	};		
	
	this.isTimeWallMoving = function(){
		return timeWallMoving;
	};
	
	/**
	 * Purpose: Update anchor controller when new divs need to be added or removed
	 * @param {Int} distance
	 */
	this.divMaintenance = function(distance){
		var anchorController = anchorgrid.getAnchorController();		
		var firstStart = anchorController[0].getStartDate();
		var lastEnd = anchorController[anchorController.length-1].getEndDate();
		var temp = distance/gridWidth;
		if((distance <= 0 && temp <= 0) || (distance >= 0 && temp >= 0)){
			numOfDivToBeAdded += temp;	
		}else{
			numOfDivToBeAdded = temp;
		}
			
		if(numOfDivToBeAdded<=-1){
			var numOfDivRequired = Math.abs(Math.ceil(numOfDivToBeAdded));		
			drawGrids(lastEnd,0,numOfDivRequired);			//append grid to anchor at the right
			numOfDivToBeAdded += numOfDivRequired;
			for(var i=0;i<numOfDivRequired;i++){
				anchorgrid.removeFrontChild();
			}
			drawGroupedEvents(lastEnd,numOfDivRequired);	//draw new required divs starting from last end date
			
		}else if(numOfDivToBeAdded >= 1){
			
			var numOfDivRequired = Math.abs(Math.floor(numOfDivToBeAdded));
			drawGrids(firstStart,numOfDivRequired,0);		//append grid to anchor at the left
			numOfDivToBeAdded -= numOfDivRequired;
			for(var i=0;i<numOfDivRequired;i++){
				anchorgrid.removeBackChild();
			}
			var newFirstStart = anchorController[0].getStartDate();
			drawGroupedEvents(newFirstStart,numOfDivRequired);		//draw new required divs starting from new start date
		}		
	};
	/**
	 * Purpose: Used to assign the grip mouse cursor
	 * @param {Boolean} grip - true to grip, false to not grip
	 */
	gripMouseCursor = function(grip){
		if(grip){
			timeWallHTML.style.cursor = "url('"+rootDir+"wallimage/cursor-closedhand.cur'),auto";				
		}else{
			timeWallHTML.style.cursor = "url('"+rootDir+"wallimage/cursor-openhand.cur'),auto";
		}
	};
	/**
	 * Purpose: Return pixel given mood
	 * @param {Int} mood 
	 */
	moodPixel = function(mood){
		var drawHeight = 450 - 70;		//450 = Lowest point of black, 70 = Highest point of red
		var minY = 70;
		return minY + drawHeight * (1 - mood/ moods);  		
	};
	/**
	 * Purpose: Return translated mood given mood index
	 * @param {Int} index
	 */
	this.getMoodsTranslation = function(index){
		return moodTranslation[index];
	};
	/**
	 * Purpose: Return the colour of the mood given its description
	 * @param {String} description
	 */
	this.getMoodColour = function(description){
		for(var i = 0; i < moodTranslation.length;i++){
			if(moodTranslation[i].Description == description){
				return moodTranslation[i].colour;
			}
		}
		return "";
	};
	
	this.getTimeWallContainerHeight = function(){
		return AnkhUsefulMethods.findPosY(timeWallContainer);
	};
	
	this.isPanelOpen = function(){
		return panel.isPanelOpen();
	};
	this.setFilterValue = function(value){
		panel.setFilterValue(value);
	}
	this.getTimeWallHeight = function(){
		return timeWallHeight;
	};
	this.getPanelWindowDates = function(){
		return {start:panelWindowStart,end:panelWindowEnd};
	};
	this.getBalloons = function(){
		return {summary:summaryBalloon,detailed:detailedBalloon};
	};
	
	/**
	 * Purpose: Display event tool tip
	 */
	displayToolTip = function(currentLeft,currentTop,mood,title,count,date, imgsrc){
		var toolTipContainer = document.createElement('div');
		toolTipContainer.style.fontSize = "12px";
		var headerTxt = document.createElement('span');
		toolTipContainer.appendChild(headerTxt);
		headerTxt.style.fontWeight = "bold";
		headerTxt.innerHTML = title;
		var dateTxt = document.createElement('span');
		dateTxt.style.fontStyle = "italic";
		dateTxt.innerHTML = "&nbsp;("+date+") ";
		toolTipContainer.appendChild(dateTxt);
		
		var remainingEvents = document.createElement('span');
		if(count == 1){
			remainingEvents.innerHTML = "and "+count+" other event.";
		}else if(count > 1){
			remainingEvents.innerHTML = "and "+count+" other events.";
		}
		toolTipContainer.appendChild(remainingEvents);
		var moodContainer = document.createElement('div');
		moodContainer.innerHTML = mood;
		toolTipContainer.appendChild(moodContainer);
		if(currentLeft < 480){			
			ankhToolTip.display(toolTipContainer,null,currentTop,currentLeft,true);
		}else{
			ankhToolTip.display(toolTipContainer,null,currentTop,currentLeft,false);
		}		
	};
	/**
	 * Purpose: Hide event tool tip
	 */
	hideToolTip = function(){
		ankhToolTip.hide();
	};
	
	init(latestEventDate);	
};
/**
 * Purpose - Create TimeWall Picture control - the picture below the timewall. It is able to move the time wall.
 * @param {Object} parent - parent HTML container
 * @param {String} picturePath - path to the image source; recommended to have absolute path
 * @param {String} originalPicturePath - path to the original image stored on myTimeWall
 * @param {Function} onMouseClick - event handler to display on mouseclick
 */
TimeWallPictureControl = function(parent,picturePath,originalPicturePath,date,eventId,eventTitle,ownerId,ownerMood,timeWall){
	
	var windowScrollTime = 500;		//500ms
	var totalBrowserMovementCount = 10;
	
	var container = document.createElement('div');	
	container.style.textAlign = "center";	
	container.style.cursor = "pointer";
	parent.appendChild(container);
	
	var timeWall = timeWall;
	var picture = document.createElement('img');
	picture.src = picturePath;
	picture.originalPic = originalPicturePath;
	picture.style.margin = "3px";
	picture.style.padding = "3px";
	picture.style.border = "1px solid #C1CCB5";
	container.appendChild(picture);
	
	var viewThisOnTimeWall = document.createElement('div');	
	viewThisOnTimeWall.innerHTML = eventTitle;
	viewThisOnTimeWall.style.color = "#819284";
	viewThisOnTimeWall.style.width = "140px";
	var ankhDate = new AnkhDate();
	viewThisOnTimeWall.date = date;
	viewThisOnTimeWall.eventId = eventId;
	viewThisOnTimeWall.ownerId = ownerId;
	viewThisOnTimeWall.ownerMood = ownerMood;
	
	container.appendChild(viewThisOnTimeWall);
	/**
	 * Purpose: Initialise event handlers for the picture control
	 */
	initEventHandler = function(){
		
		activate = function(){
			picture.style.border = "1px solid #5E6F61";
			viewThisOnTimeWall.style.color = "#5E6F61";
			viewThisOnTimeWall.style.textDecoration = "underline";
		};
		deactivate = function(){
			picture.style.border = "1px solid #C1CCB5";
			viewThisOnTimeWall.style.color = "#819284";
			viewThisOnTimeWall.style.textDecoration = "none";
		};
		EventUtil.addEventHandler(picture,"mouseover",activate);
		EventUtil.addEventHandler(picture,"mouseout",deactivate);
		EventUtil.addEventHandler(picture,"click",scrollTimeWall);		
		EventUtil.addEventHandler(viewThisOnTimeWall,"mouseover",activate);
		EventUtil.addEventHandler(viewThisOnTimeWall,"mouseout",deactivate);
		EventUtil.addEventHandler(viewThisOnTimeWall,"click",scrollTimeWall);
	};
	
	/**
	 * Purpose: Used to scroll Time Wall
	 */
	scrollTimeWall = function(){	
		timeWall.setFilterValue("Show All");
		timeWall.scrollTo(viewThisOnTimeWall.date,viewThisOnTimeWall.eventId,viewThisOnTimeWall.ownerId,viewThisOnTimeWall.ownerMood);
		var scrollTop;
		if(isChrome || isSafari){
			scrollTop = document.body.scrollTop;
		}else{
			scrollTop = document.documentElement.scrollTop;
		}
		var totalDistance = timeWall.getTimeWallContainerHeight() -  scrollTop;
		var kinematics = new Kinematics(totalDistance/2,0,windowScrollTime/2);
		moveBrowserWindow(kinematics,0);
	};
	
	/**
	 * Purpose - Scroll brower window with acceleration and deeceleration
	 * @param {Object} kinematics - kinematics object
	 * @param {Object} count - current number of iteration
	 */
	moveBrowserWindow = function(kinematics,count){
		if(count == totalBrowserMovementCount){
			return;
		}
		if(count == totalBrowserMovementCount/2){
			kinematics.setAcceleration(-kinematics.getAcceleration());			
		}
		kinematics.getNext(windowScrollTime/totalBrowserMovementCount);
		var distance = kinematics.getDistance();
		if (isChrome || isSafari) {
			document.body.scrollTop = document.body.scrollTop + distance;
		}else{
			document.documentElement.scrollTop = document.documentElement.scrollTop + distance;
		}
		window.setTimeout(function x(){
			moveBrowserWindow(kinematics, count + 1)
		},windowScrollTime/totalBrowserMovementCount);		
	};
	
	
	initEventHandler();
};
/*
 * Purpose: Zoom Animation object
 */
ZoomAnimation = function(rootDir){
	var zoomAnimationImgList = new Object();
	if (isIE && !isMinIE7) {
		zoomAnimationImgList['Zoom In'] = rootDir + "wallimage/zoom/zoom in_enlarge8.png";
		zoomAnimationImgList['Zoom Out'] = rootDir + "wallimage/zoom/zoom out_minimise8_new.gif";
	}else{
		zoomAnimationImgList['Zoom In'] = rootDir + "wallimage/zoom/zoom in_enlarge.png";
		zoomAnimationImgList['Zoom Out'] = rootDir + "wallimage/zoom/zoom out_minimise.png";
	}
	
	for(var i in zoomAnimationImgList){
		var tempImg = new Image();
		tempImg.src = zoomAnimationImgList[i];
	}
	
	//morphing attributes
	var morphingAnimation = 10;				//number of iterations
	var morphingTotalTime = 500;			//500 ms
	
	var dimensionInit = false;
	var originalWidth;
	var originalHeight;
	
	var cursorHeightOffset = 8;
	var cursorWidthOffset = 8;

	//HTML
	
	var container = document.createElement('div');
	container.id = "ZoomAnimation";	
	container.style.display = "none";			//IE6 will not display zoom animation because it is too ugly. Temporary measure.
	
	var img = document.createElement('img');
	img.src = zoomAnimationImgList['Zoom In'];
	img.src = zoomAnimationImgList['Zoom Out'];
	container.appendChild(img);
	
	this.getAnimationHMTML = function(){		
		return container;	
	};
	
	/*
	 * Purpose - Display the location of the zoom out animation cursor
	 * Inputs:
	 * x - center of the zoom image (x coordinates)
	 * y - center of the zoom image (y coordinates)
	 */
	this.zoomOut= function(x,y){
		
		img.src = zoomAnimationImgList['Zoom Out'];
		displayImg();
		container.style.left = x - img.width/2 + cursorWidthOffset + "px";
		container.style.top = y - img.height/2 + cursorHeightOffset + "px";
			
		var widthDifference = img.width/2;
		var heightDifference = img.height/2;
		var leftDifference = widthDifference/2;
		var topDifference = heightDifference/2;
		
		var widthKinematics = new Kinematics(widthDifference/2,0,morphingTotalTime/2);
		var heightKinematics = new Kinematics(heightDifference/2,0,morphingTotalTime/2);
		var leftKinematics = new Kinematics(leftDifference/2,0,morphingTotalTime/2);
		var topKinematics = new Kinematics(topDifference/2,0,morphingTotalTime/2);
		
		morphAnimated(0,widthKinematics,heightKinematics,leftKinematics,topKinematics)
	};
	
	/*
	 * Purpose - Display the location of the zoom in animation cursor
	 * Inputs:
	 * x - center of the zoom image (x coordinates)
	 * y - center of the zoom image (y coordinates)
	 */
	this.zoomIn = function(x,y){
		img.src = zoomAnimationImgList['Zoom In'];
		displayImg();
		container.style.left = x - img.width/4 + cursorWidthOffset + "px";
		container.style.top = y - img.height/4 + cursorHeightOffset + "px";
		
		var widthDifference = img.width/2;
		var heightDifference = img.height/2;
		var leftDifference = widthDifference/2;
		var topDifference = heightDifference/2;
		
		img.height = originalHeight/2;
		img.width = originalWidth/2;					
		
		var widthKinematics = new Kinematics(-widthDifference/2,0,morphingTotalTime/2);
		var heightKinematics = new Kinematics(-heightDifference/2,0,morphingTotalTime/2);
		var leftKinematics = new Kinematics(-leftDifference/2,0,morphingTotalTime/2);
		var topKinematics = new Kinematics(-topDifference/2,0,morphingTotalTime/2);
		
		morphAnimated(0,widthKinematics,heightKinematics,leftKinematics,topKinematics)
	};
	
	morphAnimated = function(count,widthKinematics,heightKinematics,leftKinematics,topKinematics){
		if(count == morphingAnimation){			
			resetImg();
			return;
		}
		if(count == morphingAnimation/2){	
			widthKinematics.setAcceleration(- widthKinematics.getAcceleration());		
			heightKinematics.setAcceleration(- heightKinematics.getAcceleration());		
			leftKinematics.setAcceleration(- leftKinematics.getAcceleration());		
			topKinematics.setAcceleration(- topKinematics.getAcceleration());			
		}
		
		widthKinematics.getNext(morphingTotalTime/morphingAnimation);
		heightKinematics.getNext(morphingTotalTime/morphingAnimation);
		leftKinematics.getNext(morphingTotalTime/morphingAnimation);
		topKinematics.getNext(morphingTotalTime/morphingAnimation);
		
		container.style.left = parseInt(container.style.left,10)+leftKinematics.getDistance() + "px";		
		container.style.top = parseInt(container.style.top,10)+topKinematics.getDistance() + "px";
		img.width = img.width - widthKinematics.getDistance(),10;		
		img.height = img.height - heightKinematics.getDistance(),10;
		
		window.setTimeout(function(){
			morphAnimated(count + 1, widthKinematics,heightKinematics,leftKinematics,topKinematics);
		},morphingTotalTime/morphingAnimation);
	};
	
	
	/*
	 * Purpose: Reset img back to its original width and height and visibility attributes
	 */
	resetImg = function(){
		container.style.visibility = "hidden";
		container.style.display = "none";
		img.width = originalWidth;
		img.height = originalHeight;	
	};
	
	/*
	 * Purpose: Display the animation image at the right location and set the original width and height
	 */
	displayImg = function(){		
		if(!isIE || isMinIE7){						// do not show the zoom animation for IE6
			container.style.visibility = "visible";
			container.style.display = "block";		
			if(!dimensionInit){
				originalHeight = img.height;
				originalWidth = img.width;
				dimensionInit = true;			
			}
		}
	};
};
ZoomBar = function(parent,generalPicFilePath,dropHandler,zoomLvl){
	var that = this;
	
	var definePoints = new Array(21,42,63,84,105,126);
	var stopPoints = new Array();
	var threshold = 8;		
	var stopPointsLabel = new Array("1 month","6 months","1 year","2 years","10 years","20 years");
	for(var i = 0 ;i < definePoints.length;i++){
		stopPoints[i] = definePoints[i] - 8;			//8 = ceil of 15/2. 15=> height of zoom mover
	}
	var movingUp = false;
	var oldTop;
	
	var container = document.createElement('div');
	parent.appendChild(container);
	var zoomBar = new AnkhSprite(generalPicFilePath,10,146,{x:80,y:0});			//6 is the real size but 10 is put so that more user can mouse over it easier
	zoomBar.style.marginLeft = "4px";
	container.appendChild(zoomBar);
		
	var zoomMover = new AnkhSprite(generalPicFilePath,15,15,{x:44,y:197});
	zoomMover.style.position = "absolute";
	zoomMover.style.left = "0px";
	container.appendChild(zoomMover);
	
	var labelContainer = document.createElement('div');
	labelContainer.style.position = "absolute";
	labelContainer.style.left = "15px";
	labelContainer.style.visibility = "hidden";
	container.appendChild(labelContainer);
	for(var i = 0;i < stopPoints.length;i++){
		var label = document.createElement('div');
		label.style.position = "absolute";
		label.style.top = stopPoints[i]+"px";
		label.style.width = "60px";
		label.style.color = "#5E6F61";
		label.innerHTML = stopPointsLabel[i];
		labelContainer.appendChild(label);
	}
	
	var effects = new AnkhEffects();	
	var zoomId = 0;
	
	var destination;
	var dropHandler = dropHandler;
	
	init = function(){
		var drag = new AnkhDrag(zoomMover, true, false, null, null, that.limitY,null,null,null,that.setPositionY);
		var initialLvl = zoomLvl;
		that.setStopPoint(initialLvl);
		EventUtil.addEventHandler(container,"mouseover",function x(){labelContainer.style.visibility = "visible";});
		EventUtil.addEventHandler(container,"mouseout",function x(){labelContainer.style.visibility = "hidden";});
		EventUtil.addEventHandler(zoomBar,"click",moveToPosition);
		EventUtil.addEventHandler(zoomBar,"mousedown",function x(){EventUtil.getEvent().stopPropagation();});
		EventUtil.addEventHandler(zoomBar,"click",function x(){EventUtil.getEvent().stopPropagation();});
		EventUtil.addEventHandler(container,"click",function x(){EventUtil.getEvent().stopPropagation();});
	};
	
	moveToPosition = function(){
		var posY = EventUtil.getEvent().pageY - AnkhUsefulMethods.findPosY(container);		
		var max = 1000;
		var index = 0;
		
		for(var i = 0;i < definePoints.length; i++){
			if(Math.abs(definePoints[i] - posY) < max){
				max = Math.abs(definePoints[i] - posY);
				index = i;
			}else{
				break;
			}
		}		
		if(stopPoints[index] != oldTop){
			that.moveToStopPoint(index);
			if(dropHandler){			
				dropHandler(index);
			}
			oldTop = stopPoints[index];
		}				
	};
	
	/*Used for the manually moving of zoom mover */
	
	this.limitY = function(eventObj,currentY,prevY){			
		var height = 15;
		var barHeight = 123;
		var posY = AnkhUsefulMethods.findPosY(container);
		var relativeCurY = currentY - posY;
		if(prevY < currentY){
			movingUp = false;
		}else{
			movingUp = true;
		}
		if(relativeCurY < 0 || relativeCurY > barHeight - height){
			return false;
		}
		return true;
	};
		
	this.setPositionY = function(eventObj,currentY){
		var posY = AnkhUsefulMethods.findPosY(container);
		var relativeCurY = currentY - posY;
		var zoomLvl;
		var newTop;
		if (movingUp) {
			for (var i = stopPoints.length - 1; i >= 0 ; i--) {	
				if(i == 0){
					newTop = stopPoints[0];
					zoomLvl  = i;
				}		
				else if (relativeCurY >= stopPoints[i] - threshold) {
					newTop = stopPoints[i];
					zoomLvl  = i;
					break;
				}
			}
		}else{
			for (var i = 0; i < stopPoints.length; i++) {
				if(i == stopPoints.length - 1){
					newTop = stopPoints[stopPoints.length - 1];
					zoomLvl  = i;
				}			
				else if (relativeCurY <= stopPoints[i] + threshold) {
					newTop = stopPoints[i];
					zoomLvl  = i;
					break;
				}
			}
		}	
		zoomMover.style.top = newTop + "px";
		if(newTop != oldTop){			
			if(dropHandler){			
				dropHandler(zoomLvl);
			}
		}		
		oldTop = newTop;
	};
	/* Used for mousewheel to move zoom mover */
	
	this.moveToStopPoint = function(index){		
		destination = stopPoints[index];	
		zoomMover.destination = destination;
		effects.moveUpDown(10,zoomMover,100,stopPoints[0],stopPoints[stopPoints.length - 1],handleFinalDestination);		
	};
	handleFinalDestination = function(){		
		zoomMover.style.top = destination +"px";
	};
	this.setStopPoint = function(index){
		zoomMover.style.top = stopPoints[index]+"px";
		oldTop = stopPoints[index];
	};
	
	this.labelContainerVisible = function(){
		labelContainer.style.visibility = "visible";
	};
	this.labelContainerInvisible = function(){
		labelContainer.style.visibility = "hidden";
	};
	init();
	
};
/**
 * Purpose: Detailed Balloon object; includes header and content container. Does not include content as
 * content is provided by EventObject
 * @param {Object} timeWall
 */
DetailedBalloon = function(timeWall,rootDir,isPublic,balloonIcons,pointerIcon,viewerIsOwner,isGroup,isMember,ownerId,pk){	
	var that = this;
	var images = new Object();
	if (isIE && !isMinIE7) { //if < than IE7
		images['Bubble Bg'] = rootDir+"wallimage/balloon/big_bubble_bgv2_8.png";
	}else {
		images['Bubble Bg'] = rootDir+"wallimage/balloon/big_bubble_bgv2.png";
	}
	for(var i in images){
		var img = new Image();
		img.src = images[i];
	}
	
	var eventId;					//Store the event Id of the currently displayed event
	var eventObj;
	
	//Detailed Balloon consists of bubble and pointer
	var bubbleWidth = 621;
	var bubbleHeight = 480;			//490
	var top = 5;					//default y-coordinates 5
	
	var pointerWidth = 12;
	
	var totalMorphingTime = 200;
	var morphIteration = 10;
	
	//Detailed Balloon with Shadow, i.e. image size
	var bubbleCanvasWidth = 630;
	var bubbleCanvasHeight = 493;
	
	var shadowWidthOffset = 1; 		//used to offset the contraction of the balloon shadow
	
	var timeWall = timeWall;
	var summaryBalloon;
		
	var detailedBalloonHTML = document.createElement('div');
	detailedBalloonHTML.id = "DetailedBalloon";
	detailedBalloonHTML.style.width = bubbleWidth+pointerWidth+"px";	
	detailedBalloonHTML.style.left = "0px";	

	//Background images
	var bubbleImg = document.createElement('img');
	bubbleImg.src = images['Bubble Bg'];
	bubbleImg.className = "balloonBackground";
	var pointerImg = new AnkhSprite(pointerIcon,12,26,{x:0,y:43});
	pointerImg.className = "balloonPointer";	
	pointerImg.style.right = "0px";
	pointerImg.style.top = "40px";		
	detailedBalloonHTML.appendChild(bubbleImg);
	detailedBalloonHTML.appendChild(pointerImg);
	
	//Detailed Balloon Content
	var detailedBalloonContent = document.createElement('div');
	detailedBalloonContent.id = "DetailedBalloonContent";

	//Detailed Balloon Top Buttons
	var closeBtn = new AnkhSprite(balloonIcons,17,18,{x:0,y:216},{x:17,y:216},{x:17,y:216});
	closeBtn.className = "Buttons";
	
	var minBtn = new AnkhSprite(balloonIcons,14,10,{x:0,y:266},{x:17,y:266},{x:17,y:266});
	minBtn.className = "Buttons";
		
	//Detailed Balloon Top Options
	var eventOptions = document.createElement('div');
	eventOptions.id = "EventOptions";
	
	var addParticipants = new AnkhLink("add others",null,null,"");
	addParticipants.style.visibility = "hidden";
	addParticipants.style.display = "none";
	var editEvent = new AnkhLink("edit event",null,null,"");
	editEvent.style.visibility = "hidden";
	editEvent.style.display = "none";
	editEvent.style.marginRight = "5px";	
	var addMe = new AnkhLink("add me",null,"");
	addMe.style.visibility = "hidden";
	addMe.style.display = "none";
	var addMePopup = new GreenPopup("SupportControls/Popup/",450,"Add this event onto your TimeWall?","Confirm","button","Cancel",null,"Okay");
	var requestEventAjaxLoader = new AnkhAJAXLoader("");
	requestEventAjaxLoader.style.visibility = "hidden";
		
	eventOptions.appendChild(addParticipants);	
	eventOptions.appendChild(editEvent);
	eventOptions.appendChild(addMe);
			
	//Mood Icon
	var moodIcon = document.createElement('div');
	moodIcon.style.cssFloat = "left";
	moodIcon.style.styleFloat = "left";
	
	//Previous and Next Buttons
	var prevBtn = new AnkhSprite(balloonIcons,16,16,{x:0,y:234},{x:17,y:234},{x:17,y:234});
	prevBtn.id = "PrevBtn";
	prevBtn.alt = "Previous Event";
	
	var nextBtn = new AnkhSprite(balloonIcons,16,16,{x:0,y:250},{x:17,y:250},{x:17,y:250});
	nextBtn.id = "NextBtn";
	nextBtn.alt = "Next Event";
	
	var prevNextBtnContainer = document.createElement('div');
	prevNextBtnContainer.id = "PrevNextBtnContainer";
	
	//Detailed Balloon Header
	var detailedBalloonHeader = document.createElement('div');
	detailedBalloonHeader.id = "DetailedBalloonHeader";
	
	var headerTblStructure  = new GenericTable(2,1);
	headerTblStructure.Table.cellPadding = 0;
	headerTblStructure.Table.cellSpacing = 0;
	
	var eventTitle = document.createElement('span');
	eventTitle.id = "EventTitle";	
	headerTblStructure.getCell(0,0).style.paddingLeft = "10px";
	headerTblStructure.insertIntoCell(0,0,eventTitle);
	
	
	var eventMood = document.createElement('span');
	headerTblStructure.insertIntoCell(1,0,eventMood);	
	var eventDateRange = document.createElement('span');
	headerTblStructure.insertIntoCell(1,0,eventDateRange);
	var editDate = document.createElement('span');
	editDate.id = "EditDate";
	headerTblStructure.insertIntoCell(1,0,editDate);
		
	var privacy = document.createElement('span');
	privacy.id = "Privacy";		
	
	headerTblStructure.getCell(1,0).style.paddingLeft = "10px";
	
	detailedBalloonContent.appendChild(detailedBalloonHeader);
	
	var detailedBalloonMainDiv = document.createElement('div');	
	detailedBalloonMainDiv.id = "DetailedBalloonMainDiv";
	detailedBalloonContent.appendChild(detailedBalloonMainDiv);
	detailedBalloonHTML.appendChild(detailedBalloonContent);
	var detailedBalloonHeaderHR = document.createElement('hr');
	detailedBalloonHeaderHR.style.backgroundColor = "#5E6F61";
	
	var ajaxLoadingIcon;	
	/**
	 * Purpose: Initialise events at the end of this object.
	 */
	init = function(){
		
		prevNextBtnContainer.appendChild(privacy);		
		prevNextBtnContainer.appendChild(prevBtn);
		prevNextBtnContainer.appendChild(nextBtn);
			
		detailedBalloonHeader.appendChild(closeBtn);
		detailedBalloonHeader.appendChild(minBtn);
		detailedBalloonHeader.appendChild(eventOptions);
		detailedBalloonHeader.appendChild(moodIcon);		
		detailedBalloonHeader.appendChild(prevNextBtnContainer);
		detailedBalloonHeader.appendChild(headerTblStructure.Table);
		detailedBalloonHeader.appendChild(detailedBalloonHeaderHR);
		
		addMePopup.setConfirmBtnMouseup(function (){submitRequestForEvent(eventId);},"click");	
		EventUtil.addEventHandler(minBtn,"click",morphToSummaryBalloon);
		EventUtil.addEventHandler(closeBtn,"click",closeBalloon);
		EventUtil.addEventHandler(prevBtn,"click",getPreviousEvent);
		EventUtil.addEventHandler(nextBtn,"click",getNextEvent);				
		EventUtil.addEventHandler(detailedBalloonHTML, "mousedown", function x(){EventUtil.getEvent().stopPropagation();});		
		EventUtil.addEventHandler(detailedBalloonHTML, "click", function x(){EventUtil.getEvent().stopPropagation();}); 		//prevents IE from moving the timewall when mouse down				
		EventUtil.addEventHandler(detailedBalloonHTML, "mousewheel", detailedBalloonScroll);
	};
	
	this.getDetailedBalloonHTML = function(){
		return detailedBalloonHTML;
	};
	
	this.setParticipant = function(isParticipant){		
		if (!isPublic) {
			if (isParticipant) {
				addParticipants.style.visibility = "visible";
				addParticipants.style.display = "block";
				editEvent.style.visibility = "visible";
				editEvent.style.display = "block";												
				privacy.style.visibility = "visible";
			}
			else {				
				privacy.style.visibility = "hidden";
				addParticipants.style.visibility = "hidden";
				addParticipants.style.display = "none";
				editEvent.style.visibility = "hidden";
				editEvent.style.display = "none";											
				if((isGroup && isMember) ||!isGroup){			//do not display add me link when it is not a member of a group
					addMe.style.visibility = "visible";
					addMe.style.display = "block";
				}
			}
		}else if(!isGroup){
			addMe.style.visibility = "visible";
			addMe.style.display = "block";
		}
	};
	
	/**
	 * Purpose: Draw the detailed balloon
	 * @param {int} containerLeft - left coordinates of the container
	 * @param {int} pointerLeft - left coordinates of the pointer
	 * @param {int} pointerTop - top coordinates of the pointer
	 */
	this.draw = function(containerLeft,pointerTop){
		
		AnkhUsefulMethods.removeAll(detailedBalloonMainDiv);
		ajaxLoadingIcon = new AnkhAJAXLoader("");
		ajaxLoadingIcon.style.position = "relative";
		ajaxLoadingIcon.style.top = "150px";
		ajaxLoadingIcon.style.left = "300px";
		detailedBalloonMainDiv.appendChild(ajaxLoadingIcon);
		moodIcon.style.visibility = "hidden";
		moodIcon.style.display = "none";
		addParticipants.style.visibility = "hidden";	
		editEvent.style.visibility = "hidden";		
		detailedBalloonContent.style.visibility = "visible";
		detailedBalloonContent.style.display = "block";
		
		detailedBalloonHTML.style.left = containerLeft  + "px";	
		detailedBalloonHTML.style.top = top+"px";
		detailedBalloonHTML.style.visibility = "visible";
		detailedBalloonHTML.style.display = "block";	
		detailedBalloonHTML.style.width = bubbleWidth+pointerWidth + "px";
		
		//pointerImg.style.left = pointerLeft +"px";
		pointerImg.style.top = pointerTop +"px";
		
		bubbleImg.width = bubbleCanvasWidth;
		bubbleImg.height = bubbleCanvasHeight;
		eventTitle.innerHTML = "Getting information ... ";
		eventMood.innerHTML = "";
		editDate.innerHTML = "";		
		privacy.innerHTML = "";
		
		eventDateRange.innerHTML = "";		
		prevBtn.style.visibility = "hidden";
		nextBtn.style.visibility = "hidden";		
		addMe.style.visibility = "hidden";
		addMe.style.display = "none";
		timeWall.resetZoomActivate();
	};
	
	displayPopup = function(ownerName,title,eventPicUrl){				
		var content = addMePopup.getContent();
		AnkhUsefulMethods.removeAll(content);		
		var contentTbl = new GenericTable(1,2);
		contentTbl.TBody.childNodes[0].vAlign = "top";
		content.appendChild(contentTbl.Table);
		var eventPic = new FriendControl(eventPicUrl);
		contentTbl.insertIntoCell(0,0,eventPic);
		var sentence = document.createElement('div');
		if(isMember){
			sentence.innerHTML = "Add <b>"+title+"</b> onto your personal TimeWall?"
		}else{
			sentence.innerHTML = "<b>"+ownerName+"</b> has to confirm that you participated in <b>"+title+"</b>."
		}		
		contentTbl.insertIntoCell(0,1,sentence);
		contentTbl.insertIntoCell(0,1,requestEventAjaxLoader);
		addMePopup.showInCenterofBrowser();
		
		submitRequestForEvent = function(eventId){
			var ajaxUrl = "php/request_for_event.php";								
			var parameterObj = {eventId:eventId,ownerId:ownerId,isGroup:isGroup,pk:pk};
			requestEventAjaxLoader.style.visibility = "visible";
			new AnkhAjax(ajaxUrl,"post",parameterObj,submitRequestForEventSuccess,requestEventAjaxLoader);
		};
		
		submitRequestForEventSuccess = function(transport){					
			requestEventAjaxLoader.style.visibility = "hidden";		
			if(isMember){
				var sentenceParts = new Array();
				sentenceParts[0] = "Your request has been approved. Click ";
				sentenceParts[1] = new AnkhLink("here",null,"Request.php");
				sentenceParts[2] = "&nbsp;to finalise this event on your TimeWall.";
				sentence.innerHTML = ""; 
				sentence.appendChild(new AnkhDivBuilder(sentenceParts));				
			}else{
				sentence.innerHTML = "Your request has been sent.";
			}		
			addMePopup.showSecondPage();
		};						
	};
			
	/**
	 * Purpose: To load event object into detailed balloon
	 * @param {Object} eventObject - current event object to be displayed
	 */
	this.loadEventObject = function(eventObject){
		eventObj = eventObject;
		//Setting the present information	
		ajaxLoadingIcon.style.visibility = "hidden";
		ajaxLoadingIcon.style.display = "none";							
		addParticipants.style.visibility = "hidden";	
		editEvent.style.visibility = "hidden";		
		eventId = eventObject.getEventId();
		editEvent.href = "EditEventDetails.php?eId="+eventId+"&editEvent";
		addParticipants.href = "EditEventParticipants.php?eId="+eventId+"&addParticipant";		
		displayPrevNextBtns(eventObject);		
		if(isPublic && !isGroup){										
			addMe.href = "Signup.php?addMe="+eventId+"&owner="+ownerId;			
		}else{
			EventUtil.addEventHandler(addMe,"click",function (){displayPopup(eventObject.getOwnerName(),eventObject.getUserTitle(),eventObject.getEventPic());});			
		}
		
		eventTitle.innerHTML = eventObject.getUserTitle();
		var ankhDate = new AnkhDate();
		
		if(eventObject.getEventEndDt() - eventObject.getEventStartDt() == 0){		//if event lies within the same date, then only display one date
			eventDateRange.innerHTML = ", "+ankhDate.getDMY(eventObject.getEventStartDt()," ");
		}else{
			eventDateRange.innerHTML = ", "+ankhDate.getDMY(eventObject.getEventStartDt()," ")+" - "+ ankhDate.getDMY(eventObject.getEventEndDt()," ");
		}
		
		var iconCoordinate = timeWall.getMoodsTranslation(eventObject.getBalloonMood()).Image1;
		AnkhUsefulMethods.removeAll(moodIcon);
		var icon = new AnkhSprite(iconCoordinate['img'],iconCoordinate['width'],iconCoordinate['height'],iconCoordinate['normSrc']);
		moodIcon.appendChild(icon);		
		moodIcon.style.visibility = "visible";
		moodIcon.style.display = "block";
		eventMood.innerHTML = timeWall.getMoodsTranslation(eventObject.getBalloonMood()).Description;
		eventMood.style.color = timeWall.getMoodsTranslation(eventObject.getBalloonMood()).colour;		
		editDate.innerHTML = "edited "+ankhDate.compareWithToday(eventObject.getUserLastUpdateDt(),eventObject.getTodayDate());
		if(viewerIsOwner){
			privacy.innerHTML = "Viewable by "+eventObject.getPrivacy();
			privacy.style.visibility = "hidden";
		}
		var detailEventHTML = eventObject.getDetailedEventHTML();
		AnkhUsefulMethods.removeAll(detailedBalloonMainDiv);
		detailedBalloonMainDiv.appendChild(detailEventHTML);		
		that.resetOverflow();	
	} ;

	/**
	 * Purpose: Display Previous and Next Buttons when appropriate
	 * @param {Object} eventObject
	 */
	displayPrevNextBtns = function(eventObject){
		prevBtn.style.visibility = "visible";
		nextBtn.style.visibility = "visible";				
		
		var events = summaryBalloon.getEvents();
		for (var i = 0; i < events.length; i++) {
			if(events[i].getEventId() == eventId){
				if(i == 0){
					prevBtn.style.visibility = "hidden";
				}
				if(i== events.length - 1){
					nextBtn.style.visibility = "hidden";
				}
			}
		}	
	};
	/**
	 * Purpose: Get Next Event
	 */
	getNextEvent = function(){
		var events = summaryBalloon.getEvents();
		for(var i = 0;i<events.length-1;i++){		
			if(events[i].getEventId() == eventId){
				that.loadEventObject(events[i+1]);	
				summaryBalloon.setCurrentNavigationPage(i+1 +1);			
				break;
			}
		}
		EventUtil.getEvent().stopPropagation();
	};
	/**
	 * Purpose: Get Previous Event
	 */
	getPreviousEvent = function(){
		var events = summaryBalloon.getEvents();
		for(var i = 1;i<events.length;i++){		
			if(events[i].getEventId() == eventId){
				that.loadEventObject(events[i-1]);
				summaryBalloon.setCurrentNavigationPage(i-1 +1);				
				break;
			}
		}
		EventUtil.getEvent().stopPropagation();
	};
	

	/**
	 * Purpose: Assign summary balloon to Detailed balloon
	 * @param {Object} obj
	 */
	this.setSummaryBalloon = function(obj){
		summaryBalloon = obj;
	};
	
	/**
	 * Purposes: closes detailed balloon
	 */
	closeBalloon = function(){
		detailedBalloonHTML.style.visibility = "hidden";
		detailedBalloonHTML.style.display = "none";
		EventUtil.getEvent().stopPropagation();
	};
	
	/**
	 * Purpose: Starter function to morph detailed to summary balloon
	 */
	morphToSummaryBalloon = function(){
		var summaryBalloonHTML = summaryBalloon.getSummaryBalloonHTML();
		//Getting the total required pixels to move the balloon
		var totalTopDifference =  summaryBalloon.getTop() - top;
		var totalHeightDifference =  parseInt(summaryBalloonHTML.style.height,10) - bubbleHeight;
		var totalLeftDifference = bubbleWidth -	summaryBalloon.getBubbleWidth();
		var totalWidthDifference = totalLeftDifference;
		var finalLeft = parseInt(detailedBalloonHTML.style.left,10) + totalLeftDifference;
		
		var leftKinematics = new Kinematics(totalLeftDifference/2,0,totalMorphingTime/2);
		var topKinematics = new Kinematics(totalTopDifference/2,0,totalMorphingTime/2);
		var heightKinematics = new Kinematics(totalHeightDifference/2,0,totalMorphingTime/2);
		var widthKinematics = new Kinematics(totalWidthDifference/2,0,totalMorphingTime/2); 
		leftKinematics.Residual = 0;
		topKinematics.Residual = 0;
		heightKinematics.Residual = 0;
		widthKinematics.Residual = 0;
							
		detailedBalloonContent.style.visibility = "hidden";
		detailedBalloonContent.style.display = "none";
		AnkhUsefulMethods.removeAll(detailedBalloonMainDiv);
		animatedDetailedMorph(0,leftKinematics,topKinematics,widthKinematics,heightKinematics,finalLeft);
		EventUtil.getEvent().stopPropagation();
	};

	/**
	 * Purpose: Used to morph detailed to summary balloon 
	 * @param {int} count - current iteration count
	 * @param {Object} leftKinematics - left kinematics to return distance moved
	 * @param {Object} topKinematics - top kinematics to return distance moved
	 * @param {Object} heightKinematics - height kinematics to return distance moved
	 */
	animatedDetailedMorph = function(count,leftKinematics,topKinematics,widthKinematics,heightKinematics,finalLeft){
		
		if (count == morphIteration) {								
			var pointerTop = parseInt(pointerImg.style.top,10);						
			summaryBalloon.minDraw(finalLeft,pointerTop);		//draw detailed balloon based on current x, y coordinates
			return;
		}
		if(count == morphIteration/2){			//when reached the middle point
			leftKinematics.setAcceleration(-leftKinematics.getAcceleration());
			topKinematics.setAcceleration(-topKinematics.getAcceleration());
			heightKinematics.setAcceleration(-heightKinematics.getAcceleration());
			widthKinematics.setAcceleration(-widthKinematics.getAcceleration());
		}		
		
		leftKinematics.getNext(totalMorphingTime/morphIteration);
		topKinematics.getNext(totalMorphingTime/morphIteration);
		heightKinematics.getNext(totalMorphingTime/morphIteration);
		widthKinematics.getNext(totalMorphingTime/morphIteration);
		
		heightKinematics.Residual += heightKinematics.getDistance() - parseInt(heightKinematics.getDistance(),10);
		widthKinematics.Residual += widthKinematics.getDistance() - parseInt(widthKinematics.getDistance(),10);
		topKinematics.Residual += topKinematics.getDistance() - parseInt(topKinematics.getDistance(),10);
		leftKinematics.Residual += leftKinematics.getDistance() - parseInt(leftKinematics.getDistance(),10);
		
		if(topKinematics.Residual >= 1){
			detailedBalloonHTML.style.top = parseInt(parseInt(detailedBalloonHTML.style.top,10) + topKinematics.getDistance()) + 1 +"px";
			pointerImg.style.top = parseInt(parseInt(pointerImg.style.top,10) - topKinematics.getDistance() + 1)+"px";	
			topKinematics.Residual -= 1;	
		}else{
			detailedBalloonHTML.style.top = parseInt(parseInt(detailedBalloonHTML.style.top,10) + topKinematics.getDistance()) +"px";
			pointerImg.style.top = parseInt(parseInt(pointerImg.style.top,10) - topKinematics.getDistance())+"px";		
		}
				
		if (leftKinematics.Residual >= 1) {						
			that.setLeft(parseInt(parseInt(detailedBalloonHTML.style.left,10) + leftKinematics.getDistance() + 1) + shadowWidthOffset);			
			leftKinematics.Residual -= 1;
		}else{			
			that.setLeft(parseInt(parseInt(detailedBalloonHTML.style.left,10) + leftKinematics.getDistance()) + shadowWidthOffset);			
		}
		
		if(widthKinematics.Residual >= 1){
			
			detailedBalloonHTML.style.width = parseInt(parseInt(detailedBalloonHTML.style.width,10) - widthKinematics.getDistance()) - 1 +"px";
			bubbleImg.width = bubbleImg.width - widthKinematics.getDistance() - 1;
			widthKinematics.Residual -= 1;
		}else{
			detailedBalloonHTML.style.width = parseInt(parseInt(detailedBalloonHTML.style.width,10) - widthKinematics.getDistance()) +"px";
			bubbleImg.width = bubbleImg.width - widthKinematics.getDistance();			
		}

		if(heightKinematics.Residual <= -1){
			bubbleImg.height = bubbleImg.height + heightKinematics.getDistance() + 1;
			heightKinematics.Residual += 1;
		}
		else{
			bubbleImg.height = bubbleImg.height + heightKinematics.getDistance();
		}
		
					
		window.setTimeout(function(){
			animatedDetailedMorph(count + 1, leftKinematics, topKinematics, widthKinematics,heightKinematics,finalLeft);
		},totalMorphingTime/morphIteration);		
	};
	
	/**
	 * Purpose: Prevent Detailed Balloon from scrolling.
	 */
	detailedBalloonScroll = function(){		
		if (isIE) {
			delta = -EventUtil.getEvent().wheelDelta / 120;			
		}
		else {
			if (isKHTML) {
				delta = -EventUtil.getEvent().wheelDelta / 120;
			}
			else 
				if (isOpera) {
					delta = EventUtil.getEvent().wheelDelta / 120;
				}
				else { //for firefox
					delta = EventUtil.getEvent().detail / 3;
				}
		}		
		EventUtil.getEvent().stopPropagation();
		if (detailedBalloonMainDiv.scrollHeight > parseInt(AnkhUsefulMethods.getStyle(detailedBalloonMainDiv, "Height"), 10)) { //only if balloon has a scroll bar
			if (delta < 0) { //scroll up			
				var detailedBalloonMainDivHeight = parseInt(AnkhUsefulMethods.getStyle(detailedBalloonMainDiv, "Height"),10);
				var minScrollTop = parseInt(Math.abs(delta)*15 / 100 * detailedBalloonMainDivHeight,10);
				if (detailedBalloonMainDiv.scrollTop == 0) { //reach the top									
					EventUtil.getEvent().preventDefault();
				}
				else if (isIE && detailedBalloonMainDiv.scrollTop <= minScrollTop) {
						detailedBalloonMainDiv.scrollTop = 0;
						EventUtil.getEvent().preventDefault();
				}							
			}
			else if (delta > 0) { //scroll down
				var divHeight = parseInt(AnkhUsefulMethods.getStyle(detailedBalloonMainDiv, "Height"), 10);
				var temp = detailedBalloonMainDiv.scrollHeight - detailedBalloonMainDiv.scrollTop - divHeight;
				
				if (temp <= 0) {
					EventUtil.getEvent().preventDefault();
				}				
				else if (isIE && temp  <= Math.abs(delta) * 15 / 100 * divHeight) {
					detailedBalloonMainDiv.scrollTop = detailedBalloonMainDiv.scrollHeight - divHeight;
					EventUtil.getEvent().preventDefault();
				}
			}
		}
	};	
	/**
	 * Purpose: Set Detailed Balloon Left coordinates with Morizalla been overflow hidden to prevent 
	 * display bug when balloon crosses TimeWall border
	 * @param {int} value  - to move detailed balloon by "left" px
	 */
	this.setLeft = function(value){		
		if (isMoz) {
			detailedBalloonMainDiv.style.overflow = "hidden";
		}
		detailedBalloonHTML.style.left = value +"px";
	};	
	/**
	 * Purpose: Reset overflow style of detailed balloon
	 */
	this.resetOverflow = function(){
		if (isMoz) {
            detailedBalloonMainDiv.style.overflow = "auto";
        }
	};
	
	this.getBubbleWidth = function(){
		return bubbleWidth;
	};
	this.getBubbleHeight = function(){
		return bubbleHeight;
	};
		
	this.getTop = function(){
		return top;
	};
	this.getEventId = function(){
		return eventId;
	};
	this.getEventObj = function(){
		return eventObj;
	};
	
	this.resetPosition = function(){
		detailedBalloonHTML.style.left = "0px";
		detailedBalloonHTML.style.visibility = "hidden";
		detailedBalloonHTML.style.display = "none";
	};
	
	if(isIE && !isMinIE7){
		window.setTimeout(init,100);
	}else{
		init();	
	}
	
	
};
SummaryBalloon = function(ownerId,userName,timeWall,detailedBalloon,rootDir,photoPopup,ajaxUrl,balloonIcons,pointerIcon,isPublic,viewerIsOwner,viewerId,isGroup,pastLabels,pk){
	var that = this;
	//Preloading of Bubble images
    var bubbleImages = new Object();	 
	if (isIE && !isMinIE7) {			
		bubbleImages['Small Bubble'] = rootDir+"wallimage/balloon/PNG8/small-bubble-bg untrimmed.png";
	}else {
	 	bubbleImages['Small Bubble'] = rootDir+"wallimage/balloon/small bubble bg.png";
	}	
	for(var i in bubbleImages){
	 	var imgObj = new Image();
	 	imgObj.src = bubbleImages[i];
	}
	var ankhDate = new AnkhDate(); 
	var ajaxUrl  = ajaxUrl;
	//Number of events in a single page of summary bubble 
	var numOfEventsInAPage = 5;
	var navigationCurrentPage = 1;
	
	//Summary Balloon consists of bubble and pointer without shadow
	var bubbleWidth = 587;
	var bubbleHeight = 390;
	var pointerWidth = 12;
	var pointerHeight = 26;
	
	var groupedEventHeight = 10;
	
	var bubbleContentWidth = 575;			//temporary storage of original bubble content width so that the bubble content can be resized back to its original size, same as css 
	var top = 40;
	
	var photoPopup = photoPopup;
	
	//Summary Balloon with Shadow, i.e. image size
	var bubbleCanvasWidth = 596;
	var bubbleCanvasHeight = 403;
	
	var shadowWidthOffset = 0; 		//used to offset the expansion of the balloon shadow
	//min. distance from y-axis				
	var minXPanelOpen = 300;
	var minXPanelClose = 100;
	var minX = minXPanelOpen;			
	
	//auto-scrolling variables
	var totalAnimationTravelTime = 500;		//700ms
	var scrollingIteration = 10;
	
	//Summary -> Detailed Balloon Morph settings
	var detailedBalloon = detailedBalloon;
	var totalMorphingTime = 200;			//500ms
	var morphIteration = 10;
	 		
	var eventsData = new Array();
	var detailedBalloonEventId;
	
	var ownerId = ownerId;
	var userName = userName;
	var timeWall = timeWall;	
	
	//used to counter check if the current returned AJAX result can be populated
	var currentGetSDate;
	var currentGetEDate;
	var currentGetMood;
	
	//HTML
	var summaryBalloonHTML = document.createElement('div');
	summaryBalloonHTML.id = "SummaryBalloon";
	//Summary Balloon Images
	var bubbleImg = document.createElement('img');
	bubbleImg.className = "balloonBackground";
	var pointerImg = new AnkhSprite(pointerIcon,12,26,{x:0,y:43});
	pointerImg.className = "balloonPointer";
	pointerImg.style.right = "0px";
	var summaryBalloonContent = document.createElement('div');
	summaryBalloonContent.id = "SummaryBalloonContent";
	
	var closeBtn = new AnkhSprite(balloonIcons,17,18,{x:0,y:216},{x:17,y:216},{x:17,y:216});
	closeBtn.style.cssFloat = "right";
	closeBtn.style.styleFloat = "right";
	closeBtn.style.cursor = "pointer";
	var moodIcon = document.createElement('div');
	moodIcon.style.cssFloat = "left";
	moodIcon.style.styleFloat = "left";
	//Summary Balloon Header
	var summaryBalloonHeader = new GenericTable(2,2);
	summaryBalloonHeader.Table.id = "SummaryBalloonHeader";
	summaryBalloonHeader.getCell(0,0).id = "SummaryBalloonMood";
	summaryBalloonHeader.getCell(0,0).align = "left";
	
	var moodDescription = document.createElement('span');
	moodDescription.id = "MoodDescription";
	summaryBalloonHeader.insertIntoCell(0,0,moodDescription);
	
	var numberOfEvents = document.createElement('span');
	numberOfEvents.id = "NumberOfEvents";
	summaryBalloonHeader.insertIntoCell(0,0,numberOfEvents);
	
	var summaryBalloonDateRange = document.createElement('span');
	summaryBalloonHeader.insertIntoCell(1,0,summaryBalloonDateRange);
		
	var summaryBalloonNavigation = document.createElement('div');
	summaryBalloonNavigation.className = "navigationBar";
	summaryBalloonHeader.insertIntoCell(1,1,summaryBalloonNavigation);
	
	var lineSeparatorHR = document.createElement('hr');
	lineSeparatorHR.style.backgroundColor = "#A8B6B9";

	//Summary Balloon Main Div
	var summaryBalloonContentMainDiv = document.createElement('div');
	summaryBalloonContentMainDiv.id = "SummaryBalloonContentMainDiv";
	
	var summaryBalloonContentMain = document.createElement('div');	
	summaryBalloonContentMain.id = "SummaryBalloonContentMain";
	summaryBalloonContentMainDiv.appendChild(summaryBalloonContentMain);
	
	var ajaxLoaderImg = new AnkhAJAXLoader("");
	ajaxLoaderImg.style.position = "relative";
	ajaxLoaderImg.style.top = "100px";
	ajaxLoaderImg.style.left = "250px";
	summaryBalloonContentMainDiv.appendChild(ajaxLoaderImg);
	var navigationBar;
	
	var openDirectPicId;
	
	initComponents = function(){
		
		summaryBalloonHTML.style.left = "0px";
		summaryBalloonHTML.style.top = top+"px";
		summaryBalloonHTML.style.height = bubbleHeight + "px";
		summaryBalloonHTML.style.width = bubbleWidth + pointerWidth + "px";
		
		summaryBalloonHeader.Table.cellPadding = 0;
		summaryBalloonHeader.Table.cellSpacing = 0;
		summaryBalloonContent.appendChild(closeBtn);
		summaryBalloonContent.appendChild(moodIcon);
		summaryBalloonContent.appendChild(summaryBalloonHeader.Table);
		summaryBalloonContent.appendChild(lineSeparatorHR);
		summaryBalloonContent.appendChild(summaryBalloonContentMainDiv);
		summaryBalloonHTML.appendChild(bubbleImg);
		summaryBalloonHTML.appendChild(pointerImg);
		summaryBalloonHTML.appendChild(summaryBalloonContent);
						
		EventUtil.addEventHandler(closeBtn,"click",function x(){			
				summaryBalloonHTML.style.visibility ="hidden"; 
				summaryBalloonHTML.style.display = "none"; 
				EventUtil.getEvent().stopPropagation();});
		EventUtil.addEventHandler(summaryBalloonHTML, "mousewheel", balloonScroll);
		EventUtil.addEventHandler(summaryBalloonHTML, "mousedown", function x(){		//prevents IE from moving the timewall when mouse down			
			EventUtil.getEvent().stopPropagation();
		});		
		EventUtil.addEventHandler(summaryBalloonHTML, "click", function x(){		//prevents IE from moving the timewall when mouse down			
			EventUtil.getEvent().stopPropagation();
		});				
	};


	
	/**
	 * Purpose: Used to set the start-end date range with the mood. 
	 * 			Also used to query events within this range.
	 * @param {Int} ownerId - owner of timewall
	 * @param {Date} startDate - start date of grouped event
	 * @param {Date} endDate - end date of grouped event
	 * @param {Int} mood - mood of the grouped event
	 * @param {String} label - user's chosen label
	 * @param {String} type - privacy, custom, updates
	 */
	this.init = function(ownerId,startDate,endDate,mood,label,type){		
		detailedBalloonEventId = null;				
		pointerImg.style.top = "40px";	
		
		numberOfEvents.innerHTML = "Getting information ...";
		//reset the images' width & height to initial values since it might have been morphed
		bubbleImg.src = bubbleImages['Small Bubble'];
		bubbleImg.width = bubbleCanvasWidth;
		bubbleImg.height = bubbleCanvasHeight;						

		summaryBalloonHTML.style.left = "0px";
		summaryBalloonHTML.style.top = top+"px";							
		
		//reset the navigation current page		
		navigationCurrentPage = 1;
		updateBalloon(ownerId,startDate,endDate,mood,label,type);
	};	
		
	/**
	 * Purpose: Used primarily by TimeWall to display the detailed balloon directly.
	 * @param {Int} ownerId - owner of timewall
	 * @param {Date} startDate  - start date of grouped event in JS format
	 * @param {Date} endDate - end date of grouped event in JS format
	 * @param {Int} mood - mood of the grouped event
	 * @param {Int} eventId - if !null, detailed balloon is displayed with the associated event
	 * @param {Int} gridX - x coordinates of the selected grid
	 * @param {Int} y - y coordinates of the selected event image
	 * @param {Int} groupEventImgWidth - width of the selected event image
	 * @param {Int} anchorLeft - absolute x coordinates of the anchor
	 * @param {String} label - user's chosen label
	 * @param {String} type - privacy, custom, updates
	 * @param {Int} picId - picture id
	 */
	this.initToDisplayDetailedBalloonDirect = function(ownerId,startDate,endDate,mood,eventId,gridX,y,anchorLeft,label,type,picId){		
		detailedBalloonEventId = eventId;		
		var realX = gridX+anchorLeft;						
		var bubbleLeft = realX - bubbleWidth - 12/2 ;		//12 = pointerImg.width 
		var pointerTop = y - pointerHeight/2 - groupedEventHeight/2;
		
		openDirectPicId = picId;
		summaryBalloonContent.style.width = bubbleContentWidth +"px";
		summaryBalloonHTML.style.visibility = "hidden";
		summaryBalloonHTML.style.display = "none";
		summaryBalloonHTML.style.left = bubbleLeft + "px";
	
		bubbleImg.src = bubbleImages['Small Bubble'];
		bubbleImg.width = bubbleCanvasWidth;
		bubbleImg.height = bubbleCanvasHeight;				
		
		var summaryPointerLeft = bubbleWidth;
		var summaryPointerTop = y - pointerHeight/2 - groupedEventHeight/2;		
		pointerImg.style.top = summaryPointerTop + "px";		
		
		
		var totalTopDifference = top - detailedBalloon.getTop();
		var totalLeftDifference = 	detailedBalloon.getBubbleWidth() - bubbleWidth;
		var newDetailedBalloonLeft = bubbleLeft - totalLeftDifference;		
		var newDetailedPointerTop = summaryPointerTop + totalTopDifference;
		detailedBalloon.draw(newDetailedBalloonLeft,newDetailedPointerTop);		//draw detailed balloon based on current x, y coordi		
		updateBalloon(ownerId,startDate,endDate,mood,label,type);		
	};		

	/**
	 * 
	 * Purpose - AJAX call to obtain information for the events within this startDate - endDate
	 * @param {Int} ownerId - Id of the timewall's owner
	 * @param {Date} startDate - startDate of the groupedEvent in JS Date
	 * @param {Date} endDate - endDate of the groupedEvent in JS Date
	 * @param {Int} mood - mood of the groupedEvent
	 * @param {String} label - user's chosen label
	 * @param {String} type - privacy, custom, updates
	 */
	updateBalloon = function(ownerId,startDate,endDate,mood,label,type){		
		clean();
		ajaxLoaderImg.style.visibility = "visible";
		ajaxLoaderImg.style.display = "block";
		
		var iconCoordinate = timeWall.getMoodsTranslation(mood).Image1;
		AnkhUsefulMethods.removeAll(moodIcon);
		var icon = new AnkhSprite(iconCoordinate['img'],iconCoordinate['width'],iconCoordinate['height'],iconCoordinate['normSrc']);
		moodIcon.appendChild(icon);		
		moodDescription.innerHTML = timeWall.getMoodsTranslation(mood).Description;	

		var dayBeforeEndDate = ankhDate.subtractDays(endDate,1);
		if(ankhDate.getDMY(startDate," ") == ankhDate.getDMY(dayBeforeEndDate," ")){
			summaryBalloonDateRange.innerHTML = ankhDate.getDMY(startDate," ");
		}else{
			summaryBalloonDateRange.innerHTML = ankhDate.getDMY(startDate," ")+" - "+ankhDate.getDMY(dayBeforeEndDate," ");
		}
		
		var startMonth = startDate.getMonth()+1;
		var endMonth = endDate.getMonth()+1;	
		startDate = startDate.getFullYear()+"-"+startMonth+"-"+startDate.getDate();
		endDate = endDate.getFullYear()+"-"+endMonth+"-"+endDate.getDate();
		currentGetSDate = startDate;
		currentGetEDate = endDate;
		currentGetMood = mood;
		
		var method = "getEvents"; 				
		var parameterObj = {method:method,ownerId:ownerId,startDt:startDate,endDt:endDate,mood:mood,label:label,type:type,pk:pk};
		new AnkhAjax(ajaxUrl,"get",parameterObj,updateBalloonSuccess,ajaxLoaderImg);		
	}
	/**
	 * Purpose - This is called after updateBalloon is successful
	 */
	updateBalloonSuccess = function(transport){					
		ajaxLoaderImg.style.visibility = "hidden";
		ajaxLoaderImg.style.display = "none";			
		var result = transport.responseText.evalJSON(true);				
		if (currentGetSDate == result.startDt && currentGetEDate == result.endDt && currentGetMood == result.mood) {
								
			clean();			
			eventsData = new Array();			
			if (result.Events.length > 1) {
				numberOfEvents.innerHTML = "(" + result.Events.length + " events)";
			}
			else if (result.Events.length == 1) {
					numberOfEvents.innerHTML = "(" + result.Events.length + " event)";
			}
								
			var index;
			for (var i = 0; i < result.Events.length; i++) {				
				var todayDate = ankhDate.mysqlTimeStampToDate(result['currentTime']);
				var mood = result['mood'];
				var eventObj = new EventObject(ownerId,mood, result.Events[i], i,detailedBalloon,timeWall,photoPopup,ajaxUrl,isPublic,todayDate,viewerIsOwner,viewerId,isGroup,pastLabels,openDirectPicId,pk);					
				eventsData.push(eventObj);							
				if (detailedBalloonEventId != null && result.Events[i].eventId == detailedBalloonEventId) {
					index = i;								
					navigationCurrentPage = Math.ceil((index+1)/numOfEventsInAPage);					
				}
				EventUtil.addEventHandler(eventObj.getLinkToDetailedBalloon(), "click", displayDetailedBalloonOnMouseUp);
				EventUtil.addEventHandler(eventObj.getLinkToDetailedBalloon(), "mouseover", function x(){EventUtil.getEvent().target.className = "Link_MouseOver";});
				EventUtil.addEventHandler(eventObj.getLinkToDetailedBalloon(), "mouseout", function x(){EventUtil.getEvent().target.className = "Link";});	
			}
	
			displayEventContent();			
			if (index != null) {			
				detailedBalloon.loadEventObject(eventsData[index]);					
			}
			navigationBar = new NavigationBar(result.Events.length, numOfEventsInAPage, switchPage);			
			summaryBalloonNavigation.appendChild(navigationBar.getHTML(navigationCurrentPage));			
		}
	};
		
	//display event from the eventsData container into the summary balloon
	displayEventContent = function(){				
		for(var i = (navigationCurrentPage-1)*numOfEventsInAPage; i < navigationCurrentPage*numOfEventsInAPage;i++){				
			if (eventsData[i]!=null) {				
				summaryBalloonContentMain.appendChild(eventsData[i].getSummaryEventHTML());
			}
		}		
	};

	/**
	 * Purpose: Given the current grid X coordinates, mood Y coordinates, groupedeventImg object, 
	 * current anchorleft coordinates, the summary balloon can be drawn automatically based on 
	 * its width & height
	 * @param {Int} gridX
	 * @param {Int} y
	 * @param {Int} groupEventImgWidth
	 * @param {Int} anchorLeft
	 */
	this.draw = function(gridX,y,anchorLeft,showDetailedBalloon){
		if(!showDetailedBalloon){	
			detailedBalloon.getDetailedBalloonHTML().style.visibility = "hidden";
			detailedBalloon.getDetailedBalloonHTML().style.display = "none";
		}	
		var realX = gridX+anchorLeft;				
		var bubbleleft = realX - bubbleWidth - pointerImg.clientWidth/2 ;
		var pointerTop = y - pointerHeight/2 - groupedEventHeight/2;		
		summaryBalloonHTML.style.width = bubbleWidth + pointerWidth + "px";				
		summaryBalloonContent.style.width = bubbleContentWidth +"px";
		summaryBalloonHTML.style.visibility = "visible";
		summaryBalloonHTML.style.display = "block";		
		summaryBalloonHTML.style.left = bubbleleft + "px";
		pointerImg.style.top = pointerTop +"px";
		if(timeWall.isPanelOpen()){
			minX = minXPanelOpen;	
		}else{
			minX = minXPanelClose;
		}		
		if(bubbleleft< minX){			//auto scroll to fit balloon into timewall's viewport			
			autoScroll(minX - bubbleleft);					
		}			
		timeWall.resetZoomActivate();
	};
	
	/**
	 * Purpose: Draw summary balloon when minimised by detailed balloon
	 * @param {Int} balloonLeft
	 * @param {Int} balloonTop	 
	 * @param {Int} pointerTop
	 */
	this.minDraw = function(balloonLeft,pointerTop){
		clean();
		detailedBalloon.getDetailedBalloonHTML().style.visibility = "hidden";
		detailedBalloon.getDetailedBalloonHTML().style.display = "none";
		summaryBalloonHTML.style.visibility = "visible";
		summaryBalloonHTML.style.display = "block";
		summaryBalloonHTML.style.left = balloonLeft + "px";
		summaryBalloonHTML.style.top = top + "px";
		summaryBalloonHTML.style.width = bubbleWidth + pointerWidth + "px";
		summaryBalloonContent.style.width = bubbleContentWidth +"px";
		//reset the images' width & height to initial values since it might have been morphed
		bubbleImg.src = bubbleImages['Small Bubble'];
		bubbleImg.width = bubbleCanvasWidth;		
		bubbleImg.height = bubbleCanvasHeight;												
		pointerImg.style.top = pointerTop+"px";
		
		displayEventContent();
		navigationBar = new NavigationBar(eventsData.length,numOfEventsInAPage,switchPage);
		summaryBalloonNavigation.appendChild(navigationBar.getHTML(navigationCurrentPage));	
	};
	
	/**
	 * Purpose: Switch between the different pages. Called by the navigationBar object
	 */
	switchPage = function(){	
		navigationCurrentPage = parseInt(EventUtil.getEvent().target.innerHTML,10);
		clean();
		summaryBalloonNavigation.appendChild(navigationBar.getHTML(navigationCurrentPage));
		displayEventContent();
		EventUtil.getEvent().preventDefault();
	};
	
	/**
	 * Purpose: Used to clean up the balloon
	 */
	clean = function(){		
		AnkhUsefulMethods.removeAll(summaryBalloonNavigation);
		AnkhUsefulMethods.removeAll(summaryBalloonContentMain);
	};
	/**
	 * Purpose: Used to prevent the browser from scrolling when user is scrolling within the balloon
	 */
	balloonScroll = function(){		
		if (isIE) {
			delta = -EventUtil.getEvent().wheelDelta / 120;
		}
		else {
			if (isKHTML) {
				delta = -EventUtil.getEvent().wheelDelta / 120;
			}
			else 
				if (isOpera) {
					delta = EventUtil.getEvent().wheelDelta / 120;
				}
				else { //for firefox
					delta = EventUtil.getEvent().detail / 3;
				}
		}
		
		if (summaryBalloonContentMainDiv.scrollHeight > parseInt(AnkhUsefulMethods.getStyle(summaryBalloonContentMainDiv, "Height"), 10)) { //only if balloon has a scroll bar
			if (delta < 0) { //scroll up
				if (summaryBalloonContentMainDiv.scrollTop == 0) { //reach the top									
					EventUtil.getEvent().preventDefault();
				}
				else if (isIE && summaryBalloonContentMainDiv.scrollTop <= Math.abs(delta)*15 / 100 * parseInt(AnkhUsefulMethods.getStyle(summaryBalloonContentMainDiv, "Height"), 10)) {
						summaryBalloonContentMainDiv.scrollTop = 0;
						EventUtil.getEvent().preventDefault();
				}
			}
			else if (delta > 0) { //scroll down
				var divHeight = parseInt(AnkhUsefulMethods.getStyle(summaryBalloonContentMainDiv, "Height"), 10);
				var temp = summaryBalloonContentMainDiv.scrollHeight - summaryBalloonContentMainDiv.scrollTop - divHeight;
				if (temp == 0) {
					EventUtil.getEvent().preventDefault();
				}				
				else if (isIE && temp  <= Math.abs(delta) * 15 / 100 * divHeight) {
					summaryBalloonContentMainDiv.scrollTop = summaryBalloonContentMainDiv.scrollHeight - divHeight;
					EventUtil.getEvent().preventDefault();
				}
			}
		}	
		EventUtil.getEvent().stopPropagation();
	};				
	
	this.setLeft = function(value){
		if (isMoz) {
			summaryBalloonContentMainDiv.style.overflow = "hidden";
		}		
		summaryBalloonHTML.style.left = value +"px";
	};
	this.resetOverflow = function(){
		if (isMoz) {
			summaryBalloonContentMainDiv.style.overflow = "auto";
		}
	};
	/**
	 * Purpose: Called when balloon exceeds y-axis, to scroll the timewall and balloon back to view
	 * @param {Int} distance
	 */
	autoScroll = function(distance){	
		var kinematics = new Kinematics(distance/2,0,totalAnimationTravelTime/2);
		kinematics.residual = 0;
		animatedMovingLeft(0,distance,kinematics);		
	};
	
	 /**
	  * Purpose: 	1. Used to animate the moving of the summary balloon
	  * 			2. Adjust the time wall by the same distance
	  * @param {Int} currentIteration - current number of iteration
	  * @param {Int} totalDistance - total distance to be moved
	  * @param {Object} kinematics - kinematics of this animation
	  */
	animatedMovingLeft = function(currentIteration,totalDistance,kinematics){
		if( currentIteration == scrollingIteration){
		
			that.setLeft(minX);
			that.resetOverflow(); 
			timeWall.divMaintenance(totalDistance);
			return;
		}
		if(currentIteration == scrollingIteration/2){			//when reached the middle point
			kinematics.setAcceleration(-kinematics.getAcceleration());
		}
		kinematics.getNext(totalAnimationTravelTime/scrollingIteration);
		kinematics.residual += kinematics.getDistance() - parseInt(kinematics.getDistance(),10);
		
		if (kinematics.residual >= 1) {
			that.setLeft(parseInt(summaryBalloonHTML.style.left, 10) + parseInt(kinematics.getDistance(),10) + parseInt(kinematics.residual, 10));
			timeWall.balloonScrollRight(parseInt(kinematics.getDistance(),10) + parseInt(kinematics.residual, 10));
			kinematics.residual -= parseInt(kinematics.residual, 10);
		}
		else {
			that.setLeft(parseInt(summaryBalloonHTML.style.left, 10) + parseInt(kinematics.getDistance(),10));
			timeWall.balloonScrollRight(parseInt(kinematics.getDistance(),10));
		}
		
		window.setTimeout(function(){animatedMovingLeft(currentIteration+1,totalDistance,kinematics)},totalAnimationTravelTime/scrollingIteration);		
	};
	

	
	/**
	 * Purpose: Display detailed balloon on mouse up
	 */
	displayDetailedBalloonOnMouseUp = function(){
		eventObject = eventsData[EventUtil.getEvent().target.order]; 
		//get the eventObject to be displayed in the detailed bubble since 
		//it cannot be passed in via the EventHandler
		displayDetailedBalloon(eventObject);
	};
	
	/**
	 * Purpose: Preparing summary -> detailed balloon morphing attributes 
	 * @param {Object} eventObject
	 */
	displayDetailedBalloon = function(eventObject){
		var balloonLeft = parseInt(summaryBalloonHTML.style.left,10);
		if (balloonLeft < minX) {
			var scrollDistance = minX - balloonLeft;
			var scrollKinematics = new Kinematics(scrollDistance/2,0,totalMorphingTime/2);
			scrollBeforeMorph(scrollDistance,0,scrollKinematics, eventObject);
		}
		else {
			morphToDetailedBalloon(eventObject);
		}
	};
	
	/**
	 * Purpose: Scroll before calling function to morph summary balloon to detailed balloon
	 * @param {Int} scrollDistance
	 * @param {Int} count
	 * @param {Object} scrollKinematics
	 * @param {Object} eventObject
	 */
	scrollBeforeMorph = function(scrollDistance,count,scrollKinematics, eventObject){
		if(count == morphIteration){
			that.resetOverflow(); 
			timeWall.divMaintenance(scrollDistance);
			morphToDetailedBalloon(eventObject);
			return;
		}
		
		if(count == morphIteration/2){			//when reached the middle point
			scrollKinematics.setAcceleration(-scrollKinematics.getAcceleration());
		}
		scrollKinematics.getNext(totalMorphingTime/morphIteration);
		scrollKinematics.residual += scrollKinematics.getDistance() - parseInt(scrollKinematics.getDistance(),10);
		
		if (scrollKinematics.residual >= 1) {
			that.setLeft(parseInt(summaryBalloonHTML.style.left, 10) + parseInt(scrollKinematics.getDistance(),10) + parseInt(scrollKinematics.residual, 10));
			timeWall.balloonScrollRight(parseInt(scrollKinematics.getDistance(),10) + parseInt(scrollKinematics.residual, 10));
			scrollKinematics.residual -= parseInt(scrollKinematics.residual, 10);
		}
		else {
			that.setLeft(parseInt(summaryBalloonHTML.style.left, 10) + parseInt(scrollKinematics.getDistance(),10));
			timeWall.balloonScrollRight(parseInt(scrollKinematics.getDistance(),10));
		}
		
		window.setTimeout(function(){scrollBeforeMorph(scrollDistance,count+1,scrollKinematics, eventObject)},totalMorphingTime/morphIteration);		
		
	};
	
	/**
	 * Purpose: Used to morph summary balloon to detailed balloon
	 * @param {Object} eventObject - object to be displayed
	 */
	morphToDetailedBalloon = function(eventObject){
		var totalTopDifference = parseInt(summaryBalloonHTML.style.top,10) - detailedBalloon.getTop();
		var totalHeightDifference =  detailedBalloon.getBubbleHeight() - parseInt(summaryBalloonHTML.style.height,10);
		var totalLeftDifference = 	detailedBalloon.getBubbleWidth() - bubbleWidth;
		var totalWidthDifference = totalLeftDifference;			
		
		var balloonLeft = parseInt(summaryBalloonHTML.style.left,10);
		if(balloonLeft - totalLeftDifference < 0){
			timeWall.divMaintenance(totalLeftDifference - balloonLeft); //divMaintenance when +ve appends to the left. need to ensure that timewall is been maintained	
		}				
		var leftKinematics = new Kinematics(totalLeftDifference/2,0,totalMorphingTime/2);
		var topKinematics = new Kinematics(totalTopDifference/2,0,totalMorphingTime/2);
		var heightKinematics = new Kinematics(totalHeightDifference/2,0,totalMorphingTime/2);
		var widthKinematics = new Kinematics(totalWidthDifference/2,0,totalMorphingTime/2);
		leftKinematics.Residual = 0;
		topKinematics.Residual = 0;
		heightKinematics.Residual = 0;
		widthKinematics.Residual = 0;
												
		clean();		
		animatedMorph(0, leftKinematics, widthKinematics, topKinematics, heightKinematics, eventObject);
	};

	/**
	 * Purpose: Used to animate the morphing of summary to detailed balloon
	 * @param {Int} count
	 * @param {Object} leftKinematics
	 * @param {Object} topKinematics
	 * @param {Object} heightKinematics
	 * @param {Object} eventObject
	 */
	animatedMorph = function(count,leftKinematics,widthKinematics,topKinematics,heightKinematics,eventObject){
		if (count == morphIteration) {			
			var balloonLeft = parseInt(summaryBalloonHTML.style.left,10) + 3;			//manual adjustment	
			var pointerTop = parseInt(pointerImg.style.top,10);		
			summaryBalloonHTML.style.visibility = "hidden";
			summaryBalloonHTML.style.display = "none";	
			that.resetOverflow();
			detailedBalloon.draw(balloonLeft,pointerTop);		//draw detailed balloon based on current x, y coordinates			
			detailedBalloon.loadEventObject(eventObject);
			return;
		}
		if(count == morphIteration/2){			//when reached the middle point
			leftKinematics.setAcceleration(-leftKinematics.getAcceleration());
			topKinematics.setAcceleration(-topKinematics.getAcceleration());
			heightKinematics.setAcceleration(-heightKinematics.getAcceleration());
			widthKinematics.setAcceleration(-widthKinematics.getAcceleration());
		}				
		leftKinematics.getNext(totalMorphingTime/morphIteration);
		topKinematics.getNext(totalMorphingTime/morphIteration);
		heightKinematics.getNext(totalMorphingTime/morphIteration);
		widthKinematics.getNext(totalMorphingTime/morphIteration);
			
		heightKinematics.Residual += heightKinematics.getDistance() - parseInt(heightKinematics.getDistance(),10);
		leftKinematics.Residual += leftKinematics.getDistance() - parseInt(leftKinematics.getDistance(),10);
		topKinematics.Residual += topKinematics.getDistance() - parseInt(topKinematics.getDistance(),10);
		widthKinematics.Residual += widthKinematics.getDistance() - parseInt(widthKinematics.getDistance(),10);		
	
		if(topKinematics.Residual >= 1){			
			summaryBalloonHTML.style.top = parseInt(parseInt(summaryBalloonHTML.style.top,10) - topKinematics.getDistance() + 1) +"px";
			pointerImg.style.top = parseInt(parseInt(pointerImg.style.top,10) + topKinematics.getDistance() + 1)+"px";					
			topKinematics.Residual -= 1;	
		}else{
			summaryBalloonHTML.style.top = parseInt(parseInt(summaryBalloonHTML.style.top,10) - topKinematics.getDistance()) +"px";
			pointerImg.style.top = parseInt(parseInt(pointerImg.style.top,10) + topKinematics.getDistance())+"px";		
		}
		
		if (leftKinematics.Residual >= 1) {			
			that.setLeft(parseInt(parseInt(summaryBalloonHTML.style.left) - leftKinematics.getDistance() + 1));										
			leftKinematics.Residual -= 1;
		}else{
			that.setLeft(parseInt(parseInt(summaryBalloonHTML.style.left) - leftKinematics.getDistance()));						
		}
		
		if(widthKinematics.Residual >= 1){
			summaryBalloonHTML.style.width = parseInt(summaryBalloonHTML.style.width,10) +  widthKinematics.getDistance() + 1+"px";
			bubbleImg.width = bubbleImg.width + widthKinematics.getDistance() + 1 + shadowWidthOffset;
			summaryBalloonContent.style.width = parseInt(AnkhUsefulMethods.getStyle(summaryBalloonContent,"Width"),10) +  widthKinematics.getDistance() + 1+"px";			
			widthKinematics.Residual -= 1;
		}else{
			summaryBalloonHTML.style.width = parseInt(summaryBalloonHTML.style.width,10) +  widthKinematics.getDistance() +"px";
			bubbleImg.width = bubbleImg.width + widthKinematics.getDistance();
			summaryBalloonContent.style.width = parseInt(AnkhUsefulMethods.getStyle(summaryBalloonContent,"Width"),10) +  widthKinematics.getDistance()+"px";
		}
		if(heightKinematics.Residual >= 1){
			bubbleImg.height = bubbleImg.height + heightKinematics.getDistance() + 1;
			heightKinematics.Residual -= 1;
		}else{
			bubbleImg.height = bubbleImg.height + heightKinematics.getDistance();
		}					
		if(parseInt(summaryBalloonHTML.style.left,10) < minX){		
			var movementLeft = parseInt(parseInt(summaryBalloonHTML.style.left,10)+leftKinematics.getDistance());
			that.setLeft(movementLeft);
			timeWall.balloonScrollRight(leftKinematics.getDistance());						
		}	
		window.setTimeout(function(){
			animatedMorph(count + 1, leftKinematics, widthKinematics,topKinematics, heightKinematics,eventObject);
		},totalMorphingTime/morphIteration);		
	};

	
	this.getSummaryBalloonHTML = function(){
		return summaryBalloonHTML;
	};	
	this.addEvent = function(obj){
		eventsData.push(obj);
	};
	this.getEvents = function(){
		return eventsData;
	};
	this.getBubbleWidth = function(){
		return bubbleWidth;
	};
	this.resetPosition = function(){
		summaryBalloonHTML.style.left = "0px";
		summaryBalloonHTML.style.visibility = "hidden";
		summaryBalloonHTML.style.display = "none";
	};
	this.getTop = function(){
		return top;
	};

	/**
	 * Purpose: Used primarily by Detailed balloon to update the summary balloon's navigation page
	 * due to the next/previous event 
	 * @param {Int} currentEventRank - position of event in the array
	 */
	this.setCurrentNavigationPage = function(currentEventRank){		
		 navigationCurrentPage = Math.ceil(currentEventRank/numOfEventsInAPage);
	};
	initComponents();	
};

