/**
 * This file contains some functions which participe to communicate with
 * the MyOnlineSSH socket.
 * 
 * @author Samuel ROZE <samuel.roze@gmail.com>
 */

var MyOnlineSSHSocket = {
	/**
	 * The jQuery instance.
	 */
	socket: null,
	
	/**
	 * Is the socket connected ?
	 */
	connected: false,
	
	/**
	 * The number of messages received
	 */
	messageI:0,
	
	/**
	 * Contains the public keys which will be used to crypt data
	 * before sending to MyOnlineSSHSocket.
	 */
	keys:null,
	
	/**
	 * This string contains the last command sent to the SSH server.
	 */
	lastCommand: '',
	
	/**
	 * Is waiting a "Tab" result?
	 */
	waitOnTab: false,
	
	/**
	 * This init function called when the user validate the form
	 * and when he writed valid datas.
	 * 
	 * @return void
	 */
	init: function () {
		// Before anything, check form fields to be sure that the data
		// is right.
		if (!check_form()) {
			return;
		}
        
        // Init the socket connection
        this.socket = new jSocket();
        
        // When the socket is added the to document 
        this.socket.onReady = function() {
        	MyOnlineSSHSocket.dispatchLoadingInformation(_('Connexion à l\'interface MyOnlineSSH'));
        	MyOnlineSSHSocket.socket.connect('sock.d-sites.com', 80);              
        },
        
        // Connection attempt finished
        this.socket.onConnect = function(success){
	        if(success){
			    // Send something to the socket
	        	MyOnlineSSHSocket.connected = true;     
			    // Dispatch information
			    MyOnlineSSHSocket.dispatchLoadingInformation(_('Connecté. Récupération des clés de cryptage.'));
			    // Get encryption keys
			    MyOnlineSSHSocket.waitForKeys = true;
				MyOnlineSSHSocket.sendData('mossh::getpublickey');
	        } else {
	        	MyOnlineSSHSocket.dispatchError(_('La connexion au serveur MyOnlineSSH est impossible'));            
	        }       
        }
        
        this.socket.onData = this.dataReiceived;
        
        // Setup our socket in the div with the id="socket"
        this.socket.setup('socket');
	},
	
	/**
	 * This function sends the firsts commands which are connecting
	 * with the SSH server.
	 */
	connectToSSH: function ()
	{
		if (!this.connected) {
			this.dispatchError('La connexion doit être éffective pour envoyer les commandes');
		} else {
			// On va crypter les données...
			var form = $("form#connectionForm");
			var cryption2 = new jCryption2({
				encryptedCallback: function (encrypted_string) {
					MyOnlineSSHSocket.connectWithEncryptedData(encrypted_string);
				}
			});
			cryption2.setKeys(this.keys);
			this.dispatchLoadingInformation(_('Cryptage en cours...'));
			cryption2.getFormFields(form);
		}
	},
	
	/**
	 * Va envoyer les paramètres de connexion au socket, une fois les données
	 * encryptées.
	 */
	connectWithEncryptedData:function (encrypted_string) {
		MyOnlineSSHSocket.dispatchLoadingInformation(_('Envoi des données...'));
		this.sendData('mossh::connect::'+encrypted_string);
		this.dispatchLoadingInformation(_('Connexion au server SSH en cours...'));
	},
	
	/**
	 * Dispatch some informations about the loading status of the
	 * SSH connection.
	 */
	dispatchLoadingInformation: function (string)
	{
		set_connection_message(string, 'loading');
	},
	
	/**
	 * Dispatch the occured error.
	 */
	dispatchError: function (string)
	{
		$('<div class="information error">'+string+'</div>').appendTo('#messages');
		// On enlève le message de chargement de connexion
		set_connection_message(false);
	},
	
	/**
	 * This function is called when the socket receive data
	 * from the MyOnlineSSH server
	 * 
	 * @param data The data which is received
	 * @return void
	 */
	dataReiceived: function (data)
	{
		if (data == 'mossh::connected') {
			set_connection_message(false);
			// Affiche la command line
			MyOnlineSSHSocket.print_ssh_command_line();
		} else if (data == 'mossh::disconnected') {
			if (confirm('Connexion SSH déconnectée. Retourner à la page d\'accueil ?')) {
				window.location.reload();
			}
		} else if (MyOnlineSSHSocket.waitForKeys) {
			MyOnlineSSHSocket.waitForKeys = false;
			try {
				var keysObject = JSON.parse(data);
			} catch (SyntaxError) {
				set_connection_message(_('Impossible de récuperer les clés de cryptage'), 'error');
				return;
			}
			MyOnlineSSHSocket.dispatchLoadingInformation(_('Clées reçues.'));

			MyOnlineSSHSocket.keys = new jCryption2Key(
				keysObject.e,
				keysObject.n,
				keysObject.maxdigits
			);

		    // Envoi des commandes
		    MyOnlineSSHSocket.connectToSSH();
		} else if (data.substr(0, 21) == 'mossh::loadingerror::') {
			set_connection_message(data.substring(21), 'error');
			$('form#connectionForm input,select,textarea').removeAttr('disabled');
		} else if (data.substr(0, 20) == 'mossh::loadinginfo::') {
			MyOnlineSSHSocket.dispatchLoadingInformation(data.substring(20));
		} else if (data.substr(0, 14) == 'mossh::error::') {
			MyOnlineSSHSocket.dispatchError(data.substring(14));
		} else if (data.substr(0, 13) == 'mossh::edit::') {
			if (data.substr(13, 4) == 'done') {
				$.fn.fancybox.close();
				MyOnlineSSHSocket.waitForReply(false);
			} else if (data.substr(13, 6) == 'loading::') {
				$('div#file_info span').attr('class', 'loading').text(data.substring(26));
			} else if (data.substr(13, 6) == 'error::') {
				$('div#file_info span').attr('class', 'error').text(data.substring(19));
			} else {
				var parts = data.substring(13).split('::');
				var file_id = parts.shift();
				var file_meta = parts.join('::');
				$('<a href="files/'+file_id+'/'+file_meta+'" />').fancybox({
					frameWidth: $(window).width()-200, 
					frameHeight: $(window).height()-100, 
					callbackOnShow: function (obj) {
						$('textarea.editor').height(this.frameHeight-40);
						$('form#file_form').submit(function (e) {
							$('div#file_info').attr('class', 'loading').slideDown('slow');
							$('div#file_info span').text(_('Cryptage en cours...'));
							
							var cryption2 = new jCryption2({
								encryptedCallback: function (encrypted_string) {
								$('div#file_info span').text(_('Envoi des données...'));
									MyOnlineSSHSocket.sendData('mossh::edit::send::'+encrypted_string+'[mossh::end]');
								}
							});
							cryption2.setKeys(MyOnlineSSHSocket.keys);
							cryption2.getFormFields(this);
							
							return false;
						});
						MyOnlineSSHSocket.waitForReply(false);
					}
				}).click();
			}
		} else if (MyOnlineSSHSocket.waitOnTab != false) {
			$('span#ssh_cursor_character').text(' ');
			$('input#ssh_input').val($('input#ssh_input').val()+data);
			$('span#ssh_command').text($('input#ssh_input').val());
			$('span#ssh_command_post').text('');
			
			if (data != MyOnlineSSHSocket.waitOnTab) {
				MyOnlineSSHSocket.waitOnTab = false;
			}
		} else {
			if (data.substring(0, data.length-2) != MyOnlineSSHSocket.lastCommand) {
				MyOnlineSSHSocket.waitForReply(false);
			}
			
			// C'est le résultat d'un commande quelconque
			var actual_text = $('span#ssh_content').html();
			$('span#ssh_content').html(actual_text+data);
			$('input#ssh_input').focus();
		}
	},
	
	/**
	 * Send command to the MyOnlineSSH server which will send
	 * it to the remote SSH server.
	 * 
	 * @param string data The command
	 * @return void
	 */
	sendData: function (data)
	{
		this.lastCommand = data;
		
		if (data == '') {
			data = 'mossh::signals::empty';
		}
		this.socket.write(data);
	},
	
	/**
	 * Define is we are waiting for an SSH server reply or not.
	 * 
	 * @param bool Is waiting ?
	 * @return void
	 */
	waitForReply: function (waiting)
	{
		if (waiting) {
			$('body').append('<div id="is_loading" alt="'+_('Envoyer un signal d\'échappement')+'" style="cursor: pointer;"></div>');
			$('div#is_loading').click(function (e) {
				if (confirm(_('Êtes-vous sûr de vouloir envoyer un signal d\'échappement ?'))) {
					$(this).css('background-image', 'url(/template/images/ssh-loading-red.gif)');
					MyOnlineSSHSocket.sendData('mossh::signals::break');
				}
				$('pre#ssh').focus();
			});
		} else {
			$('body div#is_loading').remove();
		}
	},
	
	/**
	 * Print the SSH command line.
	 * 
	 * @return void
	 */
	print_ssh_command_line: function ()
	{
		this.history = new Array();
		this.historyIndex = 0;
		
		$('input#ssh_input').keyup(function (e) {
			$('span#ssh_command').text(
				$('input#ssh_input').val()
			);
			
			var index = $('input#ssh_input').val().length;
			$('input#ssh_input').selectRange(index, index);
		});
		$('input#ssh_input').keydown(function (e) {
			if (e.keyCode == 37) { // Keyboard Left
				var ssh_command_value = $('span#ssh_command').text();
				if (ssh_command_value == '') {
					return;
				}
				var ssh_command = ssh_command_value.substring(0, ssh_command_value.length-1);
				var cursor_character = ssh_command_value.substring(ssh_command_value.length-1, ssh_command_value.length);
				var ssh_command_post = $('span#ssh_cursor_character').text() + $('span#ssh_command_post').text();
			} else if (e.keyCode == 39) { // Keyboard right
				var ssh_command_post_value = $('span#ssh_command_post').text();
				if (ssh_command_post_value == '') {
					return;
				}
				var ssh_command = $('span#ssh_command').text() + $('span#ssh_cursor_character').text();
				var cursor_character = ssh_command_post_value.substring(0, 1);
				var ssh_command_post = ssh_command_post_value.substring(1);
			} else if (e.keyCode == 46) { // Suppr key
				var ssh_command = $('span#ssh_command').text();
				var ssh_cursor_character_value = $('span#ssh_cursor_character').text()
				var ssh_command_post = $('span#ssh_command_post').text().substring(1);
				var cursor_character = $('span#ssh_command_post').text().substring(0, 1);
				if (cursor_character == '') {
					return;
				}
			} else if (e.keyCode == 38) { // Keyboard Up
				var ssh_command = MyOnlineSSHSocket.getHistory(1);
				var ssh_cursor_character = ' ';
				var ssh_command_post = '';
			} else if (e.keyCode == 40) { // Keyboard Down
				var ssh_command = MyOnlineSSHSocket.getHistory(-1);
				var ssh_cursor_character = ' ';
				var ssh_command_post = '';
			} else if ((e.which == 67 || e.which == 99) && e.ctrlKey) { // Ctrl-C
				MyOnlineSSHSocket.sendData('mossh::signals::break');
				var ssh_cursor_character = ' ';
				var ssh_command_post = '';
				var ssh_command = '';
			} else if (e.keyCode == 9) { // Tab
				MyOnlineSSHSocket.sendData('mossh::signals::tab::'+$('span#ssh_command').text());
				MyOnlineSSHSocket.waitOnTab = $('span#ssh_command').text();
				$('input#ssh_input').val('');
				return false;
			} else {
				$('span#ssh_command').text(
					$('input#ssh_input').val()
				);
			}
			// Dispatch values (order is important)
			$('span#ssh_cursor_character').text(cursor_character);
			$('input#ssh_input').val(ssh_command);
			$('span#ssh_command').text(ssh_command);
			$('span#ssh_command_post').text(ssh_command_post);
		});
		$('form#ssh_form').submit(function (e) {
			var command = $('span#ssh_command').text();
			
			if ($('span#ssh_command_post').text() != ' '
				&& $('span#ssh_command_post').text() != '') {
				command += $('span#ssh_cursor_character').text();
				command += $('span#ssh_command_post').text();
			} else if ($('span#ssh_cursor_character').text() != ' ') {
				command += $('span#ssh_cursor_character').text();
			}
			
			MyOnlineSSHSocket.sendData(
				command
			);
			MyOnlineSSHSocket.history.unshift(command);
			MyOnlineSSHSocket.historyIndex = 0;
			// Clean values
			$('span#ssh_command').text('');
			$('span#ssh_cursor_character').text(' ');
			$('span#ssh_command_post').text('');
			$('input#ssh_input').val('');
			$('input#ssh_input').focus();
			MyOnlineSSHSocket.waitForReply(true);
			MyOnlineSSHSocket.waitOnTab = false;
			// important !
			return false;
		});
		$('span#ssh_command').focus(function (e) {
			$('input#ssh_input').focus();
		});
		$('pre#ssh').focus(function(e) {
			if (e.target == this) {
				$('span#ssh_command').focus();
				
				MyOnlineSSHSocket.cursorFunc = function () {
					var cursor = $('span#ssh_cursor_character');
					if (cursor.css('visibility') == 'visible') {
						cursor.css('visibility', 'hidden');
					} else {
						cursor.css('visibility', 'visible');
					}
					setTimeout(MyOnlineSSHSocket.cursorFunc, 600);
				};
				MyOnlineSSHSocket.cursorFunc();
			}
		});
		$('pre#ssh').click(function (e) {
			if (e.target == this) {
				$('span#ssh_command').focus();
			}
		});
		$('pre#ssh').blur(function (e) {
			MyOnlineSSHSocket.cursorFunc = function () {
				$('span#ssh_cursor_character').css('visibility', 'hidden');
			};
		});
		
		this.setColors();
		
		$('div#connection_contener').css({display: 'none'});
		$('pre#ssh').css({visibility: 'visible'});
	},
	
	/**
	 * Return the command history.
	 * 
	 * @param integer Index of the command in history
	 * @return string The command
	 */
	getHistory: function (difference)
	{
		this.historyIndex += difference;
		
		if (this.historyIndex <= 0) {
			this.historyIndex = 0;
			return '';
		} else if (this.history[this.historyIndex-1] == undefined) {
			this.historyIndex -= difference;
		}
		return this.history[this.historyIndex-1]
	},
	
	/**
	 * Apply the colors.
	 * 
	 * @return void
	 */
	setColors: function ()
	{
		$('pre#ssh').css('background', '#'+this.colors.background);
		$('form#ssh_form input#ssh_input').css('background', '#'+this.colors.background);
		$('pre#ssh span#ssh_content, pre#ssh span#ssh_command, pre#ssh span#ssh_command_post')
			.css('color', '#'+this.colors.color);
		$('pre#ssh span#ssh_cursor span#ssh_cursor_character')
			.css('background', '#'+this.colors.cursor.background)
			.css('color', '#'+this.colors.cursor.color);
	},
	
	/**
	 * Object which define colors which will be used for the SSH
	 * command line.
	 * 
	 * @var object
	 */
	colors: {
		background: '000000',
		color: 'ffffff',
		cursor: {
			background: 'ffffff',
			color: '000000'
		}
	}
};