package runewidth

import (
	
	

	
)

//go:generate go run script/generate.go

var (
	// EastAsianWidth will be set true if the current locale is CJK
	EastAsianWidth bool

	// StrictEmojiNeutral should be set false if handle broken fonts
	StrictEmojiNeutral bool = true

	// DefaultCondition is a condition in current locale
	DefaultCondition = &Condition{
		EastAsianWidth:     false,
		StrictEmojiNeutral: true,
	}
)

func init() {
	handleEnv()
}

func handleEnv() {
	 := os.Getenv("RUNEWIDTH_EASTASIAN")
	if  == "" {
		EastAsianWidth = IsEastAsian()
	} else {
		EastAsianWidth =  == "1"
	}
	// update DefaultCondition
	if DefaultCondition.EastAsianWidth != EastAsianWidth {
		DefaultCondition.EastAsianWidth = EastAsianWidth
		if len(DefaultCondition.combinedLut) > 0 {
			DefaultCondition.combinedLut = DefaultCondition.combinedLut[:0]
			CreateLUT()
		}
	}
}

type interval struct {
	first rune
	last  rune
}

type table []interval

func inTables( rune,  ...table) bool {
	for ,  := range  {
		if inTable(, ) {
			return true
		}
	}
	return false
}

func inTable( rune,  table) bool {
	if  < [0].first {
		return false
	}

	 := 0
	 := len() - 1
	for  >=  {
		 := ( + ) >> 1

		switch {
		case [].last < :
			 =  + 1
		case [].first > :
			 =  - 1
		default:
			return true
		}
	}

	return false
}

var private = table{
	{0x00E000, 0x00F8FF}, {0x0F0000, 0x0FFFFD}, {0x100000, 0x10FFFD},
}

var nonprint = table{
	{0x0000, 0x001F}, {0x007F, 0x009F}, {0x00AD, 0x00AD},
	{0x070F, 0x070F}, {0x180B, 0x180E}, {0x200B, 0x200F},
	{0x2028, 0x202E}, {0x206A, 0x206F}, {0xD800, 0xDFFF},
	{0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB}, {0xFFFE, 0xFFFF},
}

// Condition have flag EastAsianWidth whether the current locale is CJK or not.
type Condition struct {
	combinedLut        []byte
	EastAsianWidth     bool
	StrictEmojiNeutral bool
}

// NewCondition return new instance of Condition which is current locale.
func () *Condition {
	return &Condition{
		EastAsianWidth:     EastAsianWidth,
		StrictEmojiNeutral: StrictEmojiNeutral,
	}
}

// RuneWidth returns the number of cells in r.
// See http://www.unicode.org/reports/tr11/
func ( *Condition) ( rune) int {
	if  < 0 ||  > 0x10FFFF {
		return 0
	}
	if len(.combinedLut) > 0 {
		return int(.combinedLut[>>1]>>(uint(&1)*4)) & 3
	}
	// optimized version, verified by TestRuneWidthChecksums()
	if !.EastAsianWidth {
		switch {
		case  < 0x20:
			return 0
		case ( >= 0x7F &&  <= 0x9F) ||  == 0xAD: // nonprint
			return 0
		case  < 0x300:
			return 1
		case inTable(, narrow):
			return 1
		case inTables(, nonprint, combining):
			return 0
		case inTable(, doublewidth):
			return 2
		default:
			return 1
		}
	} else {
		switch {
		case inTables(, nonprint, combining):
			return 0
		case inTable(, narrow):
			return 1
		case inTables(, ambiguous, doublewidth):
			return 2
		case !.StrictEmojiNeutral && inTables(, ambiguous, emoji, narrow):
			return 2
		default:
			return 1
		}
	}
}

// CreateLUT will create an in-memory lookup table of 557056 bytes for faster operation.
// This should not be called concurrently with other operations on c.
// If options in c is changed, CreateLUT should be called again.
func ( *Condition) () {
	const  = 0x110000
	 := .combinedLut
	if len(.combinedLut) != 0 {
		// Remove so we don't use it.
		.combinedLut = nil
	} else {
		 = make([]byte, /2)
	}
	for  := range  {
		 := int32( * 2)
		 := .RuneWidth()
		 := .RuneWidth( + 1)
		[] = uint8() | uint8()<<4
	}
	.combinedLut = 
}

