#include "textdisplay.h"


MultilineText::MultilineText()
{
	
}

MultilineText::~MultilineText()
{
	//~ delete []textlines;
	//~ delete []displaylines;
}


void MultilineText::setup(float width, float height, int maxlines)
{
	scrWidth = width;
	scrHeight = height;
	maxdisplaylines = maxlines;
	totaldisplaylines = 0;
	// set font size
	int fontsize;
	for(int i = 124; i > 8; i--)	{
		displayFont.loadFont("fonts/NotCourier-sans.ttf", i);
		fontsize = displayFont.getLineHeight();
		if((fontsize * maxdisplaylines) <= scrHeight)	{
			break;
		}
	}
	lineX = 0;
	lineY = 0;
	lineHeight = displayFont.getLineHeight();
	lineoffsetY = displayFont.stringHeight("O");
	linepaddingX = displayFont.stringWidth("_")/2;
	displaylines = new string[maxdisplaylines];
	currentline = 0;
	currentchar = 0;
	cursorWidth = displayFont.stringWidth("_");
	cursorHeight = displayFont.getLineHeight();
	blinkperiod = 12;
	blinkcount = 0;
	textprinting = false;
}

void MultilineText::setText(string newtext)
{
	// break into newlines
	string linechars = "\n\r";
	string whitechars = " \a\b\f\n\r\t\v";
	vector<string> newlines;
	textlines.clear();
	int totalnewlines = 0;
	currentline = 0;
	bool working = true;
	
	size_t pos = 0;
	size_t start = 0;
	size_t end = 0;
	size_t len = newtext.length();
	size_t maxchars;
	
	//printf("setText <%s>\n", newtext.c_str());
	
	//~ maxchars = scrWidth/displayFont.stringWidth(".");
	//~ printf("maxchars %d\n", maxchars);
	
	while((pos = newtext.find_first_of(linechars, start))!= string::npos) {
		end = pos;
		newlines.push_back(newtext.substr(start, end-start));
		totalnewlines++;
		start = end+1;
	}
	    
	if(end < len)	{
		end = pos;
		newlines.push_back(newtext.substr(start));
		totalnewlines++;
	}
	
  
	// for each newline, break into screen wraps
	for(int i = 0; i < totalnewlines; i++)	{
		// test length
		if(displayFont.stringWidth(newlines[i].c_str()) > scrWidth)	{
			// if too big, break into words
			string words[256];
			working = true;
			int totalwords = 0;
			start = 0;
			while((pos = newlines[i].find_first_of(whitechars, start))!= string::npos) {
				end = pos;
				if(end != start)	{
					words[totalwords] = newlines[i].substr(start, end-start);
					totalwords++;
				}
				start = end+1;
				if(totalwords > 256)	{
					break;
				}
			}
			    
			if(start < len)	{
				end = pos;
				words[totalwords] = newlines[i].substr(start, end-start);
				totalwords++;
			}
			// re-assemble until fits
			string tmpstring;
			string teststring;
			for(int w = 0; w < totalwords; w++)	{
				teststring = tmpstring + words[w];
				if(displayFont.stringWidth(teststring) < scrWidth) {
					tmpstring += words[w] + " ";
				} else {
					textlines.push_back(tmpstring.substr(0, tmpstring.find_last_not_of(whitechars)+1));
					currentline++;
					tmpstring = words[w] + " ";
				}
			}
			textlines.push_back(tmpstring.substr(0, tmpstring.find_last_not_of(whitechars)+1));
			currentline++;
		} else {
			textlines.push_back(newlines[i]);
			currentline++;
		}
	}
	
	// end
	displaystate = TEXT_TYPING;
	linesinstatement = currentline;
	currentline = 0;
	topline = 0;
	totaldisplaylines = 0;
	textprinting = true;
	expired = false;
}

