global_context = {}

global_context.session_id = null;
global_context.first_connect = true;
global_context.prev_time = null;
global_context.nick = "";
global_context.roster = [];
global_context.history_list = [];
global_context.history_index = -1;
global_context.ignored_users = [];
global_context.ac_input = null;
global_context.ac_index = 0;
global_context.tab_highlighted = true;

config = {}
config.smilies = {
	'0:-)':  '/media/angel.png',
	':)':    '/media/smile.png',
	':-)':   '/media/smile.png',
	';)':    '/media/wink.png',
	';-)':   '/media/wink.png',
	':(':    '/media/sad.png',
	':-(':   '/media/sad.png',
	':D':    '/media/smile-big.png',
	':-D':   '/media/smile-big.png',
	'>:-)':  '/media/devil.png',
	'B-)':   '/media/glasses.png',
	'8-)':   '/media/glasses.png',
	':-*':   '/media/kiss.png',
	':-(|)': '/media/monkey.png',
	':-|':   '/media/plain.png',
	':-0':   '/media/surprise.png',
	':-O':   '/media/surprise.png',
	':-o':   '/media/surprise.png',
	':b':    '/media/tongue.png',
	':-b':   '/media/tongue.png',
	':p':    '/media/tongue.png',
	':-p':   '/media/tongue.png'

};

for (key in config.smilies) {
  config.smilies[key.split("").reverse().join("")] = config.smilies[key];
}

config.smilies['\'<'] = '/media/pacman.png';
 

Array.prototype.filter = function(func) {
	var ret = [];
	for (var n=0; n<this.length; n++) {
	  if (func(this[n])) { ret.push(this[n]) }
	}
	return ret;
}

Array.prototype.contains = function(v) {
  for (var n=0, e; e=this[n]; n++) {
    if (e==v) { return true }
  }
  return false;
}

Array.prototype.remove = function(v) {
  for (var n=0, e; e=this[n]; n++) {
    if (e==v) { this.splice(n, 1) }
  }
}

global_context.keepalive_timer = null;
function update_keepalive() {
	clearTimeout(global_context.keepalive_timer);
	global_context.keepalive_timer = setTimeout( server_reconnect, 1000 * 180);
}

function server_reconnect() {
	location.reload();
}

onload = function() {
	var event_ele = document.getElementById('chat');
	event_ele.addEventListener('new_chat', new_chatline, false);
	event_ele.addEventListener('chat_image', new_image, false);
	event_ele.addEventListener('user_gone', user_disconnect, false);
	event_ele.addEventListener('sessionid', store_session_id, false);
	event_ele.addEventListener('connect', user_connect, false);
	event_ele.addEventListener('status', status_message, false);

	/* Add keepalive events */
	event_ele.addEventListener('new_chat', update_keepalive, false);
	event_ele.addEventListener('chat_image', update_keepalive, false);
	event_ele.addEventListener('user_gone', update_keepalive, false);
	event_ele.addEventListener('sessionid', update_keepalive, false);
	event_ele.addEventListener('connect', update_keepalive, false);
	event_ele.addEventListener('status', update_keepalive, false);
	event_ele.addEventListener('ping', update_keepalive, false);

	document.getElementById("chat-input").addEventListener("keypress", function(event) {
			if((event.keyCode == 13 /*Enter*/) && (event.shiftKey == false)) {
				send_chatline();
			} else if ( event.keyCode == 38 ) {
				// up key
				set_text_from_history(1);
			} else if ( event.keyCode == 40 && (event.shiftKey != true)) {
				// down key
				set_text_from_history(-1);
			} else if ( event.keyCode == 9 ) {
				// tab key
				autocomplete_update();
				return false;				
			} else {
				global_context.ac_input = null;
		  }
		}, false);

	window.addEventListener('blur', function() { global_context.tab_highlighted = false }, false);
	window.addEventListener('focus', function() { global_context.tab_highlighted = true }, false);

	document.getElementById("chat-input").focus();
	blinking_dots();
	fixLayout();

  if ( (slash = window.location.toString().lastIndexOf("/")) > -1 ) {
    global_context.nick = window.location.toString().slice(slash+1);
  }
  
}

