
function Lsh() {
    this.version = "0.1";
    this.info = "ぷーたろうとの対話型インタプリタです。Lispを使用してぷーたろうを育てましょ。";
    this.input_lisp = "Lisp > ";
    this.res_lisp   = "=> ";
    this.init = function() {
	if($("lsh").value == "") {
	    $("lsh").value = this.input_lisp;
	    return;
	}
	$("lsh").value += "\n" + this.input_lisp;
    };
};

var lsh = new Lsh();
lsh.init();
(function() {
    var clavier_cds=new Object(146);
    clavier_cds[8]="BackSpace";
    clavier_cds[9]="Tabulation";
    clavier_cds[12]="Milieu (pave numerique)";
    clavier_cds[13]="Enter";
    clavier_cds[16]="Shift";
    clavier_cds[17]="Ctrl";
    clavier_cds[18]="Alt";
    clavier_cds[19]="Pause";
    clavier_cds[20]="Verr Maj";
    clavier_cds[27]="Esc";
    clavier_cds[32]="Space";
    clavier_cds[33]="Page up";
    clavier_cds[34]="Page down";
    clavier_cds[35]="End";
    clavier_cds[36]="Home";
    clavier_cds[37]="Left";
    clavier_cds[38]="Up";
    clavier_cds[39]="Right";
    clavier_cds[40]="Down";
    clavier_cds[44]="Impr ecran";
    clavier_cds[45]="Inser";
    clavier_cds[46]="Delete";
    clavier_cds[91]="Menu Demarrer Windows / touche pomme Mac";
    clavier_cds[92]="Menu Demarrer Windows";
    clavier_cds[93]="Menu contextuel Windows";
    clavier_cds[112]="F1";
    clavier_cds[113]="F2";
    clavier_cds[114]="F3";
    clavier_cds[115]="F4";
    clavier_cds[116]="F5";
    clavier_cds[117]="F6";
    clavier_cds[118]="F7";
    clavier_cds[119]="F8";
    clavier_cds[120]="F9";
    clavier_cds[121]="F10";
    clavier_cds[122]="F11";
    clavier_cds[123]="F12";
    clavier_cds[144]="Verr Num";
    clavier_cds[145]="Arret defil";
    clavier_cds[229]="F";
    clavier_cds[82]="R";
    clavier_cds[71]="G";
    clavier_cds[81]="Q";
    clavier_cds[72]="H";
    clavier_cds[69]="E";
    clavier_cds[90]="Z";
    clavier_cds[89]="Y";
    clavier_cds[191]="/";
    clavier_cds[53]="%"

    function Shell() {
	this.init = function() {
	    this.info.buffer_num = this.info.row_cursor_line_num;
	    $("lsh").scrollTop = $("lsh").scrollHeight;
	}

	this.isIE = function() {
	    return /*@cc_on!@*/false;
	};

	this.info = {
		"shell_array":  new Array(),
		"row_cursor_position": 0,
		"row_cursor_line_num": 0,
		"row_max": 0,
		"row_min": 0,
		"line_max_num": 0,
		"line_min_num": 0,
		"lsh_max": 0,
		"cursor_num": $("lsh").value.length,
	        "static_word_num": 8,
	        "scrollTop": null,
	        "scrollLeft": null,
		"buffer_num": 0,
	        "cursor": ($("lsh").selectionEnd + 1)
	};

	this.set_before_cursor = function() {
	    var info = lsh.shell.info;
	    $("lsh").selectionEnd = info.cursor;
	    $("lsh").selectionStart = info.cursor;
	    $("lsh").scrollLeft = info.scrollLeft;
	    $("lsh").scrollTop = $("lsh").scrollHeight;
	};

	this.set_info = function() {
	    var info = lsh.shell.info;
	    info.scrollTop = $("lsh").scrollTop;
	    info.scrollLeft = $("lsh").scrollLeft;

	    text_array = $("lsh").value.split("\n");
	    info.line_max_num = text_array.length;
	    info.cursor_num = $("lsh").selectionEnd;


	    info.cursor =  $("lsh").selectionEnd;
	    info.row_min = 0;
	    info.row_max = 0;
	    for(var i=0,len=info.line_max_num; i < len; i++) {
		info.row_max += text_array[i].length + 1;
		info.row_min = info.row_max - (text_array[i].length + 1);
		if(info.row_min <= info.cursor_num && info.row_max >= info.cursor_num) {
		    info.row_cursor_position = info.cursor_num - info.row_min;
		    info.row_cursor_line_num = i;
		    break;
		} 
	    }

	    //"Lisp => "を削除
	    info.shell_array = new Array();
	    for(var i=0, len=text_array.length; i < len; i++) {
		if(text_array[i].indexOf(lsh.input_lisp) == 0) {
		    info.shell_array.push(text_array[i].substr(info.static_word_num-1, text_array[i].length));
		}
	    }
	    info.row_min += info.static_word_num;
	    info.row_cursor_position -= info.static_word_num;
	    info.cursor_num += 1;
	};

	this.keydown = function(e) {
	    if(!e) e=event;
	    var isKill = false;
	    var letter;
	    if (clavier_cds[e.keyCode]) {
		letter=clavier_cds[e.keyCode];
	    }else{
		letter=String.fromCharCode(e.keyCode);
	    }

	    if(this.isCtrl(e)) {
		isKill = this.ctrl_pressed(letter);
	    } else if(this.isShift(e)) {
		isKill = this.shift_pressed(letter);
	    } else if(this.isAlt(e)) {
		isKill = this.alt_pressed(letter);
	    } else {
		isKill = this.key_bind(letter);
	    }
	    
	    if(isKill){
		if(this.isIE()) {
		    e.keyCode=0;
		}
		return false;
	    }
	    return true;
	};

	this.isAlt = function(e) {
	    if (window.event) {
		return (window.event.altKey);
	    } else {
		if(e.modifiers)
		    return (e.altKey || (e.modifiers % 2));
		else
		    return e.altKey;
	    }
	};

	this.isCtrl = function(e) {
	    if (window.event) {
		return (window.event.ctrlKey);
	    } else {
		return (e.ctrlKey || (e.modifiers==2) || (e.modifiers==3) || (e.modifiers>5));
	    }
	};

	this.isShift = function(e) {
	    if (window.event) {
		return (window.event.shiftKey);
	    } else {
		return (e.shiftKey || (e.modifiers>3));
	    }
	};

	this.ctrl_pressed = function(letter) {
	    switch(letter){
		case "P":
		    this.get_back_buffer(this.info.buffer_num -= 1);
		    return true;
		case "N":
		    this.get_after_buffer(this.info.buffer_num += 1);
		    return true;
		case "A":
		    $("lsh").selectionStart = lsh.shell.info.row_min - 1;
		    $("lsh").selectionEnd = lsh.shell.info.row_min - 1;
		    return true;
		case "D":
		    this.delete_char();
		    return true;
		case "E":
		    $("lsh").selectionStart = lsh.shell.info.row_max - 1;
		    $("lsh").selectionEnd = lsh.shell.info.row_max - 1;
		    return true;
		case "F":
		    var cursor = lsh.shell.info.cursor_num;
		    if(cursor >= this.info.row_max) {
			return true;
		    }
		    $("lsh").selectionStart = cursor;
		    $("lsh").selectionEnd = cursor;
		    return true;
		case "B":
		    var cursor = lsh.shell.info.cursor_num;
		    var move_cursor = cursor - 2;
		    if(cursor <= this.info.row_min) {
			return true;
		    }
		    $("lsh").selectionStart = move_cursor;
		    $("lsh").selectionEnd = move_cursor;
		    return true;
		case "BackSpace":
		    var cursor = lsh.shell.info.cursor_num;
		    if(cursor <= this.info.row_min) {
			return true;
		    }
		    return false;
		case "K":
		    lsh.shell.kill_line();
		    return true;
		case "L":
		    $("lsh").value = lsh.input_lisp;
		    return true;
	    }
	    return false;
	};

	this.alt_pressed = function(e) {
	    return false;
	};

	this.shift_pressed = function(letter) {
	    switch(letter) {
		case "Home":
		    $("lsh").selectionStart = lsh.shell.info.row_min - 1;
		    return true;
	    }
	    return false;
	};

	this.key_bind = function(letter) {
	    switch(letter) {
		case "Up":
		    this.get_back_buffer(this.info.buffer_num -= 1);
		    return true;
		case "Down":
		    this.get_after_buffer(this.info.buffer_num += 1);
		    return true;
		case "Left":
		    if(this.info.cursor_num <= this.info.row_min) {
			return true;
		    }
		    return false;
		case "Right":
		    if(this.info.cursor_num >= this.info.row_max) {
			return true;
		    }
		    return false;
		case "BackSpace":
		    if(this.info.cursor_num <= this.info.row_min) {
			return true;
		    }
		    return false;
		case "Page up":
		    return true;
		case "Page down":
		    return true;
		case "Home":
		    $("lsh").selectionEnd = this.info.row_min - 1;
		    $("lsh").selectionStart = this.info.row_min - 1;
		    return true;
		case "Enter":
		    if(!lsh.command.is_now_eval) {
		        this.info.buffer_num = this.info.row_cursor_line_num + 1;
		        lsh.command.eval(this.info.shell_array[this.info.shell_array.length-1]);
		    }
		    return true;
		case "Tabulation":
		    if(!lsh.command.is_now_eval) {
		        this.info.buffer_num = this.info.row_cursor_line_num + 1;
			word = this.info.shell_array[this.info.shell_array.length-1];
			complet_word = "";
			len = word.length-1;
			while(true) {
			    if(word[len] == " " || word[len] == "("  || word[len] == ")" || word[len] == "\"" || len == -1) {
				break;
			    }
			    complet_word = word[len] + complet_word;
			    len--;
			}
		        lsh.command.eval("(completion \"" + complet_word + "\")");
		    }
		    return true;
	    }
	    return false;
	};

	this.kill_line = function() {
	    scrolltop = $("lsh").scrollTop;
	    var end = $("lsh").selectionEnd;
	    var start = $("lsh").selectionStart;
	    $("lsh").value = $("lsh").value.substr(0, end);
	    $("lsh").selectionEnd = end;
	    $("lsh").selectionStart = start;
	    $("lsh").scrollTop = scrolltop;
	};

	this.delete_char = function() {
	    scrolltop = $("lsh").scrollTop;
	    var end = $("lsh").selectionEnd;
	    var start = $("lsh").selectionStart;
	    $("lsh").value = $("lsh").value.substr(0, end) + $("lsh").value.substr(end+1, $("lsh").value.length);
	    $("lsh").selectionEnd = end;
	    $("lsh").selectionStart = start;
	    $("lsh").scrollTop = scrolltop;
	};

	this.get_back_buffer = function(num) {
	    if(num < 0) return
	    if(this.info.shell_array[num] != null && this.info.shell_array[num] != ""){
		scrolltop = $("lsh").scrollTop;
		$("lsh").value = $("lsh").value.substr(0, this.info.row_min -1);
		$("lsh").value += this.info.shell_array[num];
	        $("lsh").selectionStart = $("lsh").value.length;
	        $("lsh").selectionEnd = $("lsh").value.length;
	        $("lsh").scrollTop = scrolltop;
		return;
	    }
	    this.get_back_buffer(this.info.buffer_num -= 1);
	};

	this.get_after_buffer = function(num) {
	    if(num > this.info.shell_array.length) return
	    if(this.info.shell_array[num] != null && this.info.shell_array[num] != ""){
		scrolltop = $("lsh").scrollTop;
		$("lsh").value = $("lsh").value.substr(0, this.info.row_min -1);
		$("lsh").value += this.info.shell_array[num];
	        $("lsh").selectionStart = $("lsh").value.length;
	        $("lsh").selectionEnd = $("lsh").value.length;
	        $("lsh").scrollTop = scrolltop;
		return;
	    }
	    this.get_after_buffer(this.info.buffer_num += 1);
	};
    }
    var S = new Shell();
    S.init();
    lsh["shell"] = S;

})();

$("lsh").onkeydown = function(event) {
    lsh.shell.set_info();
    return lsh.shell.keydown(event);
};

$("lsh").onclick = lsh.shell.set_before_cursor;
$("lsh").onfocus = lsh.shell.set_before_cursor;
$("lsh").onblur = lsh.shell.set_info;

