(function()
{
	Common.Object.create('Typical.Chat.RoomWindow.Users', {

		elements : null,
		
		usersToUpdateAfterUnhover : null,
		
		Users : function(roomWindow, container)
		{
			this.roomWindow = roomWindow;
			
			this.roomWindow.onConnect.add(this.handleConnect, this);
			this.roomWindow.onUserOnline.add(this.handleUserOnline, this);
			this.roomWindow.onUserOffline.add(this.handleUserOffline, this);
			
			this.userHover = false;
			
			this.initGUI(container);
		},
		
		initGUI : function(container)
		{
			var inputContainer = Builder.node('div', {className : 'input'});
			
			this.elements = {	element : Builder.node('div', {className : 'typical chat roomwindow users'}),
								container : Builder.node('div', {className : 'subcontainer'}),
								elements : {},
								elementStates : {},
								orderedDisplayedUsers : []
							};
			
			Element.insert(this.elements.element, this.elements.container);
			
			Event.observe(this.elements.container, 'mouseover', this.handleUsersHover.bindAsEventListener(this));
			Event.observe(this.elements.container, 'mouseout', this.handleUsersUnhover.bindAsEventListener(this));
			
			Element.insert(container, this.elements.element);
		},
		
		handleConnect : function()
		{
			var usersData = this.roomWindow.getUsersData();
			
			for(var i in usersData)
				this.handleUserOnline(usersData[i]);
		},
		
		handleUserOnline : function(userData)
		{
			this.checkUserAppearence(userData);
		},
		
		handleUserOffline : function(userData)
		{
			this.checkUserAppearence(userData);
		},
		
		handleUsersUnhoverTimeOut : null,
		userDetailsTimeout : null,
		
		handleUsersHover : function(event)
		{
			if(this.handleUsersUnhoverTimeOut)
				clearTimeout(this.handleUsersUnhoverTimeOut);
			
			if(this.usersToUpdateAfterUnhover == null)
				this.usersToUpdateAfterUnhover = [];
				
			if(this.userDetailsTimeout == null)
			{
				this.userDetailsTimeout = setTimeout(function()
				{
					this.userDetailsTimeout = -1;
					
					if(this.defferedHandleUserHover)
						this.defferedHandleUserHover();
					
				}.bind(this), 1000);
			}
		},
		
		handleUsersUnhover : function(event)
		{
			if(this.userFirstHoverTimeout)
			{
				clearTimeout(this.userFirstHoverTimeout);
					
				this.userFirstHoverTimeout = null;
			}
			
			if(this.handleUsersUnhoverTimeOut)
				clearTimeout(this.handleUsersUnhoverTimeOut);
			
			if(event)
				this.handleUsersUnhoverTimeOut = setTimeout(this.handleUsersUnhover.curry(null).bind(this), 2000);
				
			else
			{
				if(this.userDetailElement)
				{
					this.userDetailsTimeout = null;
					
					Element.remove(this.userDetailElement);
					
					if(this.lastUserElementDetail)
						Element.removeClassName(this.lastUserElementDetail, 'hover');
						
					this.userDetailElement = null;
				}
				
				var usersToUpdateAfterUnhover = this.usersToUpdateAfterUnhover;
				
				this.usersToUpdateAfterUnhover = null;
				
				for(var i = 0; i < usersToUpdateAfterUnhover.length; i++)
					this.checkUserAppearence(usersToUpdateAfterUnhover[i]);
			}
		},
		
		userSorter : function(userA, userB)
		{
			if(userA.isModerator != userB.isModerator)
				return userA.isModerator ? -1 : 1;
				
			else if(userA.isVIP != userB.isVIP)
				return userA.isVIP ? -1 : 1;
				
			else
				return userA.username < userB.username ? -1 : 1;
		},
		
		deleteUser : function(userData)
		{
			// Doesn't it exists?
			if(!userData)
				return;
			
			// Delete.
			if(this.elements.elements[userData.id].parentNode)
				Element.remove(this.elements.elements[userData.id]);
				
			this.elements.orderedDisplayedUsers.splice(this.elements.orderedDisplayedUsers.indexOf(userData), 1);
			
			delete this.elements.elements[userData.id];
			delete this.elements.elementStates[userData.id];
			
			this.elements.elements[userData.id] = null;
		},
		
		createUser : function(userData)
		{
			if(this.elements.elements[userData.id] || this.elements.orderedDisplayedUsers.indexOf(userData) >= 0)
				return;	
					
			// Construct element.
			var userContainer = Builder.node('div', {className : 'user', style : 'display: none'});
			{
				var userElement = Builder.node('div', {}, [Builder.node('img', {width : 50, height : 50, src : Config.baseUrl + 'external/image/profile/avatar/' + (userData.avatarExtension ? userData.id + '.' + userData.avatarExtension : 'standard.jpg'), lowsrc : Config.baseUrl + 'external/image/profile/avatar/standard.jpg', className : 'avatar'})]);
				{
					if(userData.isVIP)
						Element.insert(userElement, Builder.node('img', {className : 'vip', title : 'Is Very Important Petter.' /* @todo */, src : Config.baseUrl + 'external/image/typical/chat/roomwindow/users/vip.png'}));
					
					if(userData.isModerator)
						Element.insert(userElement, Builder.node('img', {className : 'moderator', title : 'Is moderator en zorgt dus voor een veilige chat.' /* @todo */, src : Config.baseUrl + 'external/image/typical/chat/roomwindow/users/moderator.png'}));
					
					Event.observe(userElement, 'click', 	this.handleUserClick.bindAsEventListener(this, userData));
					Event.observe(userElement, 'mouseover', this.handleUserHover.bindAsEventListener(this, userData, userElement));
				}
				Element.insert(userContainer, userElement);
			}
			
			this.elements.elementStates[userData.id] = 'toactivate';
			
			this.elements.orderedDisplayedUsers.push(userData);
			this.elements.orderedDisplayedUsers.sort(this.userSorter);
			
			var index = this.elements.orderedDisplayedUsers.indexOf(userData);
			
			if(index == 0)
				Element.insert(this.elements.container, {top : userContainer});
				
			else
				Element.insert(this.elements.container.childNodes[index - 1], {after : userContainer});
			
			this.elements.elements[userData.id] = userContainer;
		},
		
		checkUserAppearence : function(userData)
		{
			if(!this.elements.elements[userData.id] && !userData.isOnline)
				return;
				
			if(this.usersToUpdateAfterUnhover != null)
				this.usersToUpdateAfterUnhover.push(userData);
			
			else if(this.elements.elementStates[userData.id] != 'busy')
			{
				this.createUser(userData);
				
				var elementState = this.elements.elementStates[userData.id];
				var userElement = this.elements.elements[userData.id];
				
				// Add?
				if(elementState == 'toactivate')
				{
					this.elements.elementStates[userData.id] = 'busy';
					
					// Activate
					new Effect.Grow(userElement, {opacityTransition : Effect.Transitions.linear, afterSetup : function()
						{
							Element.setStyle(userElement, {display : ''});
						},
						afterFinish : function()
						{
							this.elements.elementStates[userData.id] = 'active';
							
							this.checkUserAppearence(userData);
						}.bind(this)});
				}
				else if(userData.isOnline && elementState == 'inactive')
				{
					this.elements.elementStates[userData.id] = 'busy';
					
					new Effect.Appear(userElement, {afterFinish : function()
						{
							this.elements.elementStates[userData.id] = 'active';
							
							this.checkUserAppearence(userData);
						}.bind(this)});
				}
				else if(!userData.isOnline && elementState == 'active')
				{
					this.elements.elementStates[userData.id] = 'busy';
					
					// Inactivate
					new Effect.Fade(userElement, {to : 0.25, afterFinish : function(userData)
						{
							this.elements.elementStates[userData.id] = 'inactive';
							
							this.checkUserAppearence.curry(userData).bind(this).delay(5);
						}.bind(this, userData)});
				}
				else if(!userData.isOnline && elementState == 'inactive')
				{
					this.elements.elementStates[userData.id] = 'shrinking';
					
					// Delete
					Element.setOpacity(userElement, 0.25);
					
					new Effect.Shrink(userElement, {afterFinish : function(userData)
						{	
							this.deleteUser(userData);
						
							this.checkUserAppearence(userData);
						}.bind(this, userData)});	
				}
			}
		},
		
		userDetailElement : null,
		
		handleUserHover : function(event, userData, userElement)
		{
			if(this.userDetailsTimeout != -1)
			{
				this.defferedHandleUserHover = this.handleUserHover.bind(this).curry(event, userData, userElement);
				
				return;
			}
			
			if(this.lastUserElementDetail)
				Element.removeClassName(this.lastUserElementDetail, 'hover');
			
			if(this.userDetailElement)
				Element.remove(this.userDetailElement);
				
			Element.addClassName(userElement, 'hover');
			
			this.lastUserElementDetail = userElement;
			
			this.userDetailElement = Builder.node('div', {className : 'userdetails', style : (this.userDetailsTimeout == null || this.userDetailsTimeout >= 0 ? 'display: none' : '')}, [
										Builder.node('div', {className : 'username'}, userData.username),
										Builder.node('img', {className : 'gender', src : Config.baseUrl + 'external/image/typical/chat/roomwindow/users/' + userData.gender + '.png'}),
										Builder.node('div', {className : 'age'}, userData.age + ' jaar'),
										Builder.node('div', {className : 'livingplace'}, userData.livingPlace)
									]);
			{		
				// Position
				var usersPerRow = this.getUsersPerRow();
				var rowIndex = this.elements.orderedDisplayedUsers.indexOf(userData) % usersPerRow;
				
				var left = usersPerRow - rowIndex > 2;
				
				Element.addClassName(this.userDetailElement, left ? 'left' : 'right');
				
				Element.setStyle(this.userDetailElement, {left : (left ? userElement.offsetLeft + 58 : userElement.offsetLeft - 116) + 'px',
														top : userElement.offsetTop + 'px'});

				Element.setOpacity(this.userDetailElement, 0.92);
				
				Event.observe(this.userDetailElement, 'mouseover', this.handleUserUnhover.bind(this));
			}
			Element.insert(this.elements.element, this.userDetailElement);		
		},
		
		handleUserUnhover : function()
		{
			if(!this.userDetailElement)
				return;
			
			if(this.lastUserElementDetail)
				Element.removeClassName(this.lastUserElementDetail, 'hover');
			
			Element.remove(this.userDetailElement);
			
			this.userDetailElement = null;
		},
		
		/** @todo **/
		getUsersPerRow : function()
		{
			return 4;
			
			for(var i = 0, lastY = 0; i < this.elements.orderedDisplayedUsers.length; lastY = y, i++)
			{
				var y = Element.cumulativeOffset(this.elements.elements[this.elements.orderedDisplayedUsers[i].id])[1];
				
				if(lastY != 0 && y != lastY)
					return i;
					
				lastY = y;
			}
			
			return 0;
		},
		
		handleUserClick : function(event, userData)
		{
			// @todo
			Typical.SiteWrapper.goTo('/profiel/' + userData.username);
		}
		
	});
})();