window.onresize = function() {
	fixLayout();
	var cc = document.getElementById("chat-area");
	cc.scrollTop = cc.scrollHeight + 500;
}

function decode_data(data) {
	if(!data) {
		return "";
	}
	try {
		return decodeURIComponent(data);
	} catch(e) {
		return "IV";
	}
}

function store_session_id(event) {
	global_context.session_id = event.data.split("\n")[0];
	document.getElementById("status").style.display = "none";
	add_chat_message("status", "", "status-message", "Started talking on " + (new Date).toString());
}

function status_message(event) {
	data = event.data.split("\n");
	message = data[0]
	add_chat_message("status", "", "status-message", message);
}

function create_date_element() {
	var current_date = new Date();
	var date_ele = document.createElement("td");
		date_ele.appendChild(document.createTextNode( padZero(current_date.getHours()) +
		":" + padZero(current_date.getMinutes())));
	if( global_context.prev_time == null
			|| (global_context.prev_time.getHours() != current_date.getHours()) 
			|| (global_context.prev_time.getMinutes() != current_date.getMinutes())) {
		date_ele.className = "time";
	} else {
		date_ele.className = "old-time";
	}
	global_context.prev_time = new Date();
	return date_ele;
}

function add_chat_message(type, type_content, message, message_content) {

	var time_ele = create_date_element();
	var nick_ele = document.createElement("td");
	nick_ele.className = type;
	nick_ele.appendChild( document.createTextNode(decode_data(type_content)) );

	var chat_content = document.createElement("td");
	chat_content.className = message;
	var span_ele = document.createElement("span")
	if (decode_data(type_content) == global_context.nick) {
		chat_content.className += " own-message";
	}


	var words = decode_data(message_content).split(' ');
	words = words.filter(function(s) { return s!=""  });

	formatter_url(words);
	formatter_smilies(words);
	formatter_nick(words);

	var curstr = null;
	for (var n=0, e; e=words[n]; n++) {
		if ( typeof e == "string" ) {
			curstr = (curstr ? curstr+=e : e) + " " ;
		} else {
			if (curstr) {
				span_ele.appendChild(document.createTextNode(curstr));
				curstr = null;
			}
			span_ele.appendChild(e);
			curstr = " ";
		}
	}

	if (curstr && curstr != " ") {
		span_ele.appendChild(document.createTextNode(curstr));
	}
	chat_content.appendChild( span_ele );

	var chat_ele = document.createElement("tr");
	chat_ele.appendChild(time_ele);
	chat_ele.appendChild(nick_ele);
	chat_ele.appendChild(chat_content);

	var cc = document.getElementById("chat-area");
	
	if (cc.childNodes.length > 200) {
		cc.removeChild(cc.firstChild);
	}

	cc.appendChild(chat_ele);
	document.body.id = document.body.id; // forces reflow. workaround for reflow bugs
	cc.scrollTop = cc.scrollHeight + 500;
	give_notification();
}

function user_is_ignored(username) {
	return global_context.ignored_users.contains(username);
}

function ignore_user(event) {
	var username =  this.firstChild.nodeValue;
	var new_list = [];
	if(user_is_ignored(username)) {
		for(var i=0; i<global_context.ignored_users.length;  i++) {
			if(global_context.ignored_users[i] != username) {
				new_list.push(username);
			}
		}
		global_context.ignored_users = new_list;
		this.style.background = "transparent url('http://people.opera.com/sverrej/ssechat/face-smile.png') no-repeat 0 50%";
		
	} else {
		this.style.background = "transparent url('http://people.opera.com/sverrej/ssechat/dialog-error.png') no-repeat 0 50%";
		global_context.ignored_users.push(this.firstChild.nodeValue);
	}
}

function new_chatline(event) {
	var data = event.data.split("\n");
	var username = data[0];
	var message = data[1];

	if(user_is_ignored(username)) {
		return;
	}
	add_chat_message("sender", username, "sender-message", message);	
}

