"use strict";

/*
a controller for scrolling text horizontally (left)
or vertically (up) within a defined region.

marqueeData: 
{ 
	x: pixel x of display box,
	y: pixel y of display box,
	width: display box width in pixels, // text will be centered within box
	height: display box height in pixels,
	
	dir: scroll direction, // 0/false = horiz, 1/true = vert
	rate: scroll rate, // in 1/8px per frame
	loop: repeat contents after end (true/false), // if false, final content will be held
	content: string to scroll past, // newlines are honored on vert, treated as a full width of whitespace in horiz
	background: html color or canvas gradient/pattern for background,
	clear: clear the region for text before drawing (true/false) e.g. for cutaway text,
}
controls: the Controls object for advancing (speeding) this marquee
callback: a function(iteration) to be called when the marquee finishes or loops
	iteration: number of times the marquee content has gone by
tileSheet: if present, the font TileSheet (ASCII indexed)
*/
var Marquee = function(marqueeData,controls,callback,tileSheet){
	if (!tileSheet){
		var windowImg = SDS_Load_Image("art/sheets/interface/ending-font.png");
		this.tileSheet = new TileSheet(3, 4, 4, 4, windowImg);
	}
	else{
		this.tileSheet = tileSheet;
	}

	this.x = marqueeData.x;
	this.y = marqueeData.y;
	this.width = marqueeData.width;
	this.height = marqueeData.height;
	this.dir = marqueeData.dir ? true : false
	this.rate = marqueeData.rate;
	this.background = marqueeData.background;
	this.clearBg = marqueeData.clear;

	// canvas the marquee text will be composited into, which will in turn be drawn to screen
	this.compCanvas = document.createElement('canvas');
	this.compCanvas.width = this.width;
	this.compCanvas.height = this.height;
	this.compCanvas.getContext('2d').clearRect(0,0,this.compCanvas.width,this.compCanvas.height);
	
	this.textCols = this.width >> this.tileSheet.tile_width;
	if (!this.dir) textCols+=2; // if horizontal, will need +1 to fill any remaining space and +1 for wrapping
	this.textRows = this.dir ? (this.height >> this.tileSheet.tile_height)+2 : 1;
	// gonna use 1.5x line spacing, but because *2/3 is not an oldschool-friendly op,
	// we'll keep the row count based on 1x spacing, at least for now.

	// canvas holding the current chunk of pre-blocked text
	this.textCanvas = document.createElement('canvas');
	this.textCanvas.width = this.textCols << this.tileSheet.tile_width;
	this.lineHeight = (1 << this.tileSheet.tile_height) + (1 << (this.tileSheet.tile_height-1));
	this.textCanvas.height = this.textRows * this.lineHeight;
	this.textCanvas.getContext('2d').clearRect(0,0,this.textCanvas.width,this.textCanvas.height);

	this.controls = controls;

	this.callback = callback;
	
	this._heap = {};

	this.contentRows = [];
	this._buildRows(marqueeData.content); // text in each row of the displayed marquee
	this.rowStart = 0;
	this.rowEnd = this.textRows;
	this.colStart = 0;
	this.colEnd = this.textCols;
	this.iters = 0;

	this.scroll = this.dir ? -(this.compCanvas.height<<3) : -(this.compCanvas.width<<3);

	this._redrawText();
};

	Marquee.prototype._buildRows = function(content){
		this.contentRows = [];
		if (this.dir){
			this._heap.lines = content.split('\n');
			for (this._heap.l=0; this._heap.l<this._heap.lines.length; ++this._heap.l){
				this._heap.words = this._heap.lines[this._heap.l].split(' ');
				
				this._heap.buf = "";
				for (this._heap.w=0; this._heap.w<this._heap.words.length; ++this._heap.w){
					if (this._heap.buf.length==0){
						// first word always goes, even if it's too long
						// (avoid softlocks)
						this._heap.buf += this._heap.words[this._heap.w];
					}
					else if (this._heap.buf.length + this._heap.words[this._heap.w].length + 1 <= this.textCols){
						this._heap.buf += ' '+this._heap.words[this._heap.w];
					}
					else{
						this.contentRows.push(this._heap.buf);
						this._heap.buf = "";
						--this._heap.w; // try same word again next iteration
					}
				}
				this.contentRows.push(this._heap.buf);
			}
			// spaces-center any rows less than display width
			for (this._heap.row=0; this._heap.row<this.contentRows.length; this._heap.row++){
				this._heap.padSize = this.textCols - this.contentRows[this._heap.row].length;
				this._heap.padSize = Math.max(this._heap.padSize,0);
				this._heap.padHalf = this._heap.padSize>>1;
				this._heap.padLeft = "";
				for (this._heap.i=0; this._heap.i<this._heap.padHalf; ++this._heap.i){
					this._heap.padLeft += ' ';
				}
				this._heap.padRight = this._heap.padLeft;
				// if an odd number of spaces needed, make the right larger
				if (this._heap.padSize&1){
					this._heap.padRight += ' ';
				}
				this.contentRows[this._heap.row] = this._heap.padLeft + this.contentRows[this._heap.row] + this._heap.padRight;
			}
		}
		else{
			this._heap.spacer = "";
			for (this._heap.i=0; this._heap.i<this.textCols; ++this._heap.i){
				this._heap.spacer += ' ';
			}
			this.contentRows.push(content.replace('\n',this._heap.spacer));
		}
	}

	Marquee.prototype._redrawText = function(){
		this.textCanvas.getContext('2d').clearRect(0,0,this.textCanvas.width,this.textCanvas.height);

		if (this.background){
			this.textCanvas.getContext('2d').fillStyle = this.background;
			this.textCanvas.getContext('2d').fillRect(0,0,this.textCanvas.width, this.textCanvas.height);
		}

		for (this._heap.row=0; this._heap.row<this.rowEnd-this.rowStart; this._heap.row++){
			for (this._heap.col=0; this._heap.col<this.colEnd-this.colStart; this._heap.col++){
				if (this._heap.row+this.rowStart<this.contentRows.length && this._heap.col+this.colStart<this.contentRows[this._heap.row].length){
					this._drawCharacter(this.contentRows[this._heap.row+this.rowStart].charCodeAt(this._heap.col+this.colStart),this._heap.col,this._heap.row);
				}
				else{
					this._drawCharacter(" ".charCodeAt(0),this._heap.col,this._heap.row);
				}
			}
		}
	};
	Marquee.prototype._drawCharacter = function(charcode,col,row){
		this.textCanvas.getContext('2d').clearRect(
			col<<this.tileSheet.tile_width,
			row*this.lineHeight+(1<<(this.tileSheet.tile_height-2)),
			this.tileSheet.tile_pixel_width,
			this.tileSheet.tile_pixel_height
		);
		this.tileSheet.drawIntoCanvas(
			this.textCanvas,
			charcode,
			col<<this.tileSheet.tile_width,
			row*this.lineHeight+(1<<(this.tileSheet.tile_height-2))
		);
	};
	Marquee.prototype._drawControls = function(){
		// straight most-of-1-line data copy.
		// the formatted string is in the tileset.
		for (this._heap.col=0; this._heap.col<14; this._heap.col++){
			this.tileSheet.drawIntoCanvas(
				this.compCanvas,
				this._heap.col+1,
				this._heap.col<<this.tileSheet.tile_width,
				0*this.lineHeight+(1<<(this.tileSheet.tile_height-2))
			);
		}
	};

	Marquee.prototype.Update = function(){
		// scroll
		if (this.controls){
			if (this.controls.held.A || this.controls.held.up || this.controls.held.left){
				this.scroll += this.rate<<2;
			}
			else if (this.controls.held.B || this.controls.held.down || this.controls.held.right){
				//this.scroll += 0;
			}
			else{
				this.scroll += this.rate;
			}
		}
		else{
			this.scroll += this.rate;
		}

		// update row/col range if needed
		// and redraw text
		this._heap.redraw = false;
		this._heap.end = false;
		if (this.dir){
			while (this.compCanvas.height+(this.scroll>>3) > this.textCanvas.height && this.rowEnd<this.contentRows.length){
				++this.rowStart;
				++this.rowEnd;
				this.scroll -= this.lineHeight<<3;
				this._heap.redraw = true;
			}
			if (this.compCanvas.height+(this.scroll>>3) > this.textCanvas.height){
				this.scroll = (this.textCanvas.height - this.compCanvas.height)<<3;
				this._heap.end = true;
			}
		}
		else{
			while (this.compCanvas.width+(this.scroll>>3) > this.textCanvas.width && this.colEnd<this.contentRows[0].length){
				++this.colStart;
				++this.colEnd;
				this.scroll -= this.tileSheet.tile_pixel_width<<3;
				this._heap.redraw = true;
			}
			if (this.compCanvas.width+(this.scroll>>3) > this.textCanvas.width){
				this.scroll = (this.textCanvas.width - this.compCanvas.width)<<3;
				this._heap.end = true;
			}
		}

		if (this._heap.redraw){
			this._redrawText();
		}

		if (this._heap.end){
			if (this.loop){
				this.rowStart = 0;
				this.rowEnd = this.textRows;
				this.colStart = 0;
				this.colEnd = this.textCols;
				this.scroll = this.dir ? -(this.compCanvas.height<<3) : -(this.compCanvas.width<<3);
			}
			else{
				this.rate = 0;
			}

			++this.iters;
			if (this.callback) this.callback(this.iters);
		}

		// draw text canvas into comp canvas

		if (this.background){
			this.compCanvas.getContext('2d').clearRect(0,0,this.compCanvas.width, this.compCanvas.height);
			this.compCanvas.getContext('2d').fillStyle = this.background;
			this.compCanvas.getContext('2d').fillRect(0,0,this.compCanvas.width, this.compCanvas.height);
		}
		if (this.dir){
			this._heap.left = (this.compCanvas.width - this.textCanvas.width)>>1;
			if (this.clearBg) this.compCanvas.getContext('2d').clearRect(this._heap.left,-(this.scroll>>3),this.textCanvas.width, this.textCanvas.height);
			this.compCanvas.getContext('2d').drawImage(this.textCanvas,this._heap.left,-(this.scroll>>3));
		}
		else{
			this._heap.top = (this.compCanvas.height - this.textCanvas.height)>>1;
			if (this.clearBg) this.compCanvas.getContext('2d').clearRect(-(this.scroll>>3),this._heap.top,this.textCanvas.width, this.textCanvas.height);
			this.compCanvas.getContext('2d').drawImage(this.textCanvas,-(this.scroll>>3),this._heap.top);
		}
		this._drawControls();

		return 0;
	};

	Marquee.prototype.drawIntoCanvas = function(canvas){
		this._heap.ctx = canvas.getContext('2d');
		this._heap.ctx.drawImage(this.compCanvas,this.x,this.y);
	};
