package humanize

import (
	
	
	
	
)

var (
	bigIECExp = big.NewInt(1024)

	// BigByte is one byte in bit.Ints
	BigByte = big.NewInt(1)
	// BigKiByte is 1,024 bytes in bit.Ints
	BigKiByte = (&big.Int{}).Mul(BigByte, bigIECExp)
	// BigMiByte is 1,024 k bytes in bit.Ints
	BigMiByte = (&big.Int{}).Mul(BigKiByte, bigIECExp)
	// BigGiByte is 1,024 m bytes in bit.Ints
	BigGiByte = (&big.Int{}).Mul(BigMiByte, bigIECExp)
	// BigTiByte is 1,024 g bytes in bit.Ints
	BigTiByte = (&big.Int{}).Mul(BigGiByte, bigIECExp)
	// BigPiByte is 1,024 t bytes in bit.Ints
	BigPiByte = (&big.Int{}).Mul(BigTiByte, bigIECExp)
	// BigEiByte is 1,024 p bytes in bit.Ints
	BigEiByte = (&big.Int{}).Mul(BigPiByte, bigIECExp)
	// BigZiByte is 1,024 e bytes in bit.Ints
	BigZiByte = (&big.Int{}).Mul(BigEiByte, bigIECExp)
	// BigYiByte is 1,024 z bytes in bit.Ints
	BigYiByte = (&big.Int{}).Mul(BigZiByte, bigIECExp)
	// BigRiByte is 1,024 y bytes in bit.Ints
	BigRiByte = (&big.Int{}).Mul(BigYiByte, bigIECExp)
	// BigQiByte is 1,024 r bytes in bit.Ints
	BigQiByte = (&big.Int{}).Mul(BigRiByte, bigIECExp)
)

var (
	bigSIExp = big.NewInt(1000)

	// BigSIByte is one SI byte in big.Ints
	BigSIByte = big.NewInt(1)
	// BigKByte is 1,000 SI bytes in big.Ints
	BigKByte = (&big.Int{}).Mul(BigSIByte, bigSIExp)
	// BigMByte is 1,000 SI k bytes in big.Ints
	BigMByte = (&big.Int{}).Mul(BigKByte, bigSIExp)
	// BigGByte is 1,000 SI m bytes in big.Ints
	BigGByte = (&big.Int{}).Mul(BigMByte, bigSIExp)
	// BigTByte is 1,000 SI g bytes in big.Ints
	BigTByte = (&big.Int{}).Mul(BigGByte, bigSIExp)
	// BigPByte is 1,000 SI t bytes in big.Ints
	BigPByte = (&big.Int{}).Mul(BigTByte, bigSIExp)
	// BigEByte is 1,000 SI p bytes in big.Ints
	BigEByte = (&big.Int{}).Mul(BigPByte, bigSIExp)
	// BigZByte is 1,000 SI e bytes in big.Ints
	BigZByte = (&big.Int{}).Mul(BigEByte, bigSIExp)
	// BigYByte is 1,000 SI z bytes in big.Ints
	BigYByte = (&big.Int{}).Mul(BigZByte, bigSIExp)
	// BigRByte is 1,000 SI y bytes in big.Ints
	BigRByte = (&big.Int{}).Mul(BigYByte, bigSIExp)
	// BigQByte is 1,000 SI r bytes in big.Ints
	BigQByte = (&big.Int{}).Mul(BigRByte, bigSIExp)
)

var bigBytesSizeTable = map[string]*big.Int{
	"b":   BigByte,
	"kib": BigKiByte,
	"kb":  BigKByte,
	"mib": BigMiByte,
	"mb":  BigMByte,
	"gib": BigGiByte,
	"gb":  BigGByte,
	"tib": BigTiByte,
	"tb":  BigTByte,
	"pib": BigPiByte,
	"pb":  BigPByte,
	"eib": BigEiByte,
	"eb":  BigEByte,
	"zib": BigZiByte,
	"zb":  BigZByte,
	"yib": BigYiByte,
	"yb":  BigYByte,
	"rib": BigRiByte,
	"rb":  BigRByte,
	"qib": BigQiByte,
	"qb":  BigQByte,
	// Without suffix
	"":   BigByte,
	"ki": BigKiByte,
	"k":  BigKByte,
	"mi": BigMiByte,
	"m":  BigMByte,
	"gi": BigGiByte,
	"g":  BigGByte,
	"ti": BigTiByte,
	"t":  BigTByte,
	"pi": BigPiByte,
	"p":  BigPByte,
	"ei": BigEiByte,
	"e":  BigEByte,
	"z":  BigZByte,
	"zi": BigZiByte,
	"y":  BigYByte,
	"yi": BigYiByte,
	"r":  BigRByte,
	"ri": BigRiByte,
	"q":  BigQByte,
	"qi": BigQiByte,
}

var ten = big.NewInt(10)

func humanateBigBytes(,  *big.Int,  []string) string {
	if .Cmp(ten) < 0 {
		return fmt.Sprintf("%d B", )
	}
	 := (&big.Int{}).Set()
	,  := oomm(, , len()-1)
	 := []
	 := "%.0f %s"
	if  < 10 {
		 = "%.1f %s"
	}

	return fmt.Sprintf(, , )

}

// BigBytes produces a human readable representation of an SI size.
//
// See also: ParseBigBytes.
//
// BigBytes(82854982) -> 83 MB
func ( *big.Int) string {
	 := []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB", "RB", "QB"}
	return humanateBigBytes(, bigSIExp, )
}

// BigIBytes produces a human readable representation of an IEC size.
//
// See also: ParseBigBytes.
//
// BigIBytes(82854982) -> 79 MiB
func ( *big.Int) string {
	 := []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB", "RiB", "QiB"}
	return humanateBigBytes(, bigIECExp, )
}

// ParseBigBytes parses a string representation of bytes into the number
// of bytes it represents.
//
// See also: BigBytes, BigIBytes.
//
// ParseBigBytes("42 MB") -> 42000000, nil
// ParseBigBytes("42 mib") -> 44040192, nil
func ( string) (*big.Int, error) {
	 := 0
	 := false
	for ,  := range  {
		if !(unicode.IsDigit() ||  == '.' ||  == ',') {
			break
		}
		if  == ',' {
			 = true
		}
		++
	}

	 := [:]
	if  {
		 = strings.Replace(, ",", "", -1)
	}

	 := &big.Rat{}
	,  := fmt.Sscanf(, "%f", )
	if  != nil {
		return nil, 
	}

	 := strings.ToLower(strings.TrimSpace([:]))
	if ,  := bigBytesSizeTable[];  {
		 := (&big.Rat{}).SetInt()
		.Mul(, )
		 := &big.Int{}
		.Div(.Num(), .Denom())
		return , nil
	}

	return nil, fmt.Errorf("unhandled size name: %v", )
}