// DosBox console class definition.
// An idea of dos like console construction is derived from the JSConsole script:
// http://www.codeproject.com/script/Articles/MemberArticles.aspx?amid=3290305
function DosBoxConsole() {

	// detect viewport parameters 
	var displaySize = this.getRowsColumnsSize();
	this.columns = displaySize[0];
	this.rows = displaySize[1];

	// attach document to the root in a visual tree
	this.root = document.body;
	
	// defines cursor position
	this.cursorPosition = {row:0,column:0};
	this.charGrid = new Array(this.rows);
	
	for (var i = 0; i < this.rows; i++) {
		var textNode = document.createTextNode('');
		this.charGrid[i] = textNode;
		this.root.appendChild(textNode);
		if (i < this.rows - 1) {
			this.root.appendChild(document.createElement('br'));
		}
	}
}


// Method returns array containing 2 elements: [0]=>columns, [1]=>rows which defines viewport size.
// !Urgent! Calculations are valid for font size: 16px  and line-height: 1.4 em
DosBoxConsole.prototype.getRowsColumnsSize = function(){
	
	var width,height;
	var columnsRowsCount = new Array();
	
	if (!window.opera && document.documentElement && (!document.compatMode || document.compatMode=="CSS1Compat")) {
		height = document.documentElement.clientHeight;
		width =  document.documentElement.clientWidth;
	}else{		
		height = document.body.clientHeight;
		width = document.body.clientWidth;
	}
	
	columnsRowsCount[0] = Math.floor(width/10)-1;
	columnsRowsCount[1] = Math.floor(height/22.4)-1;
	
	return columnsRowsCount;
}	

DosBoxConsole.prototype.printAt = function(row, column, str, cycle) {

	if (row >= this.rows || row < 0 || column < 0 || !str) {
		return;
	}
	
	// get the text in the target row
	var oldRow = this.charGrid[row].data;
	// tentatively put the new text for the row in newRow. This is probably too long or too short
	var newRow = oldRow.substring(0, column) + str;
	
	if (newRow.length < this.columns) {
		// the text was too short, so get the remaining characters from the old string.
		// E.g.: oldRow = "0123456789", printing "hi" over '4' so newRow = "0123hi", then appending "6789" to get "0123hi6789"
		newRow += oldRow.substring(column + str.length);
		// move the cursor to the character after the new string, e.g. just after "hi".
		this.cursorPosition.row = row;
		this.cursorPosition.column = column + str.length;
	} else {
		// wrap to the next row.
		this.cursorPosition.row = row+1;
		this.cursorPosition.column = 0;
		
		if (cycle && this.cursorPosition.row >= this.rows) {
			// moved passed the bottom of the console.  Need to delete the first line, and move each line up by one.
			for (var rowIndex = 0; rowIndex < this.rows - 1; rowIndex++) {
				this.charGrid[rowIndex].data = this.charGrid[rowIndex+1].data;
			}
			// After moving up, there needs to be a new row at the bottom. Set to empty string.
			var emptyRow = '';
			for (var col = 0; col < this.columns; col++) {
				emptyRow += ' ';
			}
			this.charGrid[this.rows-1].data = emptyRow;
			// Cycled the lines up, so the current row should cycle by one as well
			this.cursorPosition.row--;
			row--;
		}
	}
	
	// truncate the text if it is too long
	if (newRow.length > this.columns) {
		newRow = newRow.substring(0, this.columns);
	}
	// set the text to the current row.
	this.charGrid[row].data = newRow;
};

DosBoxConsole.prototype.print = function(str) {
	// get new location of cursor after text added
	var newColumnPos = this.cursorPosition.column + str.length;
	
	if (newColumnPos > this.columns) {
		// text is too long to fit on one line.  Add as much as possible, then recursively call print with the remainder of the string
		
		var charsLeftOnCurLine = this.columns - this.cursorPosition.column;
		var s = str.substring(0, charsLeftOnCurLine);
		
		// print the first part
		this.print(s);
		
		// print rest of string
		this.print(str.substring(charsLeftOnCurLine));
		
	} else {
		// print the string at the current cursor position
		this.printAt(this.cursorPosition.row, this.cursorPosition.column, str, true);
	}

};

DosBoxConsole.prototype.println = function(str) {

	if (!str) {
		str = '';
	}
	
	// Actually, we don't add line-breaks. We simply pad out the line with spaces to that the cursor will be forced to the next line.
	var extraSpaces = this.columns - ((this.cursorPosition.column + str.length) % this.columns);
	var s2 = str;
	for (var i = 0; i < extraSpaces; i++) {
		s2 += ' ';
	}
	this.print(s2);
};
