package textmeasure

import (
	
	

	
	

	
)

// glyph describes one glyph in an atlas.
type glyph struct {
	dot     *geo.Point
	frame   *rect
	advance float64
}

// atlas is a set of pre-drawn glyphs of a fixed set of runes. This allows for efficient text drawing.
type atlas struct {
	face       font.Face
	mapping    map[rune]glyph
	ascent     float64
	descent    float64
	lineHeight float64
}

// NewAtlas creates a new atlas containing glyphs of the union of the given sets of runes (plus
// unicode.ReplacementChar) from the given font face.
//
// Creating an atlas is rather expensive, do not create a new atlas each frame.
//
// Do not destroy or close the font.Face after creating the atlas. atlas still uses it.
func ( font.Face,  ...[]rune) *atlas {
	 := make(map[rune]bool)
	 := []rune{unicode.ReplacementChar}
	for ,  := range  {
		for ,  := range  {
			if ![] {
				 = append(, )
				[] = true
			}
		}
	}

	,  := makeSquareMapping(, , fixed.I(2))

	 := &rect{
		tl: geo.NewPoint(
			i2f(.Min.X),
			i2f(.Min.Y),
		),
		br: geo.NewPoint(
			i2f(.Max.X),
			i2f(.Max.Y),
		),
	}

	 := make(map[rune]glyph)
	for ,  := range  {
		[] = glyph{
			dot: geo.NewPoint(
				i2f(.dot.X),
				.br.Y-(i2f(.dot.Y)-.tl.Y),
			),
			frame: rect{
				tl: geo.NewPoint(
					i2f(.frame.Min.X),
					.br.Y-(i2f(.frame.Min.Y)-.tl.Y),
				),
				br: geo.NewPoint(
					i2f(.frame.Max.X),
					.br.Y-(i2f(.frame.Max.Y)-.tl.Y),
				),
			}.norm(),
			advance: i2f(.advance),
		}
	}

	return &atlas{
		face:       ,
		mapping:    ,
		ascent:     i2f(.Metrics().Ascent),
		descent:    i2f(.Metrics().Descent),
		lineHeight: i2f(.Metrics().Height),
	}
}

func ( *atlas) ( rune) bool {
	,  := .mapping[]
	return 
}

// glyph returns the description of r within the atlas.
func ( *atlas) ( rune) glyph {
	return .mapping[]
}

// Kern returns the kerning distance between runes r0 and r1. Positive distance means that the
// glyphs should be further apart.
func ( *atlas) (,  rune) float64 {
	return i2f(.face.Kern(, ))
}

// Ascent returns the distance from the top of the line to the baseline.
func ( *atlas) () float64 {
	return .ascent
}

// Descent returns the distance from the baseline to the bottom of the line.
func ( *atlas) () float64 {
	return .descent
}

// DrawRune returns parameters necessary for drawing a rune glyph.
//
// Rect is a rectangle where the glyph should be positioned. frame is the glyph frame inside the
// atlas's Picture. NewDot is the new position of the dot.
func ( *atlas) (,  rune,  *geo.Point) (, ,  *rect,  *geo.Point) {
	if !.contains() {
		 = unicode.ReplacementChar
	}
	if !.contains(unicode.ReplacementChar) {
		return newRect(), newRect(), newRect(), 
	}
	if !.contains() {
		 = unicode.ReplacementChar
	}

	if  >= 0 {
		.X += .Kern(, )
	}

	 := .glyph()

	 := geo.NewPoint(
		.X-.dot.X,
		.Y-.dot.Y,
	)

	 = &rect{
		tl: geo.NewPoint(
			.frame.tl.X+.X,
			.frame.tl.Y+.Y,
		),
		br: geo.NewPoint(
			.frame.br.X+.X,
			.frame.br.Y+.Y,
		),
	}
	 = 

	if .w()*.h() != 0 {
		 = &rect{
			tl: geo.NewPoint(
				.tl.X,
				.Y-.Descent(),
			),
			br: geo.NewPoint(
				.br.X,
				.Y+.Ascent(),
			),
		}
	}

	.X += .advance

	return , .frame, , 
}

type fixedGlyph struct {
	dot     fixed.Point26_6
	frame   fixed.Rectangle26_6
	advance fixed.Int26_6
}

// makeSquareMapping finds an optimal glyph arrangement of the given runes, so that their common
// bounding box is as square as possible.
func makeSquareMapping( font.Face,  []rune,  fixed.Int26_6) (map[rune]fixedGlyph, fixed.Rectangle26_6) {
	 := sort.Search(int(fixed.I(1024*1024)), func( int) bool {
		 := fixed.Int26_6()
		,  := makeMapping(, , , )
		return .Max.X-.Min.X >= .Max.Y-.Min.Y
	})
	return makeMapping(, , , fixed.Int26_6())
}

// makeMapping arranges glyphs of the given runes into rows in such a way, that no glyph is located
// fully to the right of the specified width. Specifically, it places glyphs in a row one by one and
// once it reaches the specified width, it starts a new row.
func makeMapping( font.Face,  []rune, ,  fixed.Int26_6) (map[rune]fixedGlyph, fixed.Rectangle26_6) {
	 := make(map[rune]fixedGlyph)
	 := fixed.Rectangle26_6{}

	 := fixed.P(0, 0)

	for ,  := range  {
		, ,  := .GlyphBounds()
		if ! {
			continue
		}

		// this is important for drawing, artifacts arise otherwise
		 := fixed.Rectangle26_6{
			Min: fixed.P(.Min.X.Floor(), .Min.Y.Floor()),
			Max: fixed.P(.Max.X.Ceil(), .Max.Y.Ceil()),
		}

		.X -= .Min.X
		 = .Add()

		[] = fixedGlyph{
			dot:     ,
			frame:   ,
			advance: ,
		}
		 = .Union()

		.X = .Max.X

		// padding + align to integer
		.X += 
		.X = fixed.I(.X.Ceil())

		// width exceeded, new row
		if .Max.X >=  {
			.X = 0
			.Y += .Metrics().Ascent + .Metrics().Descent

			// padding + align to integer
			.Y += 
			.Y = fixed.I(.Y.Ceil())
		}
	}

	return , 
}

func i2f( fixed.Int26_6) float64 {
	return float64() / (1 << 6)
}