function new_image(event) {
	var data = event.data.split("\n");
	add_chat_message("image", data[0], "image-message", data[1]);
}

function user_disconnect(event) {
	var username = decode_data(event.data.split("\n")[0]);
  global_context.roster.remove(username);
	var users = document.getElementById("user-list").getElementsByTagName("li");
	var i;
	for(i=0; i<users.length; i++) {
		if( users[i].name == username) {
			users[i].parentNode.removeChild( users[i] );

			/* Don't get any messages before session id */
			if(global_context.session_id != null) {
				add_chat_message("disconnect", "", "disconnect-message", "<- " + username + " has disconnected");
			}
			return;
		}
	}

}

function existing_nick(nick) {
  return global_context.roster.contains(nick);
}


function user_connect(event) {

	var usernames = event.data.split("\n");
	var i;
	for(i=0; i<usernames.length; i++) {
		var username = decode_data(usernames[i]);
		if(existing_nick(username)) {
			continue;
		}
		
		if((username == "") && (username == " ")) {
			continue;
		}
		
		global_context.roster.push(username);
		if (!global_context.first_connect) {
      add_to_nicklist(username);
    }

		// Don't get any messages before session id
		if((global_context.session_id != null)	&& (global_context.first_connect == false)) {
			add_chat_message("join", "", "join-message", "-> " + username + " has joined");
		}
	}
  
  if (global_context.first_connect) {
    render_nicklist();
  	global_context.first_connect = false;  
  }


}

function render_nicklist() {
	var roster = document.getElementById("user-list");
	var users = global_context.roster.sort(function(a,b) {
    a = a.toLowerCase();
    b = b.toLowerCase();
    if (b>a) { return -1 }
    else if (a>b) { return 1 }
    else { return 0 }
  })  ;

    while (roster.firstChild) { roster.removeChild( roster.firstChild ) }

    for (var n=0, e; e=users[n]; n++) {
      roster.appendChild(create_nickelement(e));
    }
}

function add_to_nicklist(e) {
    render_nicklist()
  	return;
}

function create_nickelement(e) {
    var user_ele = document.createElement("li");
    user_ele.onclick = ignore_user;
    user_ele.name = e;
    user_ele.title = e + " (click to mute)";
    user_ele.className = "username";
	if(user_is_ignored(e)) {
		user_ele.style.background = "transparent url('http://people.opera.com/sverrej/ssechat/dialog-error.png') no-repeat 0 50%";
	} 
    user_ele.appendChild( document.createTextNode(e));
    return user_ele;
}

function send_chatline() {
	if(global_context.session_id == null) {
		opera.postError("waiting for sessionid...");
		return;
	}

	// Send text
	var chatline = document.getElementById("chat-input").value;
	if (chatline=="" || !chatline.match(/\S/)) { return }
	var request = new XMLHttpRequest();
	request.open("GET", "/chat/" + global_context.session_id + encodeURIComponent(chatline));
	request.send();
	if ( !global_context.history_list[0] || global_context.history_list[0] != chatline ) {
		global_context.history_list.unshift(chatline);
	}
	global_context.history_index = -1;
	document.getElementById("chat-input").value = "";
}

// For pixel perfectness, in the wait for CSS3 layout stuff. I apologize.
function fixLayout() {
	var header     = document.getElementById('header');
	var chatInput  = document.getElementById('chat-input');
	var chatArea   = document.getElementById('chat-area');
	var userList   = document.getElementById('user-list');

	var cs = window.getComputedStyle;
	var headerHeight = parseInt(cs(header, null).getPropertyValue('height'));
	var inputHeight = parseInt(cs(chatInput, null).getPropertyValue('height'));

	var fixedHeight = window.innerHeight - headerHeight - inputHeight;
	userList.style.top = headerHeight + 'px';
	chatArea.style.height = chatArea.style.maxHeight = userList.style.maxHeight = fixedHeight + 'px';
	chatArea.style.width = window.innerWidth - 180 + 'px';
	chatInput.style.width = parseInt(cs(chatArea, null).getPropertyValue('width')) - 5 + "px";
	userList.style.maxHeight = window.innerHeight - headerHeight - inputHeight + "px";

}

