/*
 *	jQuery terminal
 *	@author Eirik Lillebo
 */
var shell = {
	
	// TODO: container: terminal.parent() ?
	mainFrame: null,
	activeFrame: null,
	history: [],
	historyLimit: 10,
	curCmd: 0,
	
	loadInterface: function(){
		
		// Define template container
		var template_pre_html = '<div id="templates">';
		var template_post_html = '</div>';
		
		var template = "";

		$.ajax({
			type: "POST",
			url: "templates/interface.html",
			success: function(data, textStatus, jqXHR){
				
				// Get all interface templates
				template = template_pre_html + data + template_post_html;
				$("body").append(template);
				
				// Get mainFrame
				shell.mainFrame = $("#templates").find(".term-display").clone();
				$(terminal.selector).append(shell.mainFrame);
				shell.activeFrame = shell.mainFrame;
				
				// Prompt user
				shell.input(terminal, null, null);
				
			},
			error: function(){
				// TODO: Error handling
			}
		});
	},
	
	setContainer: function(){
		var size = {
			width: window.innerWidth || document.body.clientWidth,
			height: window.innerHeight || document.body.clientHeight
		};
		$(".container").css("height", size.height-200);
		this.addPanelScroll(".container");
	},
	
	input: function(term, prompt, callback){
		
		// Remove any previous prompt
		$(term.selector).find(".prompt").remove();
		
		var template = $("#templates").find(".prompt").clone();
		var prefix   = template.find(".pre");
		
		// Format prompt
		if (prompt){
			prefix.html(prompt);
		} else {
			prefix.html("&gt;");
		}
		
		var input  = template.find(".cmd");
		
		// Register callback
		if (callback && typeof(callback) === "function") {
			input.data("callback", callback);
		}
		
		// Add to display
		// TODO: term.selector = container?
		$(term.selector).append(template);
		this.updateScroll(false);
		
		// Set styles (width)
		var pre_width    = parseInt(prefix.outerWidth());
		var prompt_width = parseInt(template.outerWidth());
		var input_width  = prompt_width - pre_width;
		input.css("width", input_width);
		
		this.eventHandlers();
		input.focus();
		
	},
	
    parseInput: function(term, el){
	
		var fn   = el.data("callback");
		var cmd  = el.val();
		var cmds = cmd.split(" ");
		
		term.logInput(cmd);
		
		// Redirect to callback
		if (fn && typeof(fn) === "function") {
			fn(term, cmds);
			return;
		}
		
		term.curCmd = 0;

		// Add cmd to history
		if (this.history.length == this.historyLimit){
			this.history.pop();
			this.history.unshift(cmd);
		} else {
			this.history.unshift(cmd);
		}
		
		this.print("&gt; " + cmd);
		
		var app = cmds[0].toLowerCase();
		
		cmds.shift();
		var params = cmds;
		
		// Delegate to terminal
		switch(app){
			case "clear"  : this.clear();
							break;
			case "about"  : term.article(app);
							break;
			case "help"   : term.article(app);
							break;
			case "man"    : term.article("help");
							break;
			case "su"     : term.authUser(params);
						    break;
			case "hello"  : term.greet();
						    break;
			case "upload" : term.load(app, params);
						    break;
			case "journal": term.load(app, params);
		    				break;
			case "kill"   : term.kill();
		    				break;
			case "exit"   : term.kill();
							break;
			case "whoami" : term.whoami();
		    				break;
			case "pwd"    : this.print("File system not available.");
							break;
			case "ls"     : this.print("File system not available.");
							break;
			case "cd"     : this.print("File system not available.");
							break;
			case "touch"  : this.print("Can't touch this.");
							break;
			case "exit"   : this.print("Bye.");
							break;
			case "g"	  : term.google(params);
							break;
			case "tabs"   : term.tabs(params);
							break;
			case "version"  : term.article(app);
							break;
			default		  : this.print("Command not found: "+cmd);
							break;
		}
		
	},
	
	prevCmd: function(){
		
		var input = $(terminal.selector).find("input[name=cmd]");
		
		if (this.curCmd < this.history.length) {
			input.val(this.history[this.curCmd]);
			this.curCmd++;
			input.focus();
		}
		
		
	},

	nextCmd: function(){

		var input = $(terminal.selector).find("input[name=cmd]");

		if (this.curCmd > 0) {
			input.val(this.history[this.curCmd - 2]);
			this.curCmd = this.curCmd - 1;
			input.focus();
		} else {
			input.val("");
			input.focus();
		}

	},
	
	clear: function(){
		this.activeFrame.html("");
		this.input(terminal, null, null);
	},
	
	output: function(type, content){
		var timestamp = terminal.timestamp();
		var markup = "";
		
		if (!type) {
			type = 'plain';
		}
		
		var markup = $("#templates").find(type).clone();
		markup.find(".timestamp").html(timestamp);
		markup.find(".content").html(content);
		
		// TODO: change all <selector>.append to activeFrame.append
		markup.hide();
		this.activeFrame.append(markup);
		markup.show();
		
		if (!terminal.appLock) {
			this.input(terminal, null, null);			
		}
		
	},
	
	print: function(txt){
		this.output(".plain", txt);
	},
	
	error: function(txt){
		this.output(".error", txt);
	},
	
	addPanelScroll: function(selector){
		
		$(selector).jScrollPane();
		$(selector).each(function(){
			var api = $(this).data('jsp');
			var throttleTimeout;
			$(window).bind( 'resize', function() {
				if ($.browser.msie) {
					if (!throttleTimeout) {
					throttleTimeout = setTimeout(
						function() {
							api.reinitialise();
							throttleTimeout = null;
						}, 50);
					}
				} else {
					api.reinitialise();
				}
			});
		});
	},
	
	updateScroll: function(flag){
		var settings = {
			showArrows: false
		};
		var pane = $('.container');
		pane.jScrollPane(settings);
		var api = pane.data('jsp');
		api.reinitialise();
		if (!flag) {
			api.scrollToPercentY(100, false);
		} else {
			api.scrollToPercentY(100, true);
		}
	},
	
	eventHandlers: function(){
		$(".prompt input").unbind("keyup").bind("keyup", function(e){
			var code = (e.keyCode ? e.keyCode : e.which);
			switch(code){
				case 13 : terminal.view.parseInput(terminal, $(this)); break;
				case 38 : terminal.view.prevCmd(); break;
				case 40 : terminal.view.nextCmd(); break;
			}
		});
		
		$(".term-display a").unbind("click").bind("click", function(e){
			e.preventDefault();
			var target = $(this).attr("href");
			//window.location = target;
			window.open(target, '_blank');
		});
		
		window.onresize = function(){
			terminal.view.setContainer();
		};
	}
	
};

