package speiger.src.coreengine.ui.gui.font;

import java.util.Map;

import speiger.src.collections.ints.maps.impl.hash.Int2ObjectOpenHashMap;
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap;
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap;
import speiger.src.coreengine.ui.gui.font.glyth.Glyth;
import speiger.src.coreengine.ui.gui.font.glyth.GlythData;
import speiger.src.coreengine.ui.gui.font.glyth.MissingGlyth;
import speiger.src.coreengine.ui.gui.font.glyth.UnbakedGlyth;


public class GlythCache {
	private Font font;
	final int style;
	Map<FontStyle, FontCache> cache = new Object2ObjectOpenHashMap<>();
	
	public GlythCache(Font font, int style) {
		this.font = font;
		this.style = style;
	}
	
	public void reset() {
		cache.values().forEach(FontCache::reset);
		cache.clear();
	}
	
	private FontCache cache(FontStyle font) {
		return cache.computeIfAbsent(font, FontCache::new);
	}
	
	public GlythData data(FontStyle fontId, int codepoint) {
		return cache(fontId).data(codepoint);
	}
	
	public Glyth glyth(FontStyle fontId, int codepoint) {
		return cache(fontId).glyth(codepoint);
	}
	
	public class FontCache {
		Int2ObjectMap<GlythData> data = new Int2ObjectOpenHashMap<>();
		Int2ObjectMap<Glyth> glyth = new Int2ObjectOpenHashMap<>();
		FontStyle fontStyle;
		MissingGlyth missingGlyth;
		GlythData missingData;
		
		
		public FontCache(FontStyle fontStyle) {
			this.fontStyle = fontStyle;
			this.missingGlyth = new MissingGlyth(fontStyle.size(), font.oversample * 2F);
			missingData = new GlythData(missingGlyth);
		}
		
		private void reset() {
			missingGlyth.cleanCache();
			missingData.cleanCache();
		}
		
		public GlythData data(int codepoint) {
			return data.computeIfAbsent(codepoint, this::compute);
		}
		
		public Glyth glyth(int codepoint) {
			return glyth.computeIfAbsent(codepoint, this::bake);
		}
		
		private GlythData compute(int codepoint) {
			UnbakedGlyth data = font.font(fontStyle.font()).data(codepoint, style, fontStyle.size(), font.oversample);
			return data == null ? missingData : new GlythData(data);
		}
		
		private Glyth bake(int codepoint) {
			return data(codepoint).unbaked().bake(font.baker);
		}
	}
}