function blinking_dots() {
	var ele = document.getElementById("blinking-dots");
	switch (ele.firstChild.nodeValue.length) {
		case 0:
			ele.firstChild.nodeValue = ".";
			break;
		case 1:
			ele.firstChild.nodeValue = "..";
			break;
		case 2:
			ele.firstChild.nodeValue = "...";
			break;
		case 3:
			ele.firstChild.nodeValue = "";
			break;
		default:
			ele.innerHTML = "....";
			break;
	}

	if(global_context.session_id == null) {
		setTimeout( blinking_dots, 500);
	}
}

function give_notification() {

	if ( global_context.tab_highlighted ) {
		return;	
	}

	global_context.tab_highlighted = true;

	var img_hack = document.getElementById("loading-hack");
	if( img_hack.src == "http://people.opera.com/sverrej/1.png" ) {
		img_hack.src = "http://people.opera.com/sverrej/2.png";
	}	else {
		img_hack.src = "http://people.opera.com/sverrej/1.png";
	}
}

function padZero(n) { 
	return (n < 10) ? '0' + n : '' + n; 
}


function formatter_smilies(words) {
	for (var n=0, e; e=words[n]; n++) {
		if (typeof e == 'string') {
			if (e in config.smilies) {
				var i = document.createElement('img');
				i.src = config.smilies[e];
				i.alt = e;
				i.title = e;
				words[n] = i;
			}
		}
	}

}

function formatter_url(words) {
	var ur = /\b(((https?|ftp|irc|telnet|nntp|gopher|file):\/\/|(mailto|news|data):)[^\s\"<>\{\}\'\(\)]*)/g;  // "
	for (var n=0, e; e=words[n]; n++) {
		if (typeof e == 'string') {
			var m = e.match(ur); 
			if (m) {
				var a = document.createElement('a');

				a.href = m;
				a.target="_blank";
				a.appendChild(document.createTextNode(m));
				words[n] = a
			}
		}
	}
}

function formatter_nick(words) {
	for (var n=0, e; e=words[n]; n++) {
		if ( typeof e == 'string' && ( e==global_context.nick | e==global_context.nick + ":" ) ) {
			var em = document.createElement('em');
			em.className="nick-highlight";
			em.appendChild(document.createTextNode(e));
			words[n] = em
		}
	}
}

function set_text_from_history(offset) {
	curindex = global_context.history_index + offset;
	curindex = ( curindex < -1 ? -1 : curindex );
	curindex = ( curindex >= global_context.history_list.length ? global_context.history_list.length-1 : curindex );

	global_context.history_index = curindex;

	var e = document.getElementById("chat-input");
	if ( curindex == -1 ) {
		e.value = "";
	} else {
		e.value = global_context.history_list[curindex];
	}
}

function autocomplete_update() {

  var word = global_context.ac_input;

  var input  = document.getElementById("chat-input");
  if (!global_context.ac_input) {
    var cutpoint = (input.value.lastIndexOf(' ') == -1) ? 0 : input.value.lastIndexOf(' ')+1;
    head = input.value.slice(0, cutpoint);
    var word = input.value.slice(cutpoint);
    if (word == "") { return }
    
    global_context.ac_input = word;
    global_context.ac_index = 0;
  }
	
  var nicks = global_context.roster.filter(function(w) {  return w.toLowerCase().indexOf(global_context.ac_input.toLowerCase()) == 0 });	
  if (nicks.length) {
    if (head == "") {
      input.value = nicks[global_context.ac_index]+": "; 		
    } else {
      input.value = head + nicks[global_context.ac_index] + " ";
    }		
    global_context.ac_index = global_context.ac_index >= nicks.length-1 ? 0 : global_context.ac_index+1
  }
}