var terminal = {

    view: shell,
    selector: null,
	appLock: null,
	user: null,
	
    init: function(selector){
		this.selector = selector;
		this.view.setContainer();
		this.view.loadInterface();
	},
	
    prompt: function(){
    	this.view.input(this, "&gt;", null);
	},
	
	setLoader: function(el){
		var loader = $("#templates").find(".loader").clone();
		el.html(loader);
	},
	
	removeLoader: function(el){
		el.find(".loader").remove();
	},
	
	load: function(appname, params){
		
		if (!this.user) {
			this.view.error("Login required. Please authenticate using '<strong>su</strong>'.");
			return;
		}
		
		// Hide main frame
		this.view.mainFrame.hide();
		
		// Get new app frame
		var appFrame = $("#templates").find(".app-frame").clone();
		$(this.selector).find(".prompt").before(appFrame).remove();
		
		this.view.activeFrame = appFrame;
		var self = this;
		
		// Load application
		$.ajax({
			type: "POST",
			url: "templates/"+appname+".html",
			success: function(data, textStatus, jqXHR){
				self.view.activeFrame.html(data);
				if (app) {
					self.appLock = app;
					self.appLock.init(self);
				} else {
					self.view.error("App failed to load.");
				}
			},
			error: function(){
				// TODO: Error handling
			}
		});
		
		this.view.updateScroll();
	},
	
	kill: function(){
		
		if (this.appLock && this.view.activeFrame != this.view.mainFrame) {
			this.appLock = null;
			this.view.activeFrame.remove();
			this.view.activeFrame = this.view.mainFrame;
			this.view.mainFrame.show();
			this.view.input(this, null, null);
			this.view.updateScroll();
		} else {
			this.view.error("No running applications.");
		}
		
	},

	article: function(article){
		
		$.ajax({
			type: "POST",
			url: "templates/"+article+".html",
			success: function(data, textStatus, jqXHR){
				terminal.view.output(".multiline", data);
			},
			error: function(){
				console.log("Error");
				terminal.view.output("error", "Article not found.");
			}
		});

	},
	
	greet: function(){

		var reply = "";

		var date = new Date();
		var hour = date.getHours();

		if (hour < 3) {
			reply = "*Yawn* Yes, hello?";
		} else if (hour < 6) {
			reply = "zzzZzzzz....";
		} else if (hour < 12) {
			reply = "Good morning.";
		} else if (hour < 14) {
			reply = "Good afternoon.";
		} else if (hour < 18) {
			reply = "Hai.";
		} else if (hour < 24) {
			reply = "Good evening.";
		}

		terminal.view.print(reply);

	},
	
	logInput: function(content){
		
		$.ajax({
			type: "POST",
			url: "lib/log.php",
			data: "c="+content,
			success: function(data, textStatus, jqXHR){
				//console.log("Log response: "+data);
			},
			error: function(xhr){
				//console.log("Log failed: " + xhr.statusText);
			}
		});
		
	},

	google: function(params){
		params = params.join(" ");
		var search = "http://www.google.com/webhp?hl=en#sclient=psy&hl=en&site=webhp&q="+params+"&aq=f&aqi=&aql=&oq=&gs_rfai=&pbx=1&fp=94fb864a6b447b62";
		this.view.print('Google query "'+params+'"');
		window.open(search, '_blank');
	},

	tabs: function(params){

		var set = params[0];
		var targets = [];
		
		if (set == "dev") {

			targets = [
				'localhost:8888/MAMP/',
				'developer.mozilla.org/en-US/docs',
				'www.stackoverflow.com',
				'www.superuser.com',
				'www.serverfault.com',
				'www.google.com'
			];

		} else if (set == "news") {
			
			targets = [
				'www.twitter.com',
				'www.guardian.co.uk',
				'www.arstechnica.com',
				'www.slashdot.org'
			];
			
		}

		var i;
		for (i = 0; i < targets.length; i++) {
			this.view.print("Opening tab: "+targets[i]);
			window.open("http://"+targets[i], '_blank');
		}
		
	},

	authUser: function(params){
		
		var username = params[0];
		var password = params[1];

		// If only 'su' is run, reset 'this.user'
		if (!username || !password) {
			this.view.error("Auth failed: Insufficient parameters.");
			return;
		}
		
		// TODO: Fix optional parameters

		var self = this;
		
		$.ajax({
			type: "POST",
			url: "lib/authUser.php",
			data: "n="+username+"&p="+password,
			success: function(data, textStatus, jqXHR){
				if (data != "0") {
					var user = $.parseJSON(data);
						user = user[0];
					self.view.print("Welcome back, "+user.name+".");
					self.user = user;
				} else {
					self.view.error("Auth failed: Invalid credentials.");
					self.user = null;
				}
			},
			error: function(xhr){
				self.view.error("Auth failed: " + xhr.statusText);
				self.user = null;
			}
		});
		
	},

	authUsername: function(name){
		var params = [name, null];
		this.user = name;
		terminal.authUser(params);
	},

	authPassword: function(pass){
		var params = [null, pass];
		terminal.authUser(params);
	},
	
	whoami: function(){
		var username;
		if (this.user) {
			username = this.user.name;
		} else {
			username = "Mitch Hedberg";
		}
		this.view.print("Your are "+username);
	},

	timestamp: function(){
		
		var date = new Date();
		var hour = date.getHours();
		var mins = date.getMinutes();
		var secs = date.getSeconds();
		
		if (hour < 10) hour = "0"+hour;
		if (mins < 10) mins = "0"+mins;
		if (secs < 10) secs = "0"+secs;
		
		var timeString = hour+":"+mins+":"+secs;
		return timeString;
		
	},

	upload: function(params){

		if (this.user == null) {
			this.view.error("Login required. Please authenticate using '<strong>su</strong>'.");
			return;
		}

	}

};

$(document).ready(function(){
	terminal.init(".terminal");
});
