// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package colltab

import (
	

	
)

// Table holds all collation data for a given collation ordering.
type Table struct {
	Index Trie // main trie

	// expansion info
	ExpandElem []uint32

	// contraction info
	ContractTries  ContractTrieSet
	ContractElem   []uint32
	MaxContractLen int
	VariableTop    uint32
}

func ( *Table) ( []Elem,  []byte) ( []Elem,  int) {
	return .appendNext(, source{bytes: })
}

func ( *Table) ( []Elem,  string) ( []Elem,  int) {
	return .appendNext(, source{str: })
}

func ( *Table) ( int,  []byte) int {
	// TODO: implement
	panic("not implemented")
}

func ( *Table) ( int,  string) int {
	// TODO: implement
	panic("not implemented")
}

func ( *Table) () []string {
	// TODO: implement
	panic("not implemented")
}

func ( *Table) () uint32 {
	return .VariableTop
}

type source struct {
	str   string
	bytes []byte
}

func ( *source) ( *Table) ( Elem,  int) {
	if .bytes == nil {
		return .Index.lookupString(.str)
	}
	return .Index.lookup(.bytes)
}

func ( *source) ( int) {
	if .bytes == nil {
		.str = .str[:]
	} else {
		.bytes = .bytes[:]
	}
}

func ( *source) ( []byte,  int) []byte {
	if .bytes == nil {
		return norm.NFD.AppendString([:0], .str[:])
	}
	return norm.NFD.Append([:0], .bytes[:]...)
}

func ( *source) () ( rune,  int) {
	if .bytes == nil {
		return utf8.DecodeRuneInString(.str)
	}
	return utf8.DecodeRune(.bytes)
}

func ( *source) ( norm.Form) norm.Properties {
	if .bytes == nil {
		return .PropertiesString(.str)
	}
	return .Properties(.bytes)
}

// appendNext appends the weights corresponding to the next rune or
// contraction in s.  If a contraction is matched to a discontinuous
// sequence of runes, the weights for the interstitial runes are
// appended as well.  It returns a new slice that includes the appended
// weights and the number of bytes consumed from s.
func ( *Table) ( []Elem,  source) ( []Elem,  int) {
	,  := .lookup()
	 := .ctype()
	if  == ceNormal {
		if  == 0 {
			,  := .rune()
			const (
				  = 3
				 = 0xAC00
				  = 0xD7A3
			)
			if  >=  &&  <=  {
				// TODO: performance can be considerably improved here.
				 = 
				var  [16]byte // Used for decomposing Hangul.
				for  := .nfd([:0], ); len() > 0;  = [:] {
					,  = .Index.lookup()
					 = append(, )
				}
				return , 
			}
			 = makeImplicitCE(implicitPrimary())
		}
		 = append(, )
	} else if  == ceExpansionIndex {
		 = .appendExpansion(, )
	} else if  == ceContractionIndex {
		 := 0
		.tail()
		if .bytes == nil {
			,  = .matchContractionString(, , .str)
		} else {
			,  = .matchContraction(, , .bytes)
		}
		 += 
	} else if  == ceDecompose {
		// Decompose using NFKD and replace tertiary weights.
		,  := splitDecompose()
		 := len()
		 := .properties(norm.NFKD).Decomposition()
		for  := 0; len() > 0;  = [:] {
			,  = .(, source{bytes: })
		}
		[] = [].updateTertiary()
		if ++;  < len() {
			[] = [].updateTertiary()
			for ++;  < len(); ++ {
				[] = [].updateTertiary(maxTertiary)
			}
		}
	}
	return , 
}

func ( *Table) ( []Elem,  Elem) []Elem {
	 := splitExpandIndex()
	 := int(.ExpandElem[])
	++
	for ,  := range .ExpandElem[ : +] {
		 = append(, Elem())
	}
	return 
}

func ( *Table) ( []Elem,  Elem,  []byte) ([]Elem, int) {
	, ,  := splitContractIndex()

	 := .ContractTries.scanner(, , )
	 := [norm.MaxSegmentSize]byte{}
	 := 0
	 := .scan(0)

	if !.done &&  < len() && [] >= utf8.RuneSelf {
		// By now we should have filtered most cases.
		 := 
		 := 0
		 := norm.NFD.Properties([:])
		 += .Size()
		if .LeadCCC() != 0 {
			 := .TrailCCC()
			// A gap may only occur in the last normalization segment.
			// This also ensures that len(scan.s) < norm.MaxSegmentSize.
			if  := norm.NFD.FirstBoundary([:]);  != -1 {
				.s = [:+]
			}
			for  < len() && !.done && [] >= utf8.RuneSelf {
				 = norm.NFD.Properties([:])
				if  := .LeadCCC();  == 0 ||  >=  {
					break
				}
				 = .TrailCCC()
				if  := .scan();  !=  {
					// Copy the interstitial runes for later processing.
					 += copy([:], [:])
					if .pindex ==  {
						 = 
					}
					,  = , 
				} else {
					 += .Size()
				}
			}
		}
	}
	// Append weights for the matched contraction, which may be an expansion.
	,  := .result()
	 = Elem(.ContractElem[+])
	if .ctype() == ceNormal {
		 = append(, )
	} else {
		 = .appendExpansion(, )
	}
	// Append weights for the runes in the segment not part of the contraction.
	for ,  := [:], 0; len() > 0;  = [:] {
		,  = .appendNext(, source{bytes: })
	}
	return , 
}

// TODO: unify the two implementations. This is best done after first simplifying
// the algorithm taking into account the inclusion of both NFC and NFD forms
// in the table.
func ( *Table) ( []Elem,  Elem,  string) ([]Elem, int) {
	, ,  := splitContractIndex()

	 := .ContractTries.scannerString(, , )
	 := [norm.MaxSegmentSize]byte{}
	 := 0
	 := .scan(0)

	if !.done &&  < len() && [] >= utf8.RuneSelf {
		// By now we should have filtered most cases.
		 := 
		 := 0
		 := norm.NFD.PropertiesString([:])
		 += .Size()
		if .LeadCCC() != 0 {
			 := .TrailCCC()
			// A gap may only occur in the last normalization segment.
			// This also ensures that len(scan.s) < norm.MaxSegmentSize.
			if  := norm.NFD.FirstBoundaryInString([:]);  != -1 {
				.s = [:+]
			}
			for  < len() && !.done && [] >= utf8.RuneSelf {
				 = norm.NFD.PropertiesString([:])
				if  := .LeadCCC();  == 0 ||  >=  {
					break
				}
				 = .TrailCCC()
				if  := .scan();  !=  {
					// Copy the interstitial runes for later processing.
					 += copy([:], [:])
					if .pindex ==  {
						 = 
					}
					,  = , 
				} else {
					 += .Size()
				}
			}
		}
	}
	// Append weights for the matched contraction, which may be an expansion.
	,  := .result()
	 = Elem(.ContractElem[+])
	if .ctype() == ceNormal {
		 = append(, )
	} else {
		 = .appendExpansion(, )
	}
	// Append weights for the runes in the segment not part of the contraction.
	for ,  := [:], 0; len() > 0;  = [:] {
		,  = .appendNext(, source{bytes: })
	}
	return , 
}