package ksuid

import (
	
	
)

const (
	// lexographic ordering (based on Unicode table) is 0-9A-Za-z
	base62Characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
	zeroString       = "000000000000000000000000000"
	offsetUppercase  = 10
	offsetLowercase  = 36
)

var (
	errShortBuffer = errors.New("the output buffer is too small to hold to decoded value")
)

// Converts a base 62 byte into the number value that it represents.
func base62Value( byte) byte {
	switch {
	case  >= '0' &&  <= '9':
		return  - '0'
	case  >= 'A' &&  <= 'Z':
		return offsetUppercase + ( - 'A')
	default:
		return offsetLowercase + ( - 'a')
	}
}

// This function encodes the base 62 representation of the src KSUID in binary
// form into dst.
//
// In order to support a couple of optimizations the function assumes that src
// is 20 bytes long and dst is 27 bytes long.
//
// Any unused bytes in dst will be set to the padding '0' byte.
func fastEncodeBase62( []byte,  []byte) {
	const  = 4294967296
	const  = 62

	// Split src into 5 4-byte words, this is where most of the efficiency comes
	// from because this is a O(N^2) algorithm, and we make N = N / 4 by working
	// on 32 bits at a time.
	 := [5]uint32{
		binary.BigEndian.Uint32([0:4]),
		binary.BigEndian.Uint32([4:8]),
		binary.BigEndian.Uint32([8:12]),
		binary.BigEndian.Uint32([12:16]),
		binary.BigEndian.Uint32([16:20]),
	}

	 := len()
	 := [:]
	 := [5]uint32{}

	for len() != 0 {
		 := [:0]
		 := uint64(0)

		for ,  := range  {
			 := uint64() + uint64()*
			 :=  / 
			 =  % 

			if len() != 0 ||  != 0 {
				 = append(, uint32())
			}
		}

		// Writes at the end of the destination buffer because we computed the
		// lowest bits first.
		--
		[] = base62Characters[]
		 = 
	}

	// Add padding at the head of the destination buffer for all bytes that were
	// not set.
	copy([:], zeroString)
}

// This function appends the base 62 representation of the KSUID in src to dst,
// and returns the extended byte slice.
// The result is left-padded with '0' bytes to always append 27 bytes to the
// destination buffer.
func fastAppendEncodeBase62( []byte,  []byte) []byte {
	 = reserve(, stringEncodedLength)
	 := len()
	fastEncodeBase62([:+stringEncodedLength], )
	return [:+stringEncodedLength]
}

// This function decodes the base 62 representation of the src KSUID to the
// binary form into dst.
//
// In order to support a couple of optimizations the function assumes that src
// is 27 bytes long and dst is 20 bytes long.
//
// Any unused bytes in dst will be set to zero.
func fastDecodeBase62( []byte,  []byte) error {
	const  = 62
	const  = 4294967296

	// This line helps BCE (Bounds Check Elimination).
	// It may be safely removed.
	_ = [26]

	 := [27]byte{
		base62Value([0]),
		base62Value([1]),
		base62Value([2]),
		base62Value([3]),
		base62Value([4]),
		base62Value([5]),
		base62Value([6]),
		base62Value([7]),
		base62Value([8]),
		base62Value([9]),

		base62Value([10]),
		base62Value([11]),
		base62Value([12]),
		base62Value([13]),
		base62Value([14]),
		base62Value([15]),
		base62Value([16]),
		base62Value([17]),
		base62Value([18]),
		base62Value([19]),

		base62Value([20]),
		base62Value([21]),
		base62Value([22]),
		base62Value([23]),
		base62Value([24]),
		base62Value([25]),
		base62Value([26]),
	}

	 := len()
	 := [:]
	 := [stringEncodedLength]byte{}

	for len() > 0 {
		 := [:0]
		 := uint64(0)

		for ,  := range  {
			 := uint64() + uint64()*
			 :=  / 
			 =  % 

			if len() != 0 ||  != 0 {
				 = append(, byte())
			}
		}

		if  < 4 {
			return errShortBuffer
		}

		[-4] = byte( >> 24)
		[-3] = byte( >> 16)
		[-2] = byte( >> 8)
		[-1] = byte()
		 -= 4
		 = 
	}

	var  [20]byte
	copy([:], [:])
	return nil
}

// This function appends the base 62 decoded version of src into dst.
func fastAppendDecodeBase62( []byte,  []byte) []byte {
	 = reserve(, byteLength)
	 := len()
	fastDecodeBase62([:+byteLength], )
	return [:+byteLength]
}

// Ensures that at least nbytes are available in the remaining capacity of the
// destination slice, if not, a new copy is made and returned by the function.
func reserve( []byte,  int) []byte {
	 := cap()
	 := len()

	if  :=  - ;  <  {
		 *= 2
		if ( - ) <  {
			 =  + 
		}
		 := make([]byte, , )
		copy(, )
		 = 
	}

	return 
}