/**
Benjamin Cabell
q121001@besiex.org
2001 copyright, all rights reserved.
LED controller

if you see this, you're a pretty cool fellow, or a pretty lame one.  history will decide.
*/
// Pre-load Images
var imagesHolder = new Array();

function preLoad(name) {
	var a = imagesHolder.length;
	imagesHolder[a] = new Image();
	imagesHolder[a].src = name;
}

function preLoad_mod (name) {
	preLoad(DEFAULT_IMAGE_PATH+name);
}


var DEFAULT_IMAGE_PATH = "/styles/gulliblebum/ledwriter/small_jpg_gif_mix/";

preLoad_mod("blank.jpg");
preLoad_mod("a.jpg");
preLoad_mod("b.jpg");
preLoad_mod("c.jpg");
preLoad_mod("d.jpg");
preLoad_mod("e.jpg");
preLoad_mod("f.jpg");
preLoad_mod("g.jpg");
preLoad_mod("h.jpg");
preLoad_mod("i.jpg");
preLoad_mod("j.jpg");
preLoad_mod("k.jpg");
preLoad_mod("l.jpg");
preLoad_mod("m.jpg");
preLoad_mod("n.jpg");
preLoad_mod("o.jpg");
preLoad_mod("p.jpg");
preLoad_mod("q.jpg");
preLoad_mod("r.jpg");
preLoad_mod("s.jpg");
preLoad_mod("t.jpg");
preLoad_mod("u.jpg");
preLoad_mod("v.jpg");
preLoad_mod("w.jpg");
preLoad_mod("x.jpg");
preLoad_mod("y.jpg");
preLoad_mod("z.jpg");
preLoad_mod("0.jpg");
preLoad_mod("1.jpg");
preLoad_mod("2.jpg");
preLoad_mod("3.jpg");
preLoad_mod("4.jpg");
preLoad_mod("5.jpg");
preLoad_mod("6.jpg");
preLoad_mod("7.jpg");
preLoad_mod("8.jpg");
preLoad_mod("9.jpg");
preLoad_mod("fslash.jpg");
preLoad_mod("mixa.gif");
preLoad_mod("mixb.gif");
preLoad_mod("mixc.gif");
preLoad_mod("period.jpg");
preLoad_mod("dash.jpg");
preLoad_mod("question.jpg");
preLoad_mod("comma.jpg");
preLoad_mod("colon.jpg");
preLoad_mod("lt.jpg");
preLoad_mod("gt.jpg");
preLoad_mod("apostrophe.jpg");

// global vars required by LEDController...
var LEDController_handles = new Array();

function LEDController (name,rows,cols,defaultMessage) {
	LEDController_handles[name] = this;  // we need this so we can refer to ourselves in setTimeouts/etc.

	this.name = name;

	this.rows = rows;
	this.cols = cols;

	this.message = ""; // The message this LED is working to display...
	this.defaultMessage = (defaultMessage == null) ? "" : defaultMessage; // This is the message the display wants to show all the time, and switches from for tool tip help.

	this.default_writespeed = 50;


	this.timeouts = new Array();

	this.isClicking = false;
	this.clickSound = 'bcx_click_long_single.wav';
	this.isWriting = false; // tells whether it's in the middle of writing something...

	this.is_emergency_stop = false;

	// Path for images...  so i can switch between larger and higher resolution sources...

	this.image_path = DEFAULT_IMAGE_PATH;
	this.image_height = 20;
	this.image_width = 13;

	// Methods...
	this.generate_table = LEDController_generate_table;

	this.restoreDefaultMessage = LEDController_restoreDefaultMessage;
	this.addTimeout = LEDController_addTimeout;
	this.clearAllTimeouts = LEDController_clearAllTimeouts;
	this.show_by_rowcol = LEDController_show_by_rowcol;
	this.show_by_pos = LEDController_show_by_pos;
	this.wrap_message = LEDController_wrap_message;
	this.clearDisplay = LEDController_clearDisplay;
	this.setText = LEDController_setText;
	this.showMessage = LEDController_showMessage;
	this.emergency_stop = LEDController_emergency_stop;
}


function LEDController_emergency_stop() {
	this.is_emergency_stop = true;
	stopSound(this.clickSound);
	this.clearAllTimeouts();
}