void MultilineText::draw()
{
	if(displaystate != TEXT_CLEAR)	{
		// previous lines
		if(totaldisplaylines > 0)	{
			for(int i = 0; i < totaldisplaylines; i++)	{
				lineY = lineHeight*i;
				lineWidth = displayFont.stringWidth(displaylines[i].c_str());
				if(lineWidth > 0)	{
					lineWidth += linepaddingX;
				}
				ofSetColor(bgcolour.r,bgcolour.g,bgcolour.b);
				ofRect(lineX,lineY,lineWidth, lineHeight);
				ofSetColor(forecolour.r,forecolour.g,forecolour.b);
				displayFont.drawString(displaylines[i].c_str(), lineX,lineY+lineoffsetY);
			}
		}
		// current line
		string current = displaylines[totaldisplaylines].substr(0, currentchar+1);
		lineY = lineHeight*totaldisplaylines;
		lineWidth = displayFont.stringWidth(current.c_str());
		if(lineWidth > 0)	{
			lineWidth += linepaddingX;
		}
		ofSetColor(bgcolour.r,bgcolour.g,bgcolour.b);
		ofRect(lineX,lineY,lineWidth, lineHeight);
		ofSetColor(forecolour.r,forecolour.g,forecolour.b);
		displayFont.drawString(current.c_str(), lineX,lineY+lineoffsetY);
		
		if(textprinting)	{
			blinkcount++;
			blinkcount = blinkcount % blinkperiod;
			if(blinkcount < (blinkperiod/2))	{
				ofSetColor(forecolour.r,forecolour.g,forecolour.b);
			} else {
				ofSetColor(bgcolour.r,bgcolour.g,bgcolour.b);
			}
			ofRect(lineWidth,lineY,cursorWidth, cursorHeight);
		}
	}
}


void MultilineText::setBackgroundColour(Colour colour)
{
	bgcolour.r = colour.r;
	bgcolour.g = colour.g;
	bgcolour.b = colour.b;
}

void MultilineText::setForeColour(Colour colour)
{
	forecolour.r = colour.r;
	forecolour.g = colour.g;
	forecolour.b = colour.b;
}
	
void MultilineText::nextLine()
{
	if(currentline < linesinstatement)	{
		if(currentline < maxdisplaylines)	{
			displaylines[currentline] = textlines[currentline];
			currentlinelength = displaylines[currentline].length();
			totaldisplaylines = currentline;
			currentline++;
			currentchar = 0;
		} else	{
			topline = (currentline-maxdisplaylines)+1;
			int d = 0;
			for(int i = topline; i < currentline+1; i++)	{
				displaylines[d] = textlines[i];
				d++;
			}
			currentlinelength = displaylines[d-1].length();
			totaldisplaylines = currentline-topline;
			currentline++;
			currentchar = 0;
		}
	} else {
		textprinting = false;
		displaystate = TEXT_PAUSED;
		setTimeout(textwait);
		startTimeout();
	}
}

void MultilineText::nextChar()
{
	if(textprinting)	{
		currentchar++;
		if(currentchar >= currentlinelength)	{
			nextLine();
		}
	}
}


void MultilineText::setTimeout(int nduration)
{
	if(duration > -1)	{
		duration = nduration;
	} else {
		doingtime = false;
	}
	expired = false;
}


void MultilineText::setTextwait(int nduration)
{
	textwait = nduration;
}

void MultilineText::setPausewait(int nduration)
{
	pausewait = nduration;
}


void MultilineText::cancelTimeout()
{
	switch(displaystate)	{
		case TEXT_PAUSED:
			displaystate = TEXT_CLEAR;
			setTimeout(pausewait);
			startTimeout();
			totaldisplaylines = 0;
			currentline = 0;
			currentchar = 0;
			displaylines[0] = "";
			break;
		case TEXT_CLEAR:
			doingtime = false;
			expired = true;
			timeout = 0;
			break;
	}
}

void MultilineText::updateTimeout()
{
	if(doingtime)	{
		if(ofGetElapsedTimeMillis() >= timeout)
			cancelTimeout();
	}
}

void MultilineText::startTimeout()
{
	nowtime = ofGetElapsedTimeMillis();
	timeout = nowtime + duration;
	doingtime = true;
	expired = false;
}