

var left;
var right;
var transcript;
var branch_template;
var said_template;
var saying_template;
var temp;
var next_step;


function body_load()
	{
	var noscript = document.getElementById( "noscript" );
	noscript.parentNode.removeChild( noscript );
	
	transcript = document.getElementById( "transcript" );
	branch_template = document.getElementById( "branch_template" );
	said_template = document.getElementById( "said_template" );
	saying_template = document.getElementById( "saying_template" );
	temp = document.getElementById( "temp" );
	next_step = document.getElementById( "next_step" );
	
	left = init( "left", "jane" );
	right = init( "right", "alex" );
	left.other = right;
	right.other = left;
	}


function init( div_id, who )
	{
	var side =
		{ 
			other: null, 
			div: document.getElementById( div_id ), 
			who: who, 
			branches: [],
			focused_branch: null,
			msgs: [],
		};
	focus_branch( side, add_branch( side ));
	return side;
	}


function add_branch( side )
	{
	var html = branch_template.innerHTML
		.replace( "${index}", side.branches.length + 1 );
	var branch_div = new_div( html );
	side.div.appendChild( branch_div );
	
	html = saying_template.innerHTML
		.replace( "${who}", side.who );
	var saying_div = new_div( html );
	branch_div.appendChild( saying_div );

	var branch = 
		{ 
			div: branch_div, 
			saying_div: saying_div,
			textarea: saying_div.childNodes[ 1 ].childNodes[ 0 ],
			msgs: [],
			re_msg: null,
		};
	side.branches.push( branch );
	
	return branch;
	}


function split_branch( side, branch, re_msg )
	{
	var at = index_of( branch.msgs, re_msg );
	var new_branch = add_branch( side );
	
	var src = branch.msgs;
	var tgt = new_branch.msgs;
	for (var i = 0; i <= at; i++)
		{
		var msg = src.shift();
		branch.div.removeChild( msg.div );
		new_branch.div.insertBefore( msg.div, new_branch.saying_div );
		new_branch.re_msg = msg;
		tgt.push( msg );
		}
	
	side.div.insertBefore( new_branch.div, branch.div );
	
	return new_branch;
	}


function merge_branches( side, src_branch, tgt_branch )
	{
	transcribe( "*" + side.who + " merges" );
	var src = src_branch.msgs;
	var tgt = tgt_branch.msgs;
	for (var i = 0; i <= src.length; i++)
		{
		var msg = src.shift();
		src_branch.div.removeChild( msg.div );
		tgt_branch.div.insertBefore( msg.div, tgt_branch.saying_div );
		tgt_branch.re_msg = msg;
		tgt.push( msg );
		if (tgt_branch == side.focused_branch)
			mark_read( msg );
		}
	side.div.removeChild( src_branch.div );
	side.branches.pop(); // Assumes src_branch is always the last.
	}


function focus_branch( side, branch )
	{
	var was = side.focused_branch;
	if (branch == was) return;
	if (was)
		was.textarea.className = "";
	branch.textarea.className = "focused";
	side.focused_branch = branch;
	
	for (var i = 0; i < branch.msgs.length; i++)
		mark_read( branch.msgs[ i ] );
	}

function mark_unread( msg )
	{
	msg.div.className = msg.div.className + " unread";
	}

function mark_read( msg )
	{
	var style = msg.div.className;
	var new_style = style.replace( " unread", "" );
	if (style != new_style)
		msg.div.className = new_style;
	}


function said( side, branch, me, who, what )
	{
	html = said_template.innerHTML
		.replace( "${me_you}", me? "me" : "you" )
		.replace( "${who}", who )
		.replace( "${what}", what );
	var div = new_div( html );

	var re = re_of( side, what );
	var msg =
		{
			who: who,
			what: what,
			branch: branch,
			re: re,
			div: div,
		};
		
	branch.div.insertBefore( msg.div, branch.saying_div );
	branch.msgs.push( msg );	
	branch.re_msg = msg;
	side.msgs.push( msg );
	
	return msg;
	}


