package harfbuzz

import (
	

	
	ucd 
)

// Position stores a position, scaled according to the `Font`
// scale parameters.
type Position = int32

// GlyphPosition holds the positions of the
// glyph in both horizontal and vertical directions.
// All positions are relative to the current point.
type GlyphPosition struct {
	// How much the line advances after drawing this glyph when setting
	// text in horizontal direction.
	XAdvance Position
	// How much the glyph moves on the X-axis before drawing it, this
	// should not affect how much the line advances.
	XOffset Position

	// How much the line advances after drawing this glyph when setting
	// text in vertical direction.
	YAdvance Position
	// How much the glyph moves on the Y-axis before drawing it, this
	// should not affect how much the line advances.
	YOffset Position

	// glyph to which this attaches to, relative to current glyphs;
	// negative for going back, positive for forward.
	attachChain int16
	attachType  uint8 // attachment type, irrelevant if attachChain is 0
}

// unicodeProp is a two-byte number.  The low byte includes:
// - Modified General_Category: 5 bits.
// - A bit each for:
//   - Is it Default_Ignorable(); we have a modified Default_Ignorable().
//   - Whether it's one of the four Mongolian Free Variation Selectors,
//     CGJ, or other characters that are hidden but should not be ignored
//     like most other Default_Ignorable()s do during GSUB matching.
//   - Whether it's a grapheme continuation.
//
// The high-byte has different meanings, switched by the Gen-Cat:
//   - For Mn,Mc,Me: the modified Combining_Class.
//   - For Cf: whether it's ZWJ, ZWNJ, or something else.
//   - For Ws: index of which space character this is, if space fallback
//     is needed, ie. we don't set this by default, only if asked to.
//
// Above I said "modified" General_Category. This is because we need to
// remember Variation Selectors, and we don't have bits left. So we
// change their Gen_Cat from Mn to Cf, and use a bit of the high byte to
// remember them.
type unicodeProp uint16

const (
	upropsMaskIgnorable unicodeProp = 1 << (5 + iota)
	upropsMaskHidden                // MONGOLIAN FREE VARIATION SELECTOR 1..4, or TAG characters
	upropsMaskContinuation

	// if GEN_CAT=FORMAT, top byte masks
	upropsMaskCfZwj
	upropsMaskCfZwnj
	upropsMaskCfVs
	upropsMaskCfAatDeleted

	upropsMaskGenCat unicodeProp = 1<<5 - 1 // 11111
)

const isLigBase = 0x10

// generalCategory extracts the general category.
func ( unicodeProp) () generalCategory {
	return generalCategory( & upropsMaskGenCat)
}

type GlyphMask = uint32

const (
	// Indicates that if input text is broken at the beginning of the cluster this glyph is part of,
	// then both sides need to be re-shaped, as the result might be different.
	// On the flip side, it means that when this flag is not present,
	// then it's safe to break the glyph-run at the beginning of this cluster,
	// and the two sides represent the exact same result one would get
	// if breaking input text at the beginning of this cluster and shaping the two sides
	// separately.
	// This can be used to optimize paragraph layout, by avoiding re-shaping
	// of each line after line-breaking.
	GlyphUnsafeToBreak GlyphMask = 1 << iota

	// Indicates that if input text is changed on one side of the beginning of the cluster this glyph
	// is part of, then the shaping results for the other side might change.
	// Note that the absence of this flag will NOT by itself mean that it IS safe to concat text.
	// Only two pieces of text both of which clear of this flag can be concatenated safely.
	// This can be used to optimize paragraph layout, by avoiding re-shaping of each line
	// after line-breaking, by limiting the reshaping to a small piece around the
	// breaking position only, even if the breaking position carries the
	// [GlyphUnsafeToBreak] or when hyphenation or other text transformation
	// happens at line-break position, in the following way:
	// 	1. Iterate back from the line-break position until the first cluster start position that is
	// 		NOT unsafe-to-concat,
	// 	2. Shape the segment from there till the end of line,
	// 	3. Check whether the resulting glyph-run also is clear of the unsafe-to-concat at its start-of-text position;
	// 		if it is, just splice it into place and the line is shaped; If not, move on to a position further
	// 		back that is clear of unsafe-to-concat and retry from there, and repeat.
	// At the start of next line a similar algorithm can be implemented. That is:
	// 	1. Iterate forward from the line-break position until the first cluster start position that is NOT unsafe-to-concat,
	// 	2. Shape the segment from beginning of the line to that position,
	// 	3. Check whether the resulting glyph-run also is clear of the unsafe-to-concat at its end-of-text position;
	// 		if it is, just splice it into place and the beginning is shaped; If not, move on to a position further forward that is clear
	// 	 	of unsafe-to-concat and retry up to there, and repeat.
	// A slight complication will arise in the implementation of the algorithm above, because while our buffer API has a way to
	// return flags for position corresponding to start-of-text, there is currently no position
	// corresponding to end-of-text.  This limitation can be alleviated by shaping more text than needed
	// and looking for unsafe-to-concat flag within text clusters.
	// The [GlyphUnsafeToBreak] flag will always imply this flag.
	// To use this flag, you must enable the buffer flag [ProduceUnsafeToConcat] during
	// shaping, otherwise the buffer flag will not be reliably produced.
	GlyphUnsafeToConcat

	// In scripts that use elongation (Arabic, Mongolian, Syriac, etc.), this flag signifies
	// that it is safe to insert a U+0640 TATWEEL character before this cluster for elongation.
	// This flag does not determine the script-specific elongation places, but only
	// when it is safe to do the elongation without interrupting text shaping.
	GlyphSafeToInsertTatweel

	// OR of all defined flags
	glyphFlagDefined GlyphMask = GlyphUnsafeToBreak | GlyphUnsafeToConcat | GlyphSafeToInsertTatweel
)

