package speiger.src.coreengine.rendering.guiOld.renderer.lexer;

import java.util.List;
import java.util.Locale;

import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.utils.ObjectLists;
import speiger.src.coreengine.rendering.guiOld.renderer.FontRenderer;
import speiger.src.coreengine.rendering.guiOld.renderer.IFontRenderer.CharInstance;
import speiger.src.coreengine.utils.helpers.TextUtil;

public class TextLexer
{
	FontRenderer render;
	List<Word> helper = new ObjectArrayList<Word>();
	
	public TextLexer(FontRenderer render)
	{
		this.render = render;
	}
	
	public void getWords(String text, TextContext context, List<Word> words)
	{
		text = render.clearInvalidLetters(text);
		Word current = new Word(context.getScale());
		for(int i = 0,j=0,m=text.length();i<m;i++,j++)
		{
			char letter = text.charAt(i);
			if(letter == '§' && context.allowsSpecial() && i + 1 < m && text.charAt(i + 1) == '<')
			{
				String search = TextUtil.searchUntil(text, i + 2, '>', FontRenderer.INVALID_SEARCH);
				if(search.length() > 0)
				{
					context.apply(search.toLowerCase(Locale.ROOT).split(","), j--);
					i += search.length()+2;
					continue;
				}
			}
			WordType type = WordType.getByLetter(letter);
			if(current.getType() != type || type != null && type.isNewLine())
			{
				if(!current.isEmpty())
				{
					words.add(current);
					current = new Word(current);
				}
				current.setSpecail(type);
			}
			if(Character.isHighSurrogate(letter) && i + 1 < m) 
			{
				char extra = text.charAt(i + 1);
				if(Character.isLowSurrogate(extra)) 
				{
					i++;
					current.addLetter(render.getInstance(Character.toCodePoint(letter, extra), context.isBold()));
					continue;
				}
			}
			current.addLetter(render.getInstance(letter, context.isBold()));
		}
		if(!current.isEmpty())
		{
			words.add(current);
		}
	}
	
	public List<Line> evaluateLines(String text, TextContext context, float maxWidth)
	{
		if(text == null || text.isEmpty() || maxWidth < 10F * context.getScale())
		{
			return ObjectLists.empty();
		}
		List<Line> lines = new ObjectArrayList<>();
		getWords(text, context, helper);
		Line line = new Line(maxWidth);
		for(int i = 0;i<helper.size();i++)
		{
			Word word = helper.get(i);
			if(word.isNewLine())
			{
				line.addWord(word);
				line.finishLine();
				lines.add(line);
				line = new Line(maxWidth);
				continue;
			}
			if(!line.attemptAddingWord(word))
			{
				if(line.isEmpty() || (context.isSingle() && (word.size() != 1 || word.getWidth() < maxWidth - line.getWidth())))
				{
					Word removedWord = helper.remove(i--);
					splitWords(i+1, removedWord, maxWidth - line.getWidth() - 1F, context.getScale());
				}
				else
				{
					line.finishLine();
					lines.add(line);
					line = new Line(maxWidth);
					i--;
				}
			}
		}
		if(!line.isEmpty())
		{
			line.finishLine();
			lines.add(line);
		}
		helper.clear();
		return lines;
	}
	
	private void splitWords(int index, Word word, float maxLength, float scale)
	{
		Word newWord = word.getPrev() != null ? new Word(word.getPrev()) : new Word(scale);
		for(CharInstance letter : word.instanceIterator())
		{
			float width = letter.getXAdvance() * scale;
			if(width + newWord.getWidth() > maxLength)
			{
				helper.add(index++, newWord);
				newWord = new Word(newWord);
			}
			newWord.addLetter(letter);
		}
		if(newWord.size() > 0)
		{
			helper.add(index++, newWord);
			if(word.getNext() != null)
			{
				word.getNext().setPrev(newWord);
			}
		}
		else if(word.getNext() != null)
		{
			word.getNext().setPrev(newWord.getPrev());
		}
	}
}
