package uniseg

import 

// The states of the sentence break parser.
const (
	sbAny = iota
	sbCR
	sbParaSep
	sbATerm
	sbUpper
	sbLower
	sbSB7
	sbSB8Close
	sbSB8Sp
	sbSTerm
	sbSB8aClose
	sbSB8aSp
)

// sbTransitions implements the sentence break parser's state transitions. It's
// anologous to [grTransitions], see comments there for details.
//
// Unicode version 15.0.0.
func sbTransitions(,  int) ( int,  bool,  int) {
	switch uint64() | uint64()<<32 {
	// SB3.
	case sbAny | prCR<<32:
		return sbCR, false, 9990
	case sbCR | prLF<<32:
		return sbParaSep, false, 30

	// SB4.
	case sbAny | prSep<<32:
		return sbParaSep, false, 9990
	case sbAny | prLF<<32:
		return sbParaSep, false, 9990
	case sbParaSep | prAny<<32:
		return sbAny, true, 40
	case sbCR | prAny<<32:
		return sbAny, true, 40

	// SB6.
	case sbAny | prATerm<<32:
		return sbATerm, false, 9990
	case sbATerm | prNumeric<<32:
		return sbAny, false, 60
	case sbSB7 | prNumeric<<32:
		return sbAny, false, 60 // Because ATerm also appears in SB7.

	// SB7.
	case sbAny | prUpper<<32:
		return sbUpper, false, 9990
	case sbAny | prLower<<32:
		return sbLower, false, 9990
	case sbUpper | prATerm<<32:
		return sbSB7, false, 70
	case sbLower | prATerm<<32:
		return sbSB7, false, 70
	case sbSB7 | prUpper<<32:
		return sbUpper, false, 70

	// SB8a.
	case sbAny | prSTerm<<32:
		return sbSTerm, false, 9990
	case sbATerm | prSContinue<<32:
		return sbAny, false, 81
	case sbATerm | prATerm<<32:
		return sbATerm, false, 81
	case sbATerm | prSTerm<<32:
		return sbSTerm, false, 81
	case sbSB7 | prSContinue<<32:
		return sbAny, false, 81
	case sbSB7 | prATerm<<32:
		return sbATerm, false, 81
	case sbSB7 | prSTerm<<32:
		return sbSTerm, false, 81
	case sbSB8Close | prSContinue<<32:
		return sbAny, false, 81
	case sbSB8Close | prATerm<<32:
		return sbATerm, false, 81
	case sbSB8Close | prSTerm<<32:
		return sbSTerm, false, 81
	case sbSB8Sp | prSContinue<<32:
		return sbAny, false, 81
	case sbSB8Sp | prATerm<<32:
		return sbATerm, false, 81
	case sbSB8Sp | prSTerm<<32:
		return sbSTerm, false, 81
	case sbSTerm | prSContinue<<32:
		return sbAny, false, 81
	case sbSTerm | prATerm<<32:
		return sbATerm, false, 81
	case sbSTerm | prSTerm<<32:
		return sbSTerm, false, 81
	case sbSB8aClose | prSContinue<<32:
		return sbAny, false, 81
	case sbSB8aClose | prATerm<<32:
		return sbATerm, false, 81
	case sbSB8aClose | prSTerm<<32:
		return sbSTerm, false, 81
	case sbSB8aSp | prSContinue<<32:
		return sbAny, false, 81
	case sbSB8aSp | prATerm<<32:
		return sbATerm, false, 81
	case sbSB8aSp | prSTerm<<32:
		return sbSTerm, false, 81

	// SB9.
	case sbATerm | prClose<<32:
		return sbSB8Close, false, 90
	case sbSB7 | prClose<<32:
		return sbSB8Close, false, 90
	case sbSB8Close | prClose<<32:
		return sbSB8Close, false, 90
	case sbATerm | prSp<<32:
		return sbSB8Sp, false, 90
	case sbSB7 | prSp<<32:
		return sbSB8Sp, false, 90
	case sbSB8Close | prSp<<32:
		return sbSB8Sp, false, 90
	case sbSTerm | prClose<<32:
		return sbSB8aClose, false, 90
	case sbSB8aClose | prClose<<32:
		return sbSB8aClose, false, 90
	case sbSTerm | prSp<<32:
		return sbSB8aSp, false, 90
	case sbSB8aClose | prSp<<32:
		return sbSB8aSp, false, 90
	case sbATerm | prSep<<32:
		return sbParaSep, false, 90
	case sbATerm | prCR<<32:
		return sbParaSep, false, 90
	case sbATerm | prLF<<32:
		return sbParaSep, false, 90
	case sbSB7 | prSep<<32:
		return sbParaSep, false, 90
	case sbSB7 | prCR<<32:
		return sbParaSep, false, 90
	case sbSB7 | prLF<<32:
		return sbParaSep, false, 90
	case sbSB8Close | prSep<<32:
		return sbParaSep, false, 90
	case sbSB8Close | prCR<<32:
		return sbParaSep, false, 90
	case sbSB8Close | prLF<<32:
		return sbParaSep, false, 90
	case sbSTerm | prSep<<32:
		return sbParaSep, false, 90
	case sbSTerm | prCR<<32:
		return sbParaSep, false, 90
	case sbSTerm | prLF<<32:
		return sbParaSep, false, 90
	case sbSB8aClose | prSep<<32:
		return sbParaSep, false, 90
	case sbSB8aClose | prCR<<32:
		return sbParaSep, false, 90
	case sbSB8aClose | prLF<<32:
		return sbParaSep, false, 90

	// SB10.
	case sbSB8Sp | prSp<<32:
		return sbSB8Sp, false, 100
	case sbSB8aSp | prSp<<32:
		return sbSB8aSp, false, 100
	case sbSB8Sp | prSep<<32:
		return sbParaSep, false, 100
	case sbSB8Sp | prCR<<32:
		return sbParaSep, false, 100
	case sbSB8Sp | prLF<<32:
		return sbParaSep, false, 100

	// SB11.
	case sbATerm | prAny<<32:
		return sbAny, true, 110
	case sbSB7 | prAny<<32:
		return sbAny, true, 110
	case sbSB8Close | prAny<<32:
		return sbAny, true, 110
	case sbSB8Sp | prAny<<32:
		return sbAny, true, 110
	case sbSTerm | prAny<<32:
		return sbAny, true, 110
	case sbSB8aClose | prAny<<32:
		return sbAny, true, 110
	case sbSB8aSp | prAny<<32:
		return sbAny, true, 110
	// We'll always break after ParaSep due to SB4.

	default:
		return -1, false, -1
	}
}