function find_msg_for( side, re )
	{
	var i = side.msgs.length;
	while (--i >= 0)
		{
		var msg = side.msgs[ i ];
		if (msg.re == re)
			return msg;
		}
	return null;
	}


function index_of( side, re )
	{
	var i = side.msgs.length;
	while (--i >= 0)
		{
		var msg = side.msgs[ i ];
		if (msg.re == re)
			return msg.branch;
		}
	return null;
	}


function send( side )
	{
	var branch = side.focused_branch;
	var text = branch.textarea.value;
	var re = branch.re_msg && branch.re_msg != side.msgs[ side.msgs.length - 1 ]
		? branch.re_msg.re : null;
	branch.textarea.value = "";
	said( side, branch, true, side.who, text );
	receive( side.other, side.who, text, re );
	}


function receive( side, who, what, re )
	{
	transcribe( who + ": " + what + (re? " (re: " + re + "...)" : "") );
	var last_msg = side.msgs.length > 0? side.msgs[ side.msgs.length - 1 ] : null;
	var re_msg = re? find_msg_for( side, re ) : last_msg;
	var branch = re_msg? re_msg.branch : side.focused_branch;
	if (branch.re_msg != re_msg)
		branch = split_branch( side, branch, re_msg );
	else if (branch.textarea.value)
		{
		branch = add_branch( side );
		transcribe( "*" + side.who + " branches (was already typing)" );
		}
	var msg = said( side, branch, false, who, what );
	if (branch != side.focused_branch)
		mark_unread( msg );
	}


function re_of( side, text )
	{
	var l = 5;
	var re = text.slice( 0, l );
	for (var i = 0; i < side.msgs.length; i++)
		{
		var msg = side.msgs[ i ];
		var have = msg.what;
		while (l < text.length && have.slice( 0, l ) == re)
			re = text.slice( 0, ++l );
		}
	return re;
	}



function chat_input_focus( sender )
	{
	var side = side_of( sender );
	for (var i = 0; i < side.branches.length; i++)
		{
		var branch = side.branches[ i ];
		if (sender == branch.textarea)
			{
			focus_branch( side, branch );
			break;
			}
		}
	}


function chat_input_keypress( sender, event )
	{
	var keycode;
	if (window.event)
		keycode = window.event.keyCode;
	else if (event)
		keycode = event.which;
	else
		return true;
	
	if (keycode == 13)
		{ // <enter>
		send_to_other( sender );
		return false;
		}
	if (keycode == 60)
		{ // "<"
		merge_with_last( sender )
		return false;
		}

	// transcribe( "/" + side_of( sender ).who + " types " + keycode );
	}


function send_to_other( textarea )
	{
	var side = side_of( textarea );
	send( side );
	}

function merge_with_last( textarea )
	{
	var side = side_of( textarea );
	var last_branch = side.branches[ side.branches.length - 1 ];
	if (side.focused_branch != last_branch)
		merge_branches( side, last_branch, side.focused_branch );
	}


function side_of( elt )
	{
	var here = elt;
	while (here)
		{
		if (here.id == "left") return left;
		if (here.id == "right") return right;
		here = here.parentNode;
		}
	return null;
	}


function transcribe( what )
	{
	var p = document.createElement( 'p' );
	var t = document.createTextNode( what );
	p.appendChild( t );
	transcript.appendChild( p );
	}


function new_div( html )
	{
	temp.innerHTML = html;
	var div = temp.childNodes[ 0 ];
	temp.removeChild( div );
	return div;
	}


function index_of( list, elt )
	{
	var i = 0;
	var n = list.length;
	while (i < n)
		{
		if (list[ i ] === elt)
			return i;
		i++
		}
	return -1;
	}


// Sample Scenarios


function say( side, what )
	{
	type( side, what );
	send( side );
	}

function type( side, what )
	{
	side.focused_branch.textarea.value = what;
	}

function go( side, last )
	{
	// transcribe( "*" + side.who + " focuses on " + last + "..." );
	var branch = find( side, last );
	if (branch)
		focus_branch( side, branch );
	}

function merge( side, last )
	{
	var branch = find( side, last );
	if (branch)
		merge_branches( side, branch, side.focused_branch );
	}

function find( side, last )
	{
	for (var i = 0; i < side.branches.length; i++)
		{
		var branch = side.branches[ i ];
		var last_msg = branch.msgs[ branch.msgs.length - 1 ];
		if (last_msg.what.slice( 0, last.length ) == last)
			return branch;
		}
	return null;
	}


var current_story = null;
var current_step = 0;

function replay( story )
	{
	current_story = make_playable( story );
	current_step = 0;
	next_step.className = "";
	play_next_step();
	}

function play_next_step()
	{
	if (!current_story) return;
	if (current_step >= current_story.length)
		return replay_done();
	var step = current_story[ current_step++ ];
	play_step( step );
	}

function replay_done()
	{
	transcribe( "*script completed." );
	current_story = null;
	current_step = 0;
	next_step.className = "hidden";
	}

function make_playable( story )
	{
	var play = [];
	for (var i = 0; i < story.length; i++)
		{
		var step = story[ i ];
		if (step[0] == say)
			{
			play.push( [ type, step[1], step[2] ] );
			step = [ send, step[1], null ];
			}
		play.push( step );
		}
	return play;
	}


function play( story )
	{
	for (var i = 0; i < story.length; i++)
		play_step( story[ i ] );
	}

function play_step( step )
	{
	var func = step[ 0 ];
	var side = (step[ 1 ] == jane)? left : right;
	var arg = step[ 2 ];
	func( side, arg );
	}


var jane = 1;
var alex = 2;

var story1=
	[
		[ say, jane, "How about lunch tomorrow?" ],
		[ type, alex, "I'd love to, how about Spag" ],
		[ say, jane, "Oh, and did you see my latest blog post?" ],
		[ say, alex, "I'd love to, how about Spaghetti Factory at 11:30?" ],
		[ go, alex, "Oh, and" ],
		[ go, jane, "I'd love to" ],
		[ type, jane, "Agr" ],
		[ say, alex, "Yes, nice!" ],
		[ say, jane, "Agreed." ],
		[ go, jane, "Yes" ],
	];

var story2 =
	[
		[ say, jane, "Hi Alex, can we discuss XY now?" ],
		[ say, right, "Yes, sure." ],
		[ say, jane, "I see you fooed the bar." ],
		[ type, right, "Well, did I really? I did" ],
		[ say, jane, "And you shmarfed the shlomo." ],
		[ say, right, "Well, did I really? I didn't mean to." ],
		[ go, right, "And you" ],
		[ type, right, "Of course, we" ],
		[ go, jane, "Well, did" ],
		[ say, jane, "OK, I'm reverting that." ],
		[ say, right, "Of course, we discussed that. Don't you remember?" ],
	];

var story3 =
	[
		[ say, jane, "Hi Alex, how are you?" ],
		[ say, right, "Actually, I'm feeling a little tired." ],
		[ type, jane, "Ah, stayed" ],
		[ say, right, "How about you?" ],
		[ say, jane, "Ah, stayed up late again, eh?" ],
		[ go, jane, "How about" ],
		[ say, jane, "I'm splendid. Just had an uplifting experience." ],
		[ type, jane, "Your mother? She just" ],
		[ go, right, "I'm splendid" ],
		[ say, right, "Really? What?" ],
		[ say, right, "I'm curious!" ],
		[ merge, jane, "I'm curious" ],
		[ say, jane, "Your mother? She just complimented me on my career!" ],
		[ say, right, "Hah. That truly is remarkable. Well done." ],
	];


