package electrosphere.renderer.ui.font;

import electrosphere.renderer.model.Material;
import electrosphere.renderer.texture.Texture;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.awt.RenderingHints;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.util.LinkedList;
import java.util.List;

import javax.imageio.ImageIO;



/**
 * Utilities for loading fonts
 */
public class FontUtils {


    /**
     * Renders a single character to a buffered image
     * @param font The java font object
     * @param c the character
     * @param antiAlias whether to antialias the font or not
     * @return The buffered image with the rendered font
     */
    private static BufferedImage createCharImage(java.awt.Font font, char c, boolean antiAlias) {
        
        //get the size of the character
        BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = image.createGraphics();
        if(antiAlias){
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        }
        g.setFont(font);
        FontMetrics metrics = g.getFontMetrics();
        g.dispose();
        int charWidth = metrics.charWidth(c);
        int charHeight = metrics.getHeight();

        //return 0 width characters
        if (charWidth == 0) {
            return null;
        }

        //render character to a properly sized buffered image
        image = new BufferedImage(charWidth, charHeight, BufferedImage.TYPE_INT_ARGB);
        g = image.createGraphics();
        if (antiAlias) {
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        }
        g.setFont(font);
        g.setPaint(java.awt.Color.WHITE);
        g.drawString(String.valueOf(c), 0, metrics.getAscent());
        g.dispose();
        return image;
    }

    /**
     * Loads a java font object into an engine font object
     * @param font The java font object
     * @param antiAlias if true, antialias, otherwise dont
     * @return The engine font object
     */
    protected static Font loadFont(java.awt.Font font, boolean antiAlias) {
        int imageWidth = 0;
        int imageHeight = 0;


        //data for parsing characters out of the font image
        List<Font.Glyph> glyphs = new LinkedList<Font.Glyph>();

        //iterate through ascii codes
        for(int i = 32; i < 256; i++){
            if(i == 127){
                //skip del character
                continue;
            }
            char c = (char)i;
            BufferedImage ch = createCharImage(font, c, antiAlias);
            if(ch == null){
                //skip characters with no images
                continue;
            }

            imageWidth += ch.getWidth();
            imageHeight = Math.max(imageHeight, ch.getHeight());
        }

        // int fontHeight = imageHeight;

        //create font bitmap
        BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = image.createGraphics();

        int x = 0;

        //loop through ascii codes
        for (int i = 32; i < 256; i++) {
            if (i == 127) {
                //skip del character command
                continue;
            }
            char c = (char) i;
            BufferedImage charImage = createCharImage(font, c, antiAlias);
            if (charImage == null) {
                //don't render if the character is blank
                continue;
            }

            int charWidth = charImage.getWidth();
            int charHeight = charImage.getHeight();

            //draw the glyph to the image
            g.drawImage(charImage, x, 0, null);

            //create glyph and push it into the array
            Font.Glyph glyph = new Font.Glyph();
            glyph.height = charHeight;
            glyph.width = charWidth;
            glyph.startX = x;
            glyph.startY = 0;
            glyph.symbol = (char)i + "";
            glyphs.add(glyph);

            //increment image
            x += charWidth;
        }

        //uncomment if you need to flip the font
        // AffineTransform transform = AffineTransform.getScaleInstance(1f, -1f);
        // transform.translate(0, -image.getHeight());
        // AffineTransformOp operation = new AffineTransformOp(transform, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
        // image = operation.filter(image, null);

        try {
            File imgFile = new File("./.testcache/testimg.png");
            imgFile.delete();
            imgFile.getParentFile().mkdirs();
            ImageIO.write(image, "png", Files.newOutputStream(imgFile.toPath()));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


        //create material with new font image
        Material uiMat = new Material();
        Texture texture = new Texture(image);
        uiMat.setTexturePointer(texture.getTexturePointer());


        //construct final font object and return
        Font rVal = new Font(uiMat,glyphs,imageWidth,imageHeight);
        rVal.process();
        return rVal;
    }
    
    
}