//
// CREATE THE TABLE FOR THE LEDs
//
function LEDController_generate_table() {
	var tabledata = ""; // Just hold (and show) the table HTML

	var table_width = this.image_width*this.cols;
	var table_height = this.image_height*this.rows;

	tabledata += '<table border=0 cellspacing=0 cellpadding=0 height='+table_height+' width='+table_width+'>\n';

	for (var i=0,p=0;i<this.rows;i++) {
		if (i != 0)
			tabledata += '</tr>\n<tr height=2><td colspan='+this.cols+' height=2><img src='+this.image_path+'blank2x2.gif><td></tr>';

		tabledata += '<tr height='+this.image_height+'>\n';

		for (var j=0;j<this.cols;j++) {
			tabledata += '<td height='+this.image_height+' width='+this.image_width+'><img name="'+this.name+'_'+i+'_'+j+'" height='+this.image_height+' width='+this.image_width+' src="'+this.image_path+'blank.jpg"></td>\n';
			p++;
		}
	}

	tabledata += '</table>\n';
	//alert(tabledata);
	//document.writeln(tabledata);
	return tabledata;
}


function LEDController_restoreDefaultMessage() {
	if (this.is_emergency_stop) return;

	this.clearDisplay();
	this.setText(this.defaultMessage,0);
}


function LEDController_addTimeout(timeout) {
	var a = this.timeouts.length;
	this.timeouts[a] = timeout;
}

function LEDController_clearAllTimeouts() {
	for (var i=0;i<this.timeouts.length;i++) {
		window.clearTimeout(this.timeouts[i]);
	}

	this.timeouts = new Array();
}



// Updates a single LED given the row, column, the character to show, and whether or not it should be preceeded by a "mix" (the character roll).

function LEDController_show_by_rowcol (row,column,character,requires_mix) {
	// Do mix delay...

	//- FOR NETSCAPE I NEED TO SUPPORT undefined (IE 5.0 does not support undefined)
	//requires_mix = null


	if ((requires_mix == null) || (requires_mix == 1)) {
		ran = Math.random();

		if (ran < 0.3333)
			mfile = "mixa.gif";
		else
		if (0.333 < ran < 0.6666)
			mfile = "mixb.gif";
		else
			mfile = "mixc.gif";


		if (character != " ")
			document.images[this.name+"_"+row+"_"+column].src = this.image_path+mfile;

		delay = (character.charCodeAt(0)-97)*20;

		if (!isNaN(parseInt(character)))
			delay = parseInt(character)*20;

		if (character == " ")
			delay = 0;
		else
			delay = 250;


		if (delay < 0) delay = 0;

		if (!((is.ns) && (is.v >= 5))) {
			if (character == "'") // otherwise we get an unterminated string...
				character = "\\'";

			var mixtimer =
					setTimeout("LEDController_handles['"+this.name+"'].show_by_rowcol ("+row+","+column+",'"+character+"',0)", delay);
			this.addTimeout(mixtimer);
			return;
		}
	}

/*
	// if sound thing is loaded...
	if (!isClicking && isWriting) {
		playSound(clickSound);
		isClicking = true;
	}
*/
	var iname = "";

	switch (character) {
		case " " : iname = "blank.jpg"; break;
		case "/" : iname = "fslash.jpg"; break;
		case "." : iname = "period.jpg"; break;
		case "-" : iname = "dash.jpg"; break;
		case "*" : iname = "mixa.gif"; break;
		case "?" : iname = "question.jpg"; break;
		case "," : iname = "comma.jpg"; break;
		case ":" : iname = "colon.jpg"; break;
		case "'" : iname = "apostrophe"; break;
		case ">" : iname = "gt.jpg"; break;
		case "<" : iname = "lt.jpg"; break;
		default:
				var charCode = character.charCodeAt(0);
				if ((charCode >= 97 && charCode <= 122) || (charCode >= 48 && charCode <= 57)) {
					iname = character+".jpg";
				} else
					iname = "mixa.gif"
	}

	document.images[this.name+"_"+row+"_"+column].src = this.image_path+iname;
}


//
// Update LED segment given only position and character...  (it computers row and column)
//

function LEDController_show_by_pos (pos,character) {
	var row = Math.floor(pos/this.cols);
	var col = pos%this.cols;

	this.show_by_rowcol(row,col,character,1);
}


function LEDController_wrap_message() {
	// break non-hyphenated words with a \n
//	alert("OLD: "+this.message);
	var new_message = "";

	var chars_on_line = 0; // characters on the "current" line
	var line_start_pos = 0;
	var last_breakable_pos = 0;


	for (var i=0;i<this.message.length;i++) {
		chars_on_line++;

		if (chars_on_line > this.cols) {
			//alert(" i want to break at "+i);
			// at end of physical line...  check to see if we need to wrap...
			if (line_start_pos != 0)
				new_message += "\n";

			new_message += this.message.substring(line_start_pos,last_breakable_pos);

			line_start_pos = last_breakable_pos; // because i define the pos as the location of "-" or " " +1, see below
			chars_on_line = i-last_breakable_pos;
		}

		if (i+1 == this.message.length) {
			// Dump whatever is in the last buffer
			if (line_start_pos != 0)
				new_message += "\n";

			new_message += this.message.substring(line_start_pos);
			// - I think I need code here to strip a trailing "\n" if there is one in the new_message
		} else
		if (this.message.charAt(i) == " " || this.message.charAt(i) == "-")
			last_breakable_pos = i+1;
		else
		if (this.message.charAt(i) == "\n") {
			// we have a natural break, so dump stuff, etc.
			if (line_start_pos != 0)
				new_message += "\n";

			new_message += this.message.substring(line_start_pos,i);
			line_start_pos = i+1;
			chars_on_line = 0;
		}
		// if it then breaks naturally, ignore the last \n, if it was the last breakable pos
	}

	this.message = new_message;
//	alert("NEW: "+this.message);
}