// StringWidth return width as you can see
func ( *Condition) ( string) ( int) {
	 := uniseg.NewGraphemes()
	for .Next() {
		var  int
		for ,  := range .Runes() {
			 = .RuneWidth()
			if  > 0 {
				break // Our best guess at this point is to use the width of the first non-zero-width rune.
			}
		}
		 += 
	}
	return
}

// Truncate return string truncated with w cells
func ( *Condition) ( string,  int,  string) string {
	if .StringWidth() <=  {
		return 
	}
	 -= .StringWidth()
	var  int
	 := len()
	 := uniseg.NewGraphemes()
	for .Next() {
		var  int
		for ,  := range .Runes() {
			 = .RuneWidth()
			if  > 0 {
				break // See StringWidth() for details.
			}
		}
		if + >  {
			, _ = .Positions()
			break
		}
		 += 
	}
	return [:] + 
}

// TruncateLeft cuts w cells from the beginning of the `s`.
func ( *Condition) ( string,  int,  string) string {
	if .StringWidth() <=  {
		return 
	}

	var  int
	 := len()

	 := uniseg.NewGraphemes()
	for .Next() {
		var  int
		for ,  := range .Runes() {
			 = .RuneWidth()
			if  > 0 {
				break // See StringWidth() for details.
			}
		}

		if + >  {
			if  <  {
				_,  = .Positions()
				 += strings.Repeat(" ", +-)
			} else {
				, _ = .Positions()
			}

			break
		}

		 += 
	}

	return  + [:]
}

// Wrap return string wrapped with w cells
func ( *Condition) ( string,  int) string {
	 := 0
	 := ""
	for ,  := range  {
		 := .RuneWidth()
		if  == '\n' {
			 += string()
			 = 0
			continue
		} else if + >  {
			 += "\n"
			 = 0
			 += string()
			 += 
			continue
		}
		 += string()
		 += 
	}
	return 
}

// FillLeft return string filled in left by spaces in w cells
func ( *Condition) ( string,  int) string {
	 := .StringWidth()
	 :=  - 
	if  > 0 {
		 := make([]byte, )
		for  := range  {
			[] = ' '
		}
		return string() + 
	}
	return 
}

// FillRight return string filled in left by spaces in w cells
func ( *Condition) ( string,  int) string {
	 := .StringWidth()
	 :=  - 
	if  > 0 {
		 := make([]byte, )
		for  := range  {
			[] = ' '
		}
		return  + string()
	}
	return 
}

// RuneWidth returns the number of cells in r.
// See http://www.unicode.org/reports/tr11/
func ( rune) int {
	return DefaultCondition.RuneWidth()
}

// IsAmbiguousWidth returns whether is ambiguous width or not.
func ( rune) bool {
	return inTables(, private, ambiguous)
}

// IsNeutralWidth returns whether is neutral width or not.
func ( rune) bool {
	return inTable(, neutral)
}

// StringWidth return width as you can see
func ( string) ( int) {
	return DefaultCondition.StringWidth()
}

// Truncate return string truncated with w cells
func ( string,  int,  string) string {
	return DefaultCondition.Truncate(, , )
}

// TruncateLeft cuts w cells from the beginning of the `s`.
func ( string,  int,  string) string {
	return DefaultCondition.TruncateLeft(, , )
}

// Wrap return string wrapped with w cells
func ( string,  int) string {
	return DefaultCondition.Wrap(, )
}

// FillLeft return string filled in left by spaces in w cells
func ( string,  int) string {
	return DefaultCondition.FillLeft(, )
}

// FillRight return string filled in left by spaces in w cells
func ( string,  int) string {
	return DefaultCondition.FillRight(, )
}

// CreateLUT will create an in-memory lookup table of 557055 bytes for faster operation.
// This should not be called concurrently with other operations.
func () {
	if len(DefaultCondition.combinedLut) > 0 {
		return
	}
	DefaultCondition.CreateLUT()
}