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

import java.text.DecimalFormat;
import java.util.StringJoiner;

import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.lists.ObjectList;
import speiger.src.coreengine.math.color.ColorUtils;
import speiger.src.coreengine.rendering.guiOld.components.TextComponent;
import speiger.src.coreengine.utils.helpers.TextUtil;

public class TextContext
{
	static final int BOLD = 1;
	static final int FLIPPED = 2;
	static final int STRIKE_THROUGH = 4;
	static final int UNDERLINE = 8;
	static final int SPECIAL = 16;
	static final int SINGLE = 32;
	
	final int originalFlags;
	final int originalColor;
	final float originalItalic;
	final float scale;
	
	int flags = 0;
	float italic = 0F;
	int color = ColorUtils.WHITE;
	ObjectList<WordContext> changes = new ObjectArrayList<WordContext>();
	
	public TextContext(float scale)
	{
		this(scale, 0);
	}
	
	public TextContext(float scale, int flags)
	{
		this.scale = scale;
		originalFlags = this.flags = flags;
		originalColor = ColorUtils.WHITE;
		originalItalic = 0F;
		changes.add(new WordContext(0, flags, italic, color));
	}
	
	public TextContext(TextComponent component)
	{
		scale = component.getTextScale();
		originalFlags = createFlags(component);
		originalColor = component.getTextColor();
		originalItalic = component.getItalic();
		flags = originalFlags;
		color = originalColor;
		italic = originalItalic;
		changes.add(new WordContext(0, flags, italic, color));
	}
	
	public void reset()
	{
		flags = originalFlags;
		color = originalColor;
		italic = originalItalic;
	}
	
	public boolean allowsSpecial()
	{
		return (originalFlags & SPECIAL) != 0;
	}
	
	public boolean isBold()
	{
		return (flags & BOLD) != 0;
	}
	
	public boolean isSingle()
	{
		return (originalFlags & SINGLE) != 0;
	}
	
	public float getScale()
	{
		return scale;
	}
	
	public void apply(String[] flagString, int index)
	{
		for(int i = 0,m=flagString.length;i<m;i++)
		{
			String entry = flagString[i];
			if(TextUtil.findFlag(entry, "reset", false))
			{
				reset();
			}
			setFlag(BOLD, TextUtil.findFlag(entry, "bold", (flags & BOLD) != 0));
			setFlag(FLIPPED, TextUtil.findFlag(entry, "flip", (flags & FLIPPED) != 0));
			setFlag(UNDERLINE, TextUtil.findFlag(entry, "underline", (flags & UNDERLINE) != 0));
			setFlag(STRIKE_THROUGH, TextUtil.findFlag(entry, "strike", (flags & STRIKE_THROUGH) != 0));
			color = TextUtil.findColor(entry, "color", color, originalColor);
            italic = TextUtil.findFloat(entry, "italic", italic, italic > 0.0F ? 0.0F : 3.0F);
		}
		WordContext context = new WordContext(index, flags, italic, color);
		changes.get(changes.size() - 1).setNext(context);
		changes.add(context);
	}
	
	void setFlag(int flag, boolean value)
	{
		flags = (value ? flags | flag : flags & ~(flag));
	}
	
	static int createFlags(TextComponent component)
	{
		int flags = 0;
		flags |= component.isBold() ? BOLD : 0;
		flags |= component.isFlipped() ? FLIPPED : 0;
		flags |= component.isStrikeThrough() ? STRIKE_THROUGH : 0;
		flags |= component.isUnderlined() ? UNDERLINE : 0;
		flags |= component.isRenderingSpecial() ? SPECIAL : 0;
		flags |= component.isForcedSingleLine() ? SINGLE : 0;
		return flags;
	}
	
	public static class WordContext
	{
		static final DecimalFormat ITALIC_FORMAT = new DecimalFormat("0.##");
		WordContext prev;
		WordContext next;
		public final int charIndex;
		public final boolean bold;
		public final boolean flipped;
		public final boolean strike_through;
		public final boolean underline;
		public final float italic;
		public final int color;
		
		public WordContext(int index, int flags, float italic, int color)
		{
			charIndex = index;
			bold = (flags & BOLD) != 0;
			flipped = (flags & FLIPPED) != 0;
			strike_through = (flags & STRIKE_THROUGH) != 0;
			underline = (flags & UNDERLINE) != 0;
			this.italic = italic;
			this.color = color;
		}
		
		void setNext(WordContext next)
		{
			this.next = next;
			this.next.prev = this;
		}
		
		public boolean isNext(int index)
		{
			return next != null && next.charIndex <= index;
		}
		
		public WordContext next()
		{
			return next;
		}
		
		public String getString(boolean restart)
		{
			if(prev == null || restart)
			{
				if(anyEnabled())
				{
					StringJoiner joiner = new StringJoiner(",", "§<", ">");
					if(bold) joiner.add("bold=true");
					if(flipped) joiner.add("flipped=true");
					if(underline) joiner.add("underline=true");
					if(strike_through) joiner.add("strike=true");
					if(color != -1) joiner.add("color="+ColorUtils.toHex(color, true));
					if(italic > 0F) joiner.add("italic="+ITALIC_FORMAT.format(italic));
					return joiner.toString();
				}
				return "";
			}
			if(bold != prev.bold || flipped != prev.flipped || underline != prev.underline || strike_through != prev.strike_through || color != prev.color || Float.compare(italic, prev.italic) != 0)
			{
				StringJoiner joiner = new StringJoiner(",", "§<", ">");
				if(bold != prev.bold) joiner.add("bold="+bold);
				if(flipped != prev.flipped) joiner.add("flipped="+flipped);
				if(underline != prev.underline) joiner.add("underline="+underline);
				if(strike_through != prev.strike_through) joiner.add("strike="+strike_through);
				if(color != prev.color) joiner.add("color="+ColorUtils.toHex(color, true));
				if(Float.compare(italic, prev.italic) != 0) joiner.add("italic="+ITALIC_FORMAT.format(italic));
				return joiner.toString();
			}
			return "";
		}
		
		protected boolean anyEnabled()
		{
			return bold || flipped || underline || strike_through || color != -1 || italic > 0F;
		}
	}
	
	public WordContext getEffect()
	{
		return changes.get(0);
	}

}