// Clear the display...

function LEDController_clearDisplay () {
	if (this.is_emergency_stop) return;

	if (this.isClicking) {
		stopSound(this.clickSound);
		this.isClicking = false;
	}

	this.clearAllTimeouts();

	for (var i=0;i<this.rows;i++) {
		for (var j=0;j<this.cols;j++) {
				var r = new RegExp("([a-z0-9_]*.[a-z0-9]*)$","i");
				r.exec(document.images[this.name+"_"+i+"_"+j].src);
				if (RegExp.$1 != "blank.jpg")
					document.images[this.name+"_"+i+"_"+j].src = this.image_path+"blank.jpg";
		}
	}
}



function LEDController_setText(amessage,writespeed) {
	if (this.is_emergency_stop) return;

	if (writespeed == null || writespeed == "" || isNaN(writespeed))
		writespeed = this.default_writespeed;

	this.clearDisplay();

	if (amessage == "")
		return; // nothing to do...

	this.message = amessage.toLowerCase(); // Only one set of letters, for one case...

	this.wrap_message();

	// Activate \n, so that it means something in this LED world...  let \n wrap display
	this.message = this.message.replace(/\\n/gi,"\n");

	pos = 0;
	lastPos = 0;

	while ((pos = this.message.indexOf("\n",lastPos)) != -1) {
		var numSpaces = this.cols-(pos-(lastPos+1))%this.cols-1;

		var spaces = "";
		for (var i=0;i<numSpaces;i++) {
			spaces += " ";
		}

		var a = this.message.substr(0,pos); // up to the last \n
		var b = this.message.substr(pos+1); // from the last \n to the end

		this.message = a+spaces+b;

		lastPos = pos+numSpaces;
	}

	// Call for the message display..
	this.showMessage(0,writespeed);
}



// Shows the message through time-delayed semi-recursion...  One character at a time...
// This starts it off.
// startAt is the index in the message to start.  writespeed is the delay in ms between character updates

function LEDController_showMessage(startAt,writespeed) {
	if (startAt == 0) {
		this.isWriting = true;
	}

	if (this.isWriting && !this.isClicking) {
		// if sound thing is loaded...
		if (!this.isClicking) {
			playSound(this.clickSound);
			this.isClicking = true;
		}
	}

	// offset for wrap around...
	if (startAt%(this.rows*this.cols) == 0 && startAt != 0) {
		this.clearAllTimeouts();

		for (var i=0;i<this.rows;i++) {
			for (var j=0;j<this.cols;j++) {
				document.images[this.name+"_"+i+"_"+j].src = this.image_path+"blank.jpg";
			}
		}

	}

	//-BUG: something wrong where it skips the page roll delay , try 11x1 and the history message...  it immediately clears every other line or so for the History and other links
	pos = startAt%(this.rows*this.cols);

	if ((startAt+1)%(this.rows*this.cols) == 0) {
		tempWritespeed = 1000;
		stopSound(this.clickSound);
		this.isClicking=false;
	} else
		tempWritespeed = writespeed;


	this.show_by_pos(pos,this.message.charAt(startAt++));

	if (((startAt != (this.message.length))))
		if (this.message.charAt(startAt) == " " || writespeed == 0) {
			if ((is.ns) && (is.v >= 5)) {
				// For some odd reason Netscape 6.0 fucks everything up if the code is done as I want it...
				if (writespeed == 0)
					writespeed = 1;
				counter = setTimeout("LEDController_handles['"+this.name+"'].showMessage("+startAt+","+writespeed+")", tempWritespeed);
				this.addTimeout(counter);
			} else
				this.showMessage(startAt,writespeed);
		} else {
			counter = setTimeout("LEDController_handles['"+this.name+"'].showMessage("+startAt+","+writespeed+")", tempWritespeed);
			this.addTimeout(counter);
		}

	if (startAt == this.message.length) {
		this.isWriting = false;

		if (this.isClicking) {
			stopSound(this.clickSound);
			this.isClicking = false;
		}
	}
}


//setText("*abcdefghijklmnopqrstuvwxyz01234567890.-/?*")