// based on https://github.com/powturbo/Turbo-Base64
package yu_base64

import yu_fast "gogs.qqck.cn/s/tools/fast"

type Encoding struct {
	lutSe  [64]byte
	lutXe  [4096]uint32
	lutXd0 [256]uint32
	lutXd1 [256]uint32
	lutXd2 [256]uint32
	lutXd3 [256]uint32
	pad    bool
}

func (e *Encoding) EncodedLen(n int) int {
	if !e.pad {
		return (n*8 + 5) / 6
	}
	return (n + 2) / 3 * 4
}

func (e *Encoding) Encode(src []byte) []byte {
	if len(src) == 0 {
		return []byte{}
	}
	length := e.EncodedLen(len(src))
	dst := make([]byte, length)
	e.encode(dst, src, uintptr(length))
	return dst
}

func (e *Encoding) EncodeS(src string) []byte {
	return e.Encode(yu_fast.S2B(src))
}

func (e *Encoding) Encode2S(src []byte) string {
	return string(e.Encode(src))
}

func (e *Encoding) EncodeS2S(src string) string {
	return string(e.Encode(yu_fast.S2B(src)))
}

func (e *Encoding) DecodedLen(n int) int {
	sf := 0
	if n > 4 {
		sf++
	}
	if !e.pad {
		return n*6/8 + sf
	}
	return n/4*3 + sf
}

func (e *Encoding) Decode(src []byte) []byte {
	if len(src) == 0 {
		return []byte{}
	}
	length := e.DecodedLen(len(src))
	if length == 0 {
		return []byte{}
	}
	dst := make([]byte, length)
	return dst[:e.decode(dst, src)]
}

func (e *Encoding) DecodeS(src string) []byte {
	return e.Decode(yu_fast.S2B(src))
}

func (e *Encoding) Decode2S(src []byte) string {
	return string(e.Decode(src))
}

func (e *Encoding) DecodeS2S(src string) string {
	return string(e.Decode(yu_fast.S2B(src)))
}

func NewEncoding(lutSe [64]byte, pad bool) *Encoding {
	lutXe, lutXd0, lutXd1, lutXd2, lutXd3 := makeLuts(lutSe)
	return &Encoding{
		lutSe:  lutSe,
		lutXe:  lutXe,
		lutXd0: lutXd0,
		lutXd1: lutXd1,
		lutXd2: lutXd2,
		lutXd3: lutXd3,
		pad:    pad,
	}
}

var (
	Std    = NewEncoding(stdLutSe, true)
	RawStd = NewEncoding(stdLutSe, false)
	URL    = NewEncoding(urlLutSe, true)
	RawURL = NewEncoding(urlLutSe, false)
)
