function getRandomInt(min, max) {
	// via https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Math/random#Examples
	return Math.floor(Math.random() * (max - min + 1)) + min;
}

xkcd = {
	latest: null,
	last: null,
	cache: {},

	get: function(num, cb) {
		if(num == null)
		{
			path = '/get.php';
		}
		else if(Number(num))
		{
			path = '/get.php?id='+num;
		}
		else
		{
			cb.fail(false);
			return false;
		}

		if(num in this.cache)
		{
			this.last = this.cache[num];
			cb.success(this.cache[num]);
		}
		else
		{
			return $.ajax({
				url: path,
				dataType: 'json',
				success: $.proxy(function(data){
					this.last = this.cache[num] = data;
					cb.success(data);
				}, this),
				error: cb.fail});
		}
	}
};

loadDir = function(terminal, par, lurl){
	if(!par.contents)
	{
		par.contents_loaded = false;
		par.contents = {};
		terminal.setWorking(true);
		$.ajax({
			url: lurl,
			dataType: 'json',
			success: function(data){
				$.each(data, function(id, c){
					par.contents[c.dispname] = {
						type:c.type,
						enter:(c.type=='dir'
							?function(terminal){loadDir(terminal,this,c.data_url);}
							:null)
					};
				});
				par.contents_loaded = true;
				terminal.setWorking(false);
				terminal.updateInputDisplay();
				Terminal.scrollPage(1);
			},
			error: function(){terminal.print('No such file or directory');}
		});
	}
};

Filesystem = {
	'readme.txt': {
		type:'file',
		read:function(terminal){
			terminal.setWorking(true);
			$.get('/readme.txt', function(data){
				$.each(data.split("\n"), function(num, line){
					terminal.print(line);
				});
				terminal.setWorking(false);
			});
		}
	},
	'license.txt': {
		type:'file',
		read:function(terminal){
			terminal.setWorking(true);
			$.get('/license.txt', function(data){
				$.each(data.split("\n"), function(num, line){
					terminal.print(line);
				});
				terminal.setWorking(false);
			});
		}
	},
	'authors': {
		type:'dir',
		enter:function(terminal){loadDir(terminal,this,'/authors.php?index=1');}
	}
};

TerminalShell.pwd = Filesystem;
TerminalShell.path = [];
TerminalShell.pathnames = [];

var xkcdDisplay = function(terminal, path){
	ffail = function(){
		terminal.print($('<p>').addClass('error').text(path+': No such file or directory'));
		terminal.setWorking(false);
	};

	terminal.setWorking(true);

	if(path)
	{
		path = String(path);
		num = Number(path.match(/^\d+/));
	}
	else
	{
		num = xkcd.last.num;
	}

	xkcd.get(num, {success:function(data){
		if(data.error) ffail();
		else
		{
			$('<img>').hide()
				.load(function(){
					terminal.print($('<h3>').text(data.num+': '+data.title));
					terminal.print($('<h4>').text('By '+data.author+', '+data.date));
					$(this).fadeIn();
					var comic = $(this);
					terminal.print(comic);
					terminal.setWorking(false);
				}).attr({
					src:'http://xkcdsw.com/content/img/'+data.img,
					alt:data.title,
					title:data.alt
				}).addClass('comic');
		}
	},fail:ffail});
};

TerminalShell.commands['display'] = TerminalShell.commands['goto'] = xkcdDisplay;
TerminalShell.commands['cls'] = TerminalShell.commands['clear'];

TerminalShell.commands['next'] = function(terminal) {
	xkcdDisplay(terminal, parseInt(xkcd.last.num)+1);
};

TerminalShell.commands['previous'] =
TerminalShell.commands['prev'] = function(terminal) {
	xkcdDisplay(terminal, parseInt(xkcd.last.num)-1);
};

TerminalShell.commands['first'] = function(terminal) {
	xkcdDisplay(terminal, 1);
};

TerminalShell.commands['latest'] =
TerminalShell.commands['last'] = function(terminal) {
	xkcdDisplay(terminal, xkcd.latest.num);
};

TerminalShell.commands['random'] = function(terminal) {
	xkcdDisplay(terminal, getRandomInt(1, xkcd.latest.num));
};

TerminalShell.commands['dir'] = function(terminal, path){
	name_list = $('<ul>');
	if(path in this.pwd)
	{
		switch(this.pwd[path].type)
		{
			case 'file': name_list.append($('<li>').text(path)); break;
			case 'dir':
				if(!this.pwd[path].contents)
					TerminalShell.pwd[path].enter(terminal);

				$.each(this.pwd[path].contents,	function(name, obj){
					if(obj.type == 'dir') name += '/';
					name_list.append($('<li>').text(name));
				});
				break;
		}
	}
	else
	{
		$.each(this.pwd, function(name, obj){
			if(obj.type == 'dir') name += '/';
			name_list.append($('<li>').text(name));
		});
	}
	terminal.print(name_list);
};

TerminalShell.commands['cd'] =
TerminalShell.commands['chdir'] = function(terminal, lpath){
	if(lpath.indexOf('\\') > 0)
	{
		s = lpath.split('\\');
		for(i=0; i<s.length; i++)
		{
			TerminalShell.commands['cd'](terminal, s[i]);
		}
		return;
	}

	if(lpath == '')
	{
		return;
	}
	else if(lpath == '..')
	{
		if(TerminalShell.path.length)
		{
			TerminalShell.pwd = TerminalShell.path.pop();
			TerminalShell.pathnames.pop();
		}
	}
	else if(lpath == '\\')
	{
		TerminalShell.path = [];
		TerminalShell.pathnames = [];
		TerminalShell.pwd = Filesystem;
	}
	else if(lpath in TerminalShell.pwd)
	{
		if(TerminalShell.pwd[lpath].type == 'dir')
		{
			TerminalShell.path.push(TerminalShell.pwd);
			TerminalShell.pathnames.push(lpath);

			TerminalShell.pwd[lpath].enter(terminal);
			TerminalShell.pwd = TerminalShell.pwd[lpath].contents;
		}
		else
		{
			terminal.print('No such file or directory');
		}
	}
	else
	{
		terminal.print('No such file or directory');
	}
	Terminal.config.prompt = "\nA:\\" + TerminalShell.pathnames.join('\\') + '>';
	Terminal.updateInputDisplay();
	Terminal.scrollPage(1);
};

TerminalShell.commands['type'] = function(terminal, path){
	if(path in this.pwd)
	{
		switch(this.pwd[path].type)
		{
			case 'file': this.pwd[path].read(terminal); break;
			case 'dir': terminal.print('Access denied: cannot open directory'); break;
		}
	}
	else
	{
		terminal.print('No such file or directory');
	}
};

TerminalShell.fallback = function(terminal, cmd){
	if(Number(cmd) > 0)
	{
		TerminalShell.commands['goto'](terminal, cmd);
		return true;
	}
	return false;
};

$(document).ready(function() {
	Terminal.promptActive = false;
	$('#screen').bind('cli-load', function(e) {
		xkcd.get(null, {success: function(data) {
			xkcd.latest = data;
			$('#screen').one('cli-ready', function(e) {
				Terminal.runCommand('type readme.txt');
			});
			Terminal.runCommand('goto '+xkcd.latest.num);
		}, fail: function() {
			Terminal.print($('<p>').addClass('error').text('Bad command interpreter'));
			Terminal.promptActive = true;
		}});
	});
});