// GlyphInfo holds information about the
// glyphs and their relation to input text.
// They are internally created from user input,
// and the shapping sets the `Glyph` field.
type GlyphInfo struct {
	// Cluster is the index of the character in the original text that corresponds
	// to this `GlyphInfo`, or whatever the client passes to `Buffer.Add()`.
	// More than one glyph can have the same `Cluster` value,
	// if they resulted from the same character (e.g. one to many glyph substitution),
	// and when more than one character gets merged in the same glyph (e.g. many to one glyph substitution)
	// the glyph will have the smallest Cluster value of them.
	// By default some characters are merged into the same Cluster
	// (e.g. combining marks have the same Cluster as their bases)
	// even if they are separate glyphs.
	// See Buffer.ClusterLevel for more fine-grained Cluster handling.
	Cluster int

	// input value of the shapping
	codepoint rune

	// Glyph is the result of the selection of concrete glyph
	// after shaping, and refers to the font used.
	Glyph GID

	// Mask exposes glyph attributes (see the constants).
	// It is also used internally during the shaping.
	Mask GlyphMask

	// in C code: var1

	// GDEF glyph properties
	glyphProps uint16

	// GSUB/GPOS ligature tracking
	// When a ligature is formed:
	//
	//   - The ligature glyph and any marks in between all the same newly allocated
	//     lig_id,
	//   - The ligature glyph will get lig_num_comps set to the number of components
	//   - The marks get lig_comp > 0, reflecting which component of the ligature
	//     they were applied to.
	//   - This is used in GPOS to attach marks to the right component of a ligature
	//     in MarkLigPos,
	//   - Note that when marks are ligated together, much of the above is skipped
	//     and the current lig_id reused.
	//
	// When a multiple-substitution is done:
	//
	//   - All resulting glyphs will have lig_id = 0,
	//   - The resulting glyphs will have lig_comp = 0, 1, 2, ... respectively.
	//   - This is used in GPOS to attach marks to the first component of a
	//     multiple substitution in MarkBasePos.
	//
	// The numbers are also used in GPOS to do mark-to-mark positioning only
	// to marks that belong to the same component of the same ligature.
	ligProps uint8
	// GSUB/GPOS shaping boundaries
	syllable uint8

	// in C code: var2

	unicode unicodeProp

	complexCategory, complexAux uint8 // storage interpreted by complex shapers
}

// String returns a simple description of the glyph of the form Glyph=Cluster(mask)
func ( GlyphInfo) () string {
	return fmt.Sprintf("%d=%d(0x%x)", .Glyph, .Cluster, .Mask&glyphFlagDefined)
}

func ( *GlyphInfo) ( *Buffer) {
	 := .codepoint
	var  bufferScratchFlags
	.unicode,  = computeUnicodeProps()
	.scratchFlags |= 
}

func ( *GlyphInfo) ( generalCategory) {
	/* Clears top-byte. */
	.unicode = unicodeProp() | (.unicode & (0xFF & ^upropsMaskGenCat))
}

func ( *GlyphInfo) ( int,  GlyphMask) {
	if .Cluster !=  {
		.Mask = (.Mask & ^glyphFlagDefined) | ( & glyphFlagDefined)
	}
	.Cluster = 
}

func ( *GlyphInfo) ( *Buffer) {
	.scratchFlags |= bsfHasContinuations
	.unicode |= upropsMaskContinuation
}

func ( *GlyphInfo) () bool {
	return .unicode&upropsMaskContinuation != 0
}

func ( *GlyphInfo) () { .unicode &= ^upropsMaskContinuation }

func ( *GlyphInfo) () bool {
	return .unicode.generalCategory() == ucd.Zs
}

func ( *GlyphInfo) () bool {
	return .unicode.generalCategory() == ucd.Cf
}

func ( *GlyphInfo) () bool {
	return .isUnicodeFormat() && (.unicode&upropsMaskCfZwnj) != 0
}

func ( *GlyphInfo) () bool {
	return .isUnicodeFormat() && (.unicode&upropsMaskCfZwj) != 0
}

func ( *GlyphInfo) () bool {
	return (.unicode & upropsMaskGenCat).generalCategory().IsMark()
}

func ( *GlyphInfo) ( uint8) {
	if !.isUnicodeSpace() {
		return
	}
	.unicode = unicodeProp()<<8 | .unicode&0xFF
}

func ( *GlyphInfo) () uint8 {
	if .isUnicodeMark() {
		return uint8(.unicode >> 8)
	}
	return 0
}

func ( *GlyphInfo) () {
	.unicode &= ^upropsMaskHidden
}

func ( *GlyphInfo) ( uint8) {
	if !.isUnicodeMark() {
		return
	}
	.unicode = (unicodeProp() << 8) | (.unicode & 0xFF)
}

func ( *GlyphInfo) () bool {
	return .glyphProps&ligated != 0
}

func ( *GlyphInfo) () uint8 {
	return .ligProps >> 5
}

func ( *GlyphInfo) () bool {
	return .ligProps&isLigBase != 0
}

func ( *GlyphInfo) () uint8 {
	if .ligatedInternal() {
		return 0
	}
	return .ligProps & 0x0F
}

func ( *GlyphInfo) () uint8 {
	if (.glyphProps&tables.GPLigature) != 0 && .ligatedInternal() {
		return .ligProps & 0x0F
	}
	return 1
}

func ( *GlyphInfo) (,  uint8) {
	.ligProps = ( << 5) | &0x0F
}

func ( *GlyphInfo) (,  uint8) {
	.ligProps = ( << 5) | isLigBase | &0x0F
}

func ( *GlyphInfo) () bool {
	return (.unicode&upropsMaskIgnorable) != 0 && !.substituted()
}

func ( *GlyphInfo) () {
	.unicode &= ^upropsMaskIgnorable
}

func ( *GlyphInfo) () bool {
	return .unicode&upropsMaskHidden != 0
}

func ( *GlyphInfo) () uint8 {
	if .isUnicodeSpace() {
		return uint8(.unicode >> 8)
	}
	return notSpace
}

func ( *GlyphInfo) () bool {
	return .glyphProps&tables.GPMark != 0
}

func ( *GlyphInfo) () bool {
	return .glyphProps&tables.GPBaseGlyph != 0
}

func ( *GlyphInfo) () bool {
	return .glyphProps&tables.GPLigature != 0
}

func ( *GlyphInfo) () bool {
	return .glyphProps&multiplied != 0
}

func ( *GlyphInfo) () {
	.glyphProps &= ^(ligated | multiplied)
}

func ( *GlyphInfo) () bool {
	return .ligated() && !.multiplied()
}

func ( *GlyphInfo) () bool {
	return .glyphProps&substituted != 0
}

func ( *GlyphInfo) () bool {
	return .isUnicodeFormat() && .unicode&upropsMaskCfAatDeleted != 0
}

func ( *GlyphInfo) () {
	.setGeneralCategory(ucd.Cf)
	.unicode |= upropsMaskCfAatDeleted
	.unicode |= upropsMaskHidden
}

func ( *GlyphInfo) () bool {
	return .unicode.generalCategory() == ucd.Cf && (.unicode&upropsMaskCfVs) != 0
}

func ( *GlyphInfo) ( bool) {
	if  {
		.setGeneralCategory(ucd.Cf)
		.unicode |= upropsMaskCfVs
	} else {
		// Reset to their original condition
		.setGeneralCategory(ucd.Mn)
	}
}