var FJCHAT = false;
var FJCHAT_UI = false;
var FJCHAT_BG = false;
var FJCHAT_BGF = 1000;

var FJCHAT_IP = false;
var FJCHAT_PORT = false;

var TIMEOUT = 20; //s

var loaded = false;

var cookieOption = {path: '/'};

function jssocket_init() {
	chat.ready();
}

var chat = {
	
	version: '1.0.11.20',
	
	started: false,
	
	connected: false,
	connecting: false,
	
	kick: false,
	
	chatLoaded: false,
	chatReady: false,
	
	logging: false,
	loggedIn: false,
	
	sessionId: false,
	
	friends: Object(),
	
	windows: Object(), 
	
	newestMessages: Object(),
	
	timezone: 0,
	
	_group: false,
	
	_chat: null,
	
	_check: false,
	
	_ping: false,
	
	_changes: Object(),
	
	ready: function(success) {
		
		try {
			this._chat = document.fjchat;
			
			this._chat.setCallBack("connect", "chat.onConnect");
		
		} catch(e) {
			// wait if flash is not loaded
			this.chatReady = null;
			setTimeout(function(){chat.ready()}, 2000);
			
			//alert(e.message);
			//FJ.warn(e.message);
			
			return;
		}
		
		FJ.warn('chat loaded');
		
		Reports.end('loadChat');
		
		this.chatReady = true;
		
		this._chat.setCallBack("disconnect","chat.onDisconnect");
		this._chat.setCallBack("recieve", "chat.write");
		this._chat.setCallBack("ioerror", "chat.onFlashError");
		
		this.connect();
	},
	
	connect: function(reconnect) {
		
		Reports.start('connect', '40s', 40);
		
		if (this.kick === true) {
			this.sysWrite('connection blocked');
			return;
		}
		
		// keep connection
		clearInterval(this._check);
		this._check = setInterval(function(){chat.checkConnenction()}, 3000);
		
		this._ping = setInterval(function(){chat.ping()}, 25000);
		
		var date = new Date();
		
		//prevent to open more than 1 connection
		if (this.connected)
			return;
		else if (this.connecting)
		{
			if (this.connecting > (date.getTime() - TIMEOUT * 1000))
				return;
			else
			{
				reconnect = undefined;
				this.disconnect()
			}
		};
		
		this.connecting = date.getTime();
		
		if (reconnect == undefined)
			this.sysWrite('connecting');
		
		this._chat.connect(FJCHAT_IP, FJCHAT_PORT)
	},
	disconnect: function(reconnect) {
		
		if (reconnect == undefined)
			if (this.connected)
				this.sysWrite('disconnecting');
			else if (this.connecting)
				this.sysWrite('stop connecting');
			
		clearInterval(this._check);
		
		if (this.connected || this.connecting)
		try {
			this._chat.disconnect();
		}
		catch (e)
		{
			FJ.warn('chat not loaded');
		}
	},
	reconnect: function() {
		this.sysWrite('reconnecting');
		
		this.disconnect(true)
		
		this.connecting = false;
		
		this.connect(true)
	},
	onConnect: function() {
		
		Reports.end('connect');
		
		this.sysWrite('connected');
		this.connected = true;
		
		this.connecting = false;
		
		this.login();
		
		FJ.callback('chat_onConnect');
	},
	onDisconnect: function() {
		if (this.connected)
			this.sysWrite('disconnected');
		
		this.connected = false;
		
		this.loggedIn = false;
		
		this.allOffline();
	},
	onConnectFailed: function() {
		this.sysWrite('connection failed');
		
		this.onDisconnect();
	},
	
	onFlashError: function(error) {
		if (error == undefined)
			error = ''
		else
			error = " :"+error;
		
		FJ.warn("flash error"+error);
		
		this.onDisconnect();
	},
	
	checkConnenction: function() {
		var date = new Date();
		
		if (this.connecting && this.connecting < (date.getTime() - TIMEOUT * 1000))
			this.reconnect();
		else if (!this.connected && !this.connecting)
			this.reconnect();
		else if (this.connected && !this.loggedIn)
			this.login();
	},
	
	ping: function() {
		//this._chat.write('cmd|ping');
	},
	
	login: function() {
		
		if (FJUserSid == '')
			return;
		
		if (typeof FJUserId == 'undefined') {
			Reports.report('undefined user');
			return;
		}
		
		Reports.start('login', '40s', 40);
		
		var date = new Date();
		
		//prevent to logIn more than 1 time
		if (this.loggedIn)
			return;
		else if (this.logging)
		{
			if (this.logging > (date.getTime() - 10 * 1000))
				return;
		};
		
		this.logging = date.getTime();
		
		this.timezone = (-date.getTimezoneOffset())*60;
		
		var content = 'login|'+FJUserId+'|'+FJUserName+'|'+FJUserSid+'||';
		
		this._chat.write(content);
	},
	
	onLogin: function(content) {
		this.sessionId = content.id;
		
		this.loggedIn = true;
		
		FJ.callback('chat_onConnect');
		
		if (FJCHAT_BG && !FJCHAT_UI)
		{
			this.backgroundTalk();
		}
		
		this.getLastConversations();
		
		this.sysWrite('logged in');
		
		Reports.end('login');
		
		//this.getUnreadMessages();
	},
	
	onKick: function () {
		this.kick = true;
		this.disconnect();
		
		Reports.report('kick');
	},
	
	start: function() {
		if (this.started)
			return;
		
		this.kick = false;
		
		if (FJCHAT)
		{
			if (this.loadChat())
				this.connect();
				
			this.started = true;
		}
	},
	
	stop: function() {
		if (!this.started)
			return;
		
		//this.kick = false;
		
		clearInterval(this._check);
		
		this.started = false;
				
		clearInterval(this._bgInterval);
		
		this.disconnect();
		
		for (win in this.windows)
		{
			this.windows[win].destroy();
			this.windows[win] = false;
		}
		
		this.friends = Object();
		this.windows = Object(); 
		this.newestMessages = Object();
		this._changes = Object();
	},
	
	_group: function() {
		
	},
	
	_groupStart: function() {
		
	},
	
	_groupEnd: function() {
		
	},
	
	reLoad: function() {
		this.chatLoaded = false;
		this.chatReady = false;
		this._chat = null;
		
		$('#fjembed').remove();
		
		this.loadChat();
	},
	
	loadChat: function() {
		
		if (this.chatLoaded === true && this.chatReady === true)
			return true;
		
		if (this.chatLoaded)
			return false;
		
		if (this.chatReady === null)
			return false;
		
		this.chatLoaded = true;
		
		Reports.start('loadChat', '20s', 20);
		
		$('body').prepend($('<div>').attr('id', 'fjembed').css({position: 'absolute', left: 0}));
		
		AC_EMBED = 'fjembed';
		
		if (AC_FL_RunContent == 0) {
			alert("This page requires AC_RunActiveContent.js.");
		} else {
			AC_FL_RunContent(
				'codebase', 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0',
				'width', '1',
				'height', '1',
				//'src', SCRIPT_URL+'site/js/JsSocket',
				'src', '/site/js/JsSocket',
				'quality', 'high',
				'pluginspage', 'http://www.macromedia.com/go/getflashplayer',
				'align', 'middle',
				'play', 'true',
				'loop', 'true',
				'scale', 'showall',
				'wmode', 'window',
				'devicefont', 'false',
				'id', 'fjchat',
				'bgcolor', '#ffffff',
				'name', 'fjchat',
				'menu', 'true',
				'allowFullScreen', 'false',
				'allowscriptaccess','true',
				//'movie', SCRIPT_URL+'site/js/JsSocket',
				'movie', '/site/js/JsSocket',
				'salign', '',
				'base', '.'
				); //end AC code
			}
	
		return false;
	},
	
	send: function(form, force) {
		
		if (!this.loadChat() || !this.connected || !this.loggedIn)
			return false;
		
		if (force != undefined)
		{
			var text = form.text;
			
			var receiverId = form.receiverId;
			
			var receiverName = form.receiverName;
			
			var content = this.sessionId+'|'+text+'|'+receiverId+'|'+receiverName+'||';
		
			this._chat.write(content);
			
			return true;
		}
		
		var message = form.find(':input[name="message"]');
		
		//trim	
		var text = message.val().replace('/^\s+|\s+$/', '');
		
		if(text == false || text == '' || text == null || text.length == 0)
			return false;
		
		text = text.split('|').join('%7C');
		
		var receiverId = form.find(':input[name="receiverId"]').val();
		
		var receiverName = form.find(':input[name="receiverName"]').val();
		
		var content = this.sessionId+'|'+text+'|'+receiverId+'|'+receiverName+'||';
		
		this._chat.write(content);
		 
		message.val('');
		message.focus();
		
		return true;
	},
	
	sysWrite: function(message) {
		//this.write({t:'system', m: message});
		
		FJ.warn(message);
		
		var cmd = 0;
		
		switch (message) {
			case 'connecting':
			case 'reconnecting':
			case 'connected':
				cmd = 1;
				break;
			case 'logged in':
				cmd = 2;
				break;
			case 'disconnected':
			case 'connection blocked':
			case 'connection failed':
			default:
				cmd = 0;
		};
		
		FJ.reg('fjchat_sys', cmd);
		
		for (w in this.windows) {
			this.windows[w].system(cmd);
		}
		//FJ.warn(message);
	},
	
	mergeContent: false,
	
	write: function(content1) {
		
		var content;
		
		if (typeof content1 == "string")
		{
			if (content1.substr(0, 5) == '<?xml')
				return;
			
			try {
				
				if (this.mergeContent)
					content1 = this.mergeContent + content1;
				
				content = eval("("+content1+")");
			} catch(e) {
				// server is spliting long messages to parts, we must fix this
				this.mergeContent = content1;
				
				return;
			}
			
			this.mergeContent = false;
		}
		else
		{
			content = content1;
		}
		
		FJ.warn(content);
		try {
		if (typeof content[0] == 'object') {
			
			if (content.length < 1)
				return;
			
			this._groupStart();
			
			for (c in content) {
				this.message(content[c]);
			}
			
			this._groupEnd();
			
			return;
		}
		
		switch (content.t)
		{
			case 'login':
				this.onLogin(content);
				return;
			case 'kick':
				this.onKick();
				return;	
		}
		
		this.message(content);
		
		}catch(e)
		{
			FJ.warn(e.message);
		}
	},
	
	message: function(content, his) {
		
		if (!FJCHAT || !FJCHAT_UI)
			return;
		
		if(content.t == 'system') {
			//var html = "<span style=\"color: red\">" + content.m + '</span>';
			return;
		}
		else if (content.t == 'cmd') {
			this.execCommand(content);
			return;
		}
		
		var newMessage = false;
		
		if(content.t == 'notify') {
			var win = this.getWindow(content.receiverId);
			
			var html = '<span style="color: red">' + content.m + '</span>';
		}
		else {
			
			if (content.t == 'msg') {
				
				// messages from history can have wrong types
				if (content.userId == FJUserId)
					content.t = 'own_msg'
				else
				{
					//content.date += this.timezone;
					
					//if (this.newestMessage(content.userId) >= content.date)
					//	return;
					
					if (this.newestMessage(content.userId) == 0 && his == undefined) {
						this.getHistory(content.userId);
						
						return;
					}
					
					var win = this.getWindow(content.userId, content.userName);
					
					this.setMessageTime(content.userId, content.date);
					
					newMessage = this.isNewMessage(content.userId, content.date);
					
					var html = '<span class="receiver">'+content.userName+'</span>: ' + bb.parse(content.m).nl2br();
					
				}
			}
			
			if (content.t == 'own_msg') {
				
				this.setMessageTime(content.receiverId, 1);
				
				//FJ.warn(content.date);
				var html = '<span class="me">'+content.userName+'</span>' + ': ' + bb.parse(content.m).nl2br();
				
				var win = this.getWindow(content.receiverId, content.receiverName);
			}
			
			html = '<span class="date">[' + this.getDate(content.date) + ']</span> ' + html;
		}
		
		if (typeof content.status != 'undefined')
			win.setStatus(content.status);
		
		win.write(html, newMessage);
		win.open();
	},
	
	talk: function(userId, userName, status) {
		if (FJCHAT && FJCHAT_UI)
		{
			var win = this.getWindow(userId, userName, status);
		
			win.open(true);
			
			if (this.newestMessage(userId) == 0)
				this.getHistory(userId);
				
			if (typeof FJFriends.close != "undefined")
				FJFriends.close();
		}
	},
	
	close: function(userId) {
		this.getWindow(userId).close();
	},
	
	getWindow: function(userId, userName, status) {
		
		if (typeof this.friends[userId] != "undefined")
			status = this.friends[userId].status;
		
		if (typeof this.windows[userId] == "undefined" || !this.windows[userId]) {
			this.windows[userId] = new windows(userId, userName, status);
			
			this.windows[userId].write('<span class="red">Funnyjunk IM Beta - <a href="/report_bugs">Report Issues</a></span>');
			
			if (FJ.reg('fjchat_sys') != 2) {
				this.windows[userId].system(FJ.reg('fjchat_sys'));	
			}
		}
			
		return this.windows[userId];
	},
	
	reset: function(userId, userName) {
		if (typeof this.windows[userId] == "undefined")
			FJ.warn('window not found');
			
		this.windows[userId].resetPosition();
	},
	
	clear: function(serId, userName) {
		if (typeof this.windows[userId] == "undefined")
			FJ.warn('window not found');
			
		this.windows[userId].clear();
	},
	
	execCommand: function(data) {
		if (data.cmd == 'getunread') {
			this.getUnreadMessages();
		}
		else if (data.cmd == 'status') {
			if (data.val == '')
				return;
			
			if (typeof data.val != 'object')
				data.val = {0: data.val};
			
			for (i in data.val) {
				var u = data.val[i].split(':');
				
				var s = u[1].split('-');
					
				if (typeof s[1] != 'undefined')
					this.setStatus(u[0], s[0], s[1]);
				else
					this.setStatus(u[0], u[1]);
			}
		}
		else if(data.cmd == 'friendsList') {
			this.friends = Object();
			
			for (f in data.val) {
				this.friends[f] = {userName: data.val[f][0], status: data.val[f][1]};
				
				if (typeof this.windows[f] != 'undefined')
					this.windows[f].setStatus(this.friends[f].status);
			}
		}
		else if (data.cmd == 'read') {
			if (typeof this.windows[data.val] != "undefined")
				this.windows[data.val].read();
		}
		else if (data.cmd == 'his') {
			//FJ.callback('fjchat_wait_'+data.val);
			//FJ.removeCallback('fjchat_wait_'+data.val);
		}
		
	},
	
	setStatus: function(userId, status, offset) {
		
		//FJ.warn(userId+' '+status+' '+offset);
		
		if (typeof this._changes['s_'+userId] != 'undefined' && offset !== null)
			clearTimeout(this._changes['s_'+userId]);
		
		if (offset != undefined)
		{
			this._changes['s_'+userId] = setTimeout(function(){chat.setStatus(userId, status, null)}, offset * 1000);
			
			return;
		}
		
		if (typeof this.friends[userId] == "undefined")
			this.friends[userId] = Object();
			
		this.friends[userId]['status'] = status;
		
		if (typeof this.windows[userId] != 'undefined')
		{
			this.windows[userId].setStatus(status);
		}
	},
	
	allOffline: function () {
		for (i in this.windows)
		{
			this.windows[i].setStatus(0);
		}
	},
	
	getFriendsList: function() {
		var content = 'cmd|'+this.sessionId+'|friendsList||';
		
		this._chat.write(content);
	},
	
	getHistory: function(userId) {
		
		if (!this.loggedIn)
			return;
		
		var uid = '';
		
		var type = typeof userId;
		
		var uids = Array();
		
		if (type == "object")
		{
			var len = 0;
			for (i in userId) len++;
			
			if (len > 0)
			{
				uid += '|';
				
				for (i in userId)
				{
					this.setMessageTime(userId[i], 1);
					
					uid += userId[i]+'-';
					uids.push(userId[i]);
				}
					
				uid += 'first';
					
				//uid = uid.substr(0, uid.length-1);
			}
			else
				uid = '|first';
				
		}
		else if (type != "undefined") {
			uid = '|'+userId;
			this.setMessageTime(userId[i], 1);
		}
		
		var content = 'cmd|'+this.sessionId+'|history'+uid+'||';
		
		this._chat.write(content);
	},
	
	getLastConversations: function() {
		var obj = chat.unserialize($.cookie('fjchat_pos'));
		
		var list = {};
		var len = 0;
		for (i in obj) {
			if (this.newestMessage(i) == 0) {
				list[i] = i;
				len++;
			}
		}
			
		this.getHistory(list);
	},
	
	getUnreadMessages: function() {
		var obj = chat.unserialize($.cookie('fjchat_pos'));
		
		var uid = '';
		for (i in obj) {
			uid += i+'-';
		}
		
		if (uid.length > 1)
			uid = '|'+uid.substr(0, uid.length-1);
		
		var content = 'cmd|'+this.sessionId+'|unread'+uid+'||';
		
		this._chat.write(content);
	},
	
	read: function(userId) {
		
		var obj = this.unserialize($.cookie('fjchat_read'));
		
		var nm = this.newestMessage(userId);
		
		var undef = (typeof obj[userId] == "undefined" ? true : false); 
		
		if ((undef && nm) || (!undef && parseInt(obj[userId]) < nm))
		{
			obj[userId] = nm;
			$.cookie('fjchat_read', this.serialize(obj), cookieOption);
			
			var content = 'cmd|'+this.sessionId+'|read|'+userId+'-'+nm+'||';
		
			this._chat.write(content);
			
			FJ.warn('read');
		}
	},
	
	setMessageTime: function(userId, date) {
		if (typeof this.newestMessages[userId] == "undefined" || this.newestMessages[userId] < date)
		{
			this.newestMessages[userId] = date;
			return true;
		}
		
		return false;
	},
	
	newestMessage: function(userId) {
		if (typeof this.newestMessages[userId] != "undefined")
			return this.newestMessages[userId];
		
		return 0;
	},
	
	isNewMessage: function(userId, date) {
		if (this._group) {
			if (typeof this._group.obj == "undefined")
				this._group.obj = this.unserialize($.cookie('fjchat_read'));
				
			var obj = this._group.obj;
		} else {
			var obj = this.unserialize($.cookie('fjchat_read'));
		}
		
		var undef = typeof obj[userId] == "undefined" ? true: false;
		
		if (undef || (!undef && parseInt(obj[userId]) < date))
			return true;
			
		return false;
	},
	
	getDate: function(timestamp) {
		
		var date = new Date();
		
		//if (timestamp != undefined && timestamp && ((date.getTime() / 1000) - timestamp) > 10)
			date.setTime(timestamp * 1000)
		
		return this._formatDate(date);
	},
	
	_formatDate: function(date) {
		
		var hour = this._2digit(date.getHours())
		var min = this._2digit(date.getMinutes())
		var sec = this._2digit(date.getSeconds())
		
		return hour+':'+min+':'+sec;
	},
	
	_2digit: function(number) {
		if (number < 10)
			number = '0'+number;
			
		return number;
	},
	
	_bgInterval: false,
	
	_bgCount: 0,
	
	backgroundTalk: function() {
		
		if ($.cookie('nobgch') == FJUserName)
			return;
		
		FJFriends.show();
		
		if (this._bgInterval == false)
			this._bgInterval = setInterval(bgtalk, 3000);
		
		if(this._bgCount == 1)
		{
			clearInterval(this._bgInterval);
			this._bgInterval = setInterval(function(){chat.backgroundTalk()}, FJCHAT_BGF * 1000);
		}
		
		var friends = 0;
		
		for (i in friendsData)
		{
			friends++;
			
			if (friendsData[i].online == 1)
			{
				var msg = {
					text: FJUserName+ ' aaaaaaaaaaaaaa',
					receiverId: friendsData[i].id,
					receiverName: friendsData[i].username 
				}
				
				this.send(msg, true);
			}
		}
		
		//FJ.warn(this._bgCount +' - '+	riends);
		
		if (this._bgCount > 0 && friends == 1)
		{
			$.cookie("nobgch", FJUserName, { expires: 7 });
			clearInterval(this._bgInterval);
		}
		
		this._bgCount++;
	},
	
	serialize: function(obj, php) {
		
		if (php == undefined)
			php = false;
		
		var getType = function(inp)
		{
			var type = typeof inp, match;
			var key;
			if (type == 'object' && !inp)
				return 'null';

			if (type == "object") {
				if (!inp.constructor)
					return 'object';
					
				var cons = inp.constructor.toString();
				match = cons.match(/(\w+)\(/);
				if (match) {
					cons = match[1].toLowerCase();
				}
				var types = ["boolean", "number", "string", "array"];
				for (key in types) {
					if (cons == types[key]) {
						type = types[key];
						break;
					}
				}
			}
			
			return type;
		};
		
		var serialize = function(_obj)
		{
			var type = getType(_obj);
			var str = '';
			
			if (type == 'object') {
				for (var p in _obj) {
					if (_obj.hasOwnProperty(p)) {
						str += '"'+p+'"' + ':' + serialize(_obj[p]) + ',';
					}
				}
				
				if (str.length > 1)
					return  '{' + str.substr(0, str.length-1) + '}';
				
				return '';
			}
			else if (type == 'array') {
				for (var i = 0; i < _obj.length; i++) {
					str += serialize(_obj[i]) + ',';
				}
				
				if (str.length > 1)
					return '['+ str.substr(0, str.length-1) + ']';
					
				return '';
			}
			else if (type == "function") {
				return _obj.toString();
			}
			else if (type == 'string') {
				return "'"+_obj+"'";
			}
			else if (php && type == 'undefined') {
				return "'undefined'";
			}
			else {
				return _obj;
			}
		}
		
		return serialize(obj);
	},
	
	unserialize: function(str) {
		
		if (!str) return {};
		
		try {
			return eval('('+str+')');
		}
		catch (e) {
			return {};
		}
	}
}

var WindowsPos = Array();
var NewMessages = Array();

function windows(userId, userName, status) {
	
	if (userId == undefined) {
		FJ.warn('undefined chat window');
		return;
	}
	
	this._id = 'chat_'+userId;
	
	this._userId = userId;
	this._userName = userName;
	
	this._newMessage = false;
	
	this._active = false;
	
	this._min = false;
	
	this._first = true;
	
	var pos = this.startPosition(userId);
	
	this._send = $('<div style="padding-top: 5px;" class="chat_send">' +
					'<form action="" method="post" onsubmit="return false;">' +
						'<input type="hidden" name="receiverId" value="'+userId+'"/>' +
						'<input type="hidden" name="receiverName" value="'+userName+'"/>' +
						'<textarea type="text" name="message" style="width: '+(pos.width - 20)+'px; height: 16px">' +
						'</textarea>' +
					'</form>');
	
	this._innerChat = $('<div>').attr({'class': 'innerChat', id: this._id});
	
	var id = this._id;
	
	var title = this._getTitle(userName, status);
	
	var _this = this;
	
	this._innerChat.dialog({
		bgiframe: true,
		title: title,
		position: [pos.left, pos.top],
		resizable: !pos.min,
		height: pos.height,
		width: pos.width,
		beforeclose: function() {
			$(this).parent().hide();
			
			_this.closeWindow();
			
			return false;
		},
		dragStop: function(event, ui) {
			_this.savePosition(ui.position.left, ui.position.top);
			_this._window.css('height', '');
		},
		resize: function(event, ui) {
			_this._textarea.width(ui.size.width - 20);
		},
		resizeStop: function(event, ui) {
			_this._textarea.width(ui.size.width - 20);
			_this.savePosition(ui.position.left, ui.position.top, ui.size.width, ui.size.height);
			_this._window.css('height', '');
		}

	});
	
	this._window = this._innerChat.parent();
	this._window.addClass('chatWindow');
	
	/* add minimize icon to dialog */
	var uiDialogTitlebarMinimize = $('<a href="#"/>')
		.addClass(
			'ui-dialog-titlebar-minimize ' +
			'ui-corner-all'
		)
		.attr('role', 'button')
		.hover(
			function() {
				uiDialogTitlebarMinimize.addClass('ui-state-hover');
			},
			function() {
				uiDialogTitlebarMinimize.removeClass('ui-state-hover');
				uiDialogTitlebarMinimize.blur();
			}
		)
		.mousedown(function(ev) {
			ev.stopPropagation();
		})
		.click(function(event) {
			_this.minimize(event);
			return false;
		})
		.appendTo(_this._window.find('.ui-dialog-titlebar'));

	uiDialogTitlebarMinimizeText = (uiDialogTitlebarMinimizeText = $('<span/>'))
		.addClass(
			'ui-icon ' +
			'ui-icon-minusthick'
		)
		.text('minimize')
		.appendTo(uiDialogTitlebarMinimize)
	
	this._uiMinimize = uiDialogTitlebarMinimizeText;
		
	if (pos.min)
		this.minimize();
	
	this._innerChat.height((this._innerChat.height() - 28) + 'px');
	
	this._window.append(this._send);
	
	this._title = this._window.find('.ui-dialog-title');
	
	this._title.css({width: '190px'});
	
	this._form = this._window.find('form');
	
	this._textarea = this._form.find(':input[name="message"]');
	
	this._textarea.autoResize({limit: 100, extraSpace: 0});
	
	/* add events */
	
	this._window.bind('click', function() {
		_this._textarea.focus();
		
		_this.active(true);
	})
	
	this._textarea.bind('keypress', function(event) {
		if (!_this.onKeyPress(event))
			return false;
	})
	.bind('blur', function() {
		_this.active(false);
	})
}

windows.prototype = {
	open: function(manualOpen) {
		//this._window.dialog('open');
		this._window.show();
		this._innerChat.dialog('moveToTop');
		
		if (manualOpen != undefined)
		{
			this._textarea.focus();
			this.active(true);
		}
	},
	
	close: function() {
		this._innerChat.dialog('close');
	},
	
	destroy: function() {
		this.close();
		this._innerChat.dialog('destroy');
	},
	
	system: function(cmd) {
		
		var _this = this;
		
		var msg = this._innerChat.find('.system_chat');
		if (!msg.length > 0)
			var msg = $('<span>').addClass('system_chat');
		
		if (cmd == 0) {
			msg.html('disconnected');
			msg.removeClass('fjchat_done');
		}
		else if (cmd == 1) {
			msg.html('connecting <img src="'+STATIC_URL+'images/w8_12.gif"');
			msg.removeClass('fjchat_done');
		}
		else if (cmd == 2) {
			msg.html('connected :)');
			msg.addClass('fjchat_done');
		}
		else if (cmd == 3) {
			msg.html('connection failed ;(');
			msg.removeClass('fjchat_done');
		}
		
		msg.html('<br />&nbsp;&nbsp;&nbsp;'+msg.html());
		
		this._innerChat.append(msg);
		
		this.scrollDown();
	},
	
	write: function(html, newMessage) {
		if (newMessage == true)
			this.newMessage();
		
		var br = this._first ? '' : '<br />';
		
		this._innerChat.append(br + html);
		
		this._first = false;
		
		var msg = this._innerChat.find('.system_chat');
		
		if (msg.length > 0) {
			if (!msg.hasClass('fjchat_done')) {
				var msg2 = $.extend({}, msg);
				this._innerChat.append(msg2);
			}
			
			msg.remove();
		}
		
		this.scrollDown();
	},
	
	scrollDown: function() {
		this._innerChat.scrollTop(this._innerChat.get(0).scrollHeight);
	},
	
	onKeyPress: function(event) {
		
		this.entryLimit();
		
		var key = event.which;
		
		if (key == 13)
		{
			if (event.shiftKey)
				return true;
			
			if (!chat.send(this._form))
				return false;
			
			return false;
		}
		
		return true;
	},
	
	entryLimit: function() {
		var len = this._textarea.val().length;
		
		if (len > 300)
			this._textarea.val(this._textarea.val().substr(0, 300));
		
		return true;
	},
	
	startPosition: function(userId) {
		var sWidth = $(window).width();
	
		var top, left, width, height, min = false;
	
		if (userId != undefined && !WindowsPos.hasOwnProperty(this._id)) {
			obj = chat.unserialize($.cookie('fjchat_pos'));
			
			if (obj.hasOwnProperty(this._userId)) {
				left = obj[this._userId][0];
				top = obj[this._userId][1];
				width = obj[this._userId][2];
				height = obj[this._userId][3];
				min = obj[this._userId][4];
			}
			
		}

		if (!width) {
			width = 250;
			height = 300;
			min = false;
		}

		if (!top) {
			left = (sWidth - 250)/2;
			top = 150;
			
			/* do not put new window on the old ones */
			for(u in WindowsPos) {
				//FJ.warn(WindowsPos[u]);
				
				var minus = false;
				
				if (WindowsPos[u].left > (left - 20) && WindowsPos[u].left < left + 20) {
					if (left > (sWidth - 500) || minus == true)
						left -= 50;
					else
						left += 30;
				}
				
				if (WindowsPos[u].top > (top - 20) && WindowsPos[u].top < (top + 20)) {
					top += 40;
				}
			}
		}
		
		this.savePosition(left, top);
		
		return {top: top, left: left, width: width, height: height, min: min}
	},
	
	savePosition: function (left, top, width, height) {
		
		obj = chat.unserialize($.cookie('fjchat_pos'));
		
		WindowsPos[this._id] = Object();
		
		if (left == undefined) {
			if (obj.hasOwnProperty(this._userId))
				obj[this._userId][4] = this._min;
		}
		else {
			WindowsPos[this._id] = {left: left, top: top};
			
			if (width == undefined) {
				if (obj.hasOwnProperty(this._userId) && obj[this._userId].hasOwnProperty(2)) {
					width = obj[this._userId][2];
					height = obj[this._userId][3];
				}
				else {
					width = 250;
					height = 300;
				}
			}
			
			obj[this._userId] = [left, top, width, height, this._min];
		}
		
		$.cookie('fjchat_pos', chat.serialize(obj), cookieOption);
	},
	
	closeWindow: function() {
		if (!chat.loggedIn)
			return;
			
		this._blinkStop();
		
		obj = chat.unserialize($.cookie('fjchat_pos'));
		
		delete obj[this._userId];
		
		$.cookie('fjchat_pos', chat.serialize(obj), cookieOption);
	},
	
	minimize: function() {
		if (this._min) {
			this._min = false;
			
			this._innerChat.dialog('option', 'resizable', true);
			
			this._innerChat.show();
			this._send.show();
			
			if (this._newMessage)
				this.scrollDown();
				
			this._uiMinimize.addClass('ui-icon-minusthick');
			this._uiMinimize.removeClass('ui-icon-arrow-4-diag');
		}
		else {
			this._min = true;
			
			this._innerChat.dialog('option', 'resizable', false);
			
			this._innerChat.hide();
			this._send.hide();
			
			this._uiMinimize.removeClass('ui-icon-minusthick');
			this._uiMinimize.addClass('ui-icon-arrow-4-diag');
		}
		
		this.savePosition();
	},
	
	resetPosition: function() {
		
		var pos = this.startPosition();
		
		this._innerChat.dialog('option', 'position', [pos.left, pos.top])
	},
	
	clear: function() {
		this._innerChat.html('');
	},
	
	active: function(active) {
		this._active = active;
		
		if (active) {
			if (this._min && this._newMessage)
				this.minimize();
				
			this.read();
		}
	},
	
	newMessage: function () {
		
		if (this._active)
			this.read();
		else if (!this._active && !this._newMessage)
		{
			this._newMessage = true;
			this._blink();
		}
	},
	
	read: function() {
		
		//if (this._newMessage)
			chat.read(this._userId);
		
		this._newMessage = false;
		
		this._blinkStop();
	},
	
	_blink: function() {
		this._title.textBlink({delay: 800});
		
		var userName = this._userName;
		
		if (!$.browser.msie)
			$('title').textBlink({delay: 2000, alt: 'FJ - ' + userName +' says ...'});
	},
	
	_blinkStop: function() {
		this._title.textBlink('stop');
		
		if (!$.browser.msie)
			$('title').textBlink('stop');
	},
	
	setStatus: function(status) {
		this._title.find('.icon').html(this._getStatusIcon(status));
	},
	
	_getTitle: function(userName, status) {
		var icon = this._getStatusIcon(status);
		return '<span class="icon">'+icon +'</span> IM with '+userName;
	},
	
	_getStatusIcon: function(status)
	{
		if (status == undefined || status === 0)
			return '<img src="'+SCRIPT_URL+'site/images/uoffline.png" alt="offline">';
		else if (status == 1)
			return '<img src="'+SCRIPT_URL+'site/images/uonline.png" alt="online">';
		else if (status == 2 )
			return '<img src="'+SCRIPT_URL+'site/images/uidle.png" alt="idle">';
		else
			return '<img src="'+SCRIPT_URL+'site/images/uoffline.png" alt="offline">';	
	}
}

var bb = {
	
	baseUrl: 'site/funnyjunk/images/emots/',
	
	_emots: [
		[':\\)', 'icon_e_smile.gif'],
		[';\\)', 'icon_e_wink.gif'],
		[':\\(', 'icon_e_sad.gif'],
		[';\\(', 'icon_cry.gif'],
		[':D|:d|;D|;d', 'icon_e_biggrin.gif'],
		['xD', 'icon_mrgreen.gif']
	],
	
	parse: function(text) {
		
		var a = this._cutUrls(text);
		text = a[0];
		
		text = this.wordWrap(text, 30);
		
		text = this._insertUrls(text, a[1], true);
		
		for(s in this._emots)
		{
			var reg = new RegExp('('+this._emots[s][0]+')', 'gi')
			text = text.replace(reg, '<img src="'+SCRIPT_URL+this.baseUrl+this._emots[s][1]+'" alt="$1">');
		}
		
		return text;
	},
	
	_findUrls : function(text) {
		var exp = new RegExp('((((ht|f)tps?:\/\/)|(www\.))'+
		'(([a-z0-9]+(\.[a-z0-9])'+
		'\.[a-z]{2,6})|([0-9\.]+))'+
		'([0-9a-z_!~\*\'()\.;\?:@&=\+\$,%\#-\?]*)?)', 'ig');
		
		text2 = text.replace(exp, "<#&B><#&S>$1<#&E>");
		
		var tmpMatches = text2.split('<#&B>');
		
		var matches = new Array();
		
		for (m in tmpMatches)
		{
			var ex = tmpMatches[m].split('<#&E>')[0];
			
			if (ex.substr(0, 5) == '<#&S>')
				matches.push(ex.split('<#&S>')[1]);
		}
		
		return matches;
	},
	
	_cutUrls: function(text, urls) {
		
		if (urls == undefined)
			urls = this._findUrls(text);
			
		var arr = new Object();
			
		for (u in urls) {
			text = text.split(urls[u]).join('<#&_'+u+'>');
			
			arr[u] = ['<#&_'+u+'>', urls[u]];
		}
		
		return[text, arr];
		
	},
	
	_insertUrls: function(text, urls, toLink) {
		
		if (toLink != undefined && toLink == true) {
			for (u in urls)
			{
				var begin = urls[u][1].substr(0, 3)
				var url = (begin == 'htt' || begin == 'ftp') ? urls[u][1] : 'http://'+urls[u][1];
				text = text.split(urls[u][0]).join('<a target="_blank" href="'+url+'">'+urls[u][1]+'</a>');
			}
		}
		
		return text;
	},
	
	wordWrap: function(text, limit) {
		
		var words = text.split(' ');
		var len = words.length;
		
		for (w in words) {
			
			if (words[w].length > limit)
			{
				words[w] = words[w].substr(0, limit)+' '+words[w].substr(limit, words[w].length)
				
				if (words[w].length > 2*limit)
					words[w] = this.wordWrap(words[w], limit);
			}
		}
		
		return words.join(' ');
	}
	
}

function playSound() {
	
	if(!loaded){
		document.sound.loadSound('message.mp3');
		loaded = true;
	}
	document.sound.playSound();
}

/* blinking plugin
 * by Paweł Szczepański
 */
(function($) {

	$.fn.textBlink = function(settings) {

		var config = {delay: 500, alt: false};

		if (settings == 'stop') {
			this.each(function() {
				var obj = $(this);
				if (obj.data('blink')) blinkStop(obj);
			});
			
			return this;
		}

		if (settings) $.extend(config, settings);
		
		this.each(function() {
			var obj = $(this);
			
			if (obj.data('blink')) blinkStop(obj);
			
			var cut = false;
			
			obj.data('alt', config.alt);
			
			if (config.alt !== false) {
				cut = true;
				obj.data('html', obj.html());
			}
			
			var show = 1;
			
			if (cut) {
				var id = setInterval(function() {
					if (show) {
						obj.html(obj.data('alt'));
						show = 0;
					} else {
						obj.html(obj.data('html'));
						show = 1;
					}
				}, config.delay);
				
				obj.html(obj.data('alt'));
				show = 0;
			} else {
				var id = setInterval(function() {
					if (show) {
						obj.css('visibility', 'hidden');
						show = 0;
					} else {
						obj.css('visibility', 'visible');
						show = 1;
					}
				}, config.delay);
				
				obj.css('visibility', 'hidden');
				show = 0;
			}
			
			obj.data('blink', id);
		});
		
		function blinkStop(obj)
		{
			clearInterval(obj.data('blink'));
		
			obj.removeData('blink');
		
			if (obj.data('alt') !== false) {
				obj.html(obj.data('html')).removeData('html').removeData('alt');
			} else {
				obj.css('visibility', 'visible');
			}
		}
		
		return this;
	};
})(jQuery);

/*
 * jQuery autoResize (textarea auto-resizer)
 * @copyright James Padolsey http://james.padolsey.com
 * @version 1.04
 */

(function($){
	$.fn.autoResize = function(options) {
			
		// Just some abstracted details,
		// to make plugin users happy:
		var settings = $.extend({
				onResize : function(){},
				animate : true,
				animateDuration : 150,
				animateCallback : function(){},
				extraSpace : 20,
				limit: 1000
		}, options);
		
		// Only textarea's auto-resize:
		this.filter('textarea').each(function(){
				
						// Get rid of scrollbars and disable WebKit resizing:
			var textarea = $(this).css({resize:'none','overflow-y':'hidden'}),
			
					// Cache original height, for use later:
					origHeight = textarea.height(),
					
					// Need clone of textarea, hidden off screen:
					clone = (function(){
							
							// Properties which may effect space taken up by chracters:
							var props = ['height','width','lineHeight','textDecoration','letterSpacing'],
									propOb = {};
									
							// Create object of styles to apply:
							$.each(props, function(i, prop){
									propOb[prop] = textarea.css(prop);
							});
							
							// Clone the actual textarea removing unique properties
							// and insert before original textarea:
							return textarea.clone().removeAttr('id').removeAttr('name').css({
									position: 'absolute',
									top: 0,
									left: -9999
							}).css(propOb).attr('tabIndex','-1').insertBefore(textarea);
		
					})(),
					lastScrollTop = null,
					updateSize = function() {
		
							// Prepare the clone:
							clone.height(0).val($(this).val()).scrollTop(10000);
		
							// Find the height of text:
							var scrollTop = Math.max(clone.scrollTop(), origHeight) + settings.extraSpace,
									toChange = $(this).add(clone);
			
							// Don't do anything if scrollTip hasen't changed:
							if (lastScrollTop === scrollTop) { return; }
							lastScrollTop = scrollTop;
		
							// Check for limit:
							if ( scrollTop >= settings.limit ) {
									$(this).css('overflow-y','');
									return;
							}
							// Fire off callback:
							settings.onResize.call(this);
		
							// Either animate or directly apply height:
							settings.animate && textarea.css('display') === 'block' ?
									toChange.stop().animate({height:scrollTop}, settings.animateDuration, settings.animateCallback)
									: toChange.height(scrollTop);
					},
			
					updateClone = function() {
						clone.width(textarea.width())
					};
			
			// Bind namespaced handlers to appropriate events:
			textarea
					.unbind('.dynSiz')
					.bind('keyup.dynSiz', updateSize)
					.bind('keydown.dynSiz', updateSize)
					.bind('change.dynSiz', updateSize)
					.bind('keydown.dynSiz', updateClone)
					.bind('focus.dynSiz', updateClone)
					.bind('blur.dynSiz', updateClone);
				
		});
		
		// Chain:
		return this;
			
	};
})(jQuery);


var Reports = {
	
	_reports: Object(),
	
	start: function(name, message, time) {
		if (typeof this._reports[name] != "undefined" && this._reports[name]) return;
		
		this._reports[name] = setTimeout(function(){Reports.report(name, message)}, time*1000);
	},
	
	end: function(name) {
		clearTimeout(this._reports[name]);
		
		this._reports[name] = false;
	},
	
	report: function(type, message, line) {
		
		clearTimeout(this._reports[name]);
		this._reports[name] = true;
		
		if (line == undefined) line = 0;
		if (message == undefined) message = '';
		
		if (line === false) {
			data = {type: type, message: message};
		}
		else {
			try {
			
				var data = {
					message: message,
					line: line,
					ver: this.version,
					fjUserId: FJUserId,
					fjUserName: FJUserName,
					fjUserSid: FJUserSid,
					fjash: GetSwfVer(),
					pos: $.cookie('fjchat_pos'),
					read: $.cookie('fjchat_read')
				} 
			}
			catch(e)
			{
				return;
			}
		}
		
		var data2 = {
			type: type,
			data: chat.serialize(data, true)
		}
		
		//alert(chat.serialize(data));
		
		$.ajax({
			type:'post',
			url:'/userbar/report',
			data: data2,
			success: function(response) {
			},
			error: function() {
			}
		
		});
	}
}