package peripheral

import chisel3._
import chisel3.experimental.{ChiselAnnotation, annotate}
import chisel3.util.experimental.loadMemoryFromFileInline
import chisel3.{Bundle, Input, Module, Output, SyncReadMem, UInt}
import firrtl.annotations.MemorySynthInit

import java.io.FileWriter
import java.nio.file.Paths
import javax.imageio.ImageIO

class FontROM(fontBitmapFilename: String = "vga_font_8x16.bmp") extends Module {
  val glyphWidth = GlyphInfo.glyphWidth
  val glyphHeight = GlyphInfo.glyphHeight

  val io = IO(new Bundle {
    val glyph_index = Input(UInt(7.W))
    val glyph_y = Input(UInt(4.W))

    val glyph_pixel_byte = Output(UInt(8.W))
  })

  annotate(new ChiselAnnotation {
    override def toFirrtl =
      MemorySynthInit
  })

  val (hexTxtPath, glyphCount) = readFontBitmap()
  val mem = SyncReadMem(glyphCount, UInt(8.W))
  loadMemoryFromFileInline(mem, hexTxtPath.toString.replaceAll("\\\\", "/"))
  io.glyph_pixel_byte := mem.read(io.glyph_index * GlyphInfo.glyphHeight.U + io.glyph_y, true.B)

  def readFontBitmap() = {
    val inputStream = getClass.getClassLoader.getResourceAsStream(fontBitmapFilename)
    val image = ImageIO.read(inputStream)

    val glyphColumns = image.getWidth() / glyphWidth
    val glyphRows = image.getHeight / glyphHeight
    val glyphCount = glyphColumns * glyphRows
    val glyphs = new Array[UInt](glyphCount * GlyphInfo.glyphHeight)

    for (row <- 0 until glyphRows) {
      for (col <- 0 until glyphColumns) {
        for (i <- 0 until glyphHeight) {
          var lineInt = 0
          for (j <- 0 until glyphWidth) {
            if (image.getRGB(col * glyphWidth + j, row * glyphHeight + i) != 0xFFFFFFFF) {
              lineInt |= (1 << j)
            }
          }
          glyphs((row * glyphColumns + col) * GlyphInfo.glyphHeight + i) = lineInt.U(8.W)
        }
      }
    }
    val currentDir = System.getProperty("user.dir")
    val hexTxtPath = Paths.get(currentDir, "verilog", f"${fontBitmapFilename}.txt")
    val writer = new FileWriter(hexTxtPath.toString)
    for (i <- glyphs.indices) {
      writer.write(f"@$i%x\n${glyphs(i).litValue}%02x\n")
    }
    writer.close()
    (hexTxtPath, glyphs.length)
  }
}