// transitionSentenceBreakState determines the new state of the sentence break
// parser given the current state and the next code point. It also returns
// whether a sentence boundary was detected. If more than one code point is
// needed to determine the new state, the byte slice or the string starting
// after rune "r" can be used (whichever is not nil or empty) for further
// lookups.
func transitionSentenceBreakState( int,  rune,  []byte,  string) ( int,  bool) {
	// Determine the property of the next character.
	 := property(sentenceBreakCodePoints, )

	// SB5 (Replacing Ignore Rules).
	if  == prExtend ||  == prFormat {
		if  == sbParaSep ||  == sbCR {
			return sbAny, true // Make sure we don't apply SB5 to SB3 or SB4.
		}
		if  < 0 {
			return sbAny, true // SB1.
		}
		return , false
	}

	// Find the applicable transition in the table.
	var  int
	, ,  = sbTransitions(, )
	if  < 0 {
		// No specific transition found. Try the less specific ones.
		, ,  := sbTransitions(, prAny)
		, ,  := sbTransitions(sbAny, )
		if  >= 0 &&  >= 0 {
			// Both apply. We'll use a mix (see comments for grTransitions).
			, ,  = , , 
			if  <  {
				,  = , 
			}
		} else if  >= 0 {
			// We only have a specific state.
			, ,  = , , 
			// This branch will probably never be reached because okAnyState will
			// always be true given the current transition map. But we keep it here
			// for future modifications to the transition map where this may not be
			// true anymore.
		} else if  >= 0 {
			// We only have a specific property.
			, ,  = , , 
		} else {
			// No known transition. SB999: Any × Any.
			, ,  = sbAny, false, 9990
		}
	}

	// SB8.
	if  > 80 && ( == sbATerm ||  == sbSB8Close ||  == sbSB8Sp ||  == sbSB7) {
		// Check the right side of the rule.
		var  int
		for  != prOLetter &&
			 != prUpper &&
			 != prLower &&
			 != prSep &&
			 != prCR &&
			 != prLF &&
			 != prATerm &&
			 != prSTerm {
			// Move on to the next rune.
			if  != nil { // Byte slice version.
				,  = utf8.DecodeRune()
				 = [:]
			} else { // String version.
				,  = utf8.DecodeRuneInString()
				 = [:]
			}
			if  == utf8.RuneError {
				break
			}
			 = property(sentenceBreakCodePoints, )
		}
		if  == prLower {
			return sbLower, false
		}
	}

	return
}