package humanize

import (
	
	
	
	
	
)

// IEC Sizes.
// kibis of bits
const (
	Byte = 1 << (iota * 10)
	KiByte
	MiByte
	GiByte
	TiByte
	PiByte
	EiByte
)

// SI Sizes.
const (
	IByte = 1
	KByte = IByte * 1000
	MByte = KByte * 1000
	GByte = MByte * 1000
	TByte = GByte * 1000
	PByte = TByte * 1000
	EByte = PByte * 1000
)

var bytesSizeTable = map[string]uint64{
	"b":   Byte,
	"kib": KiByte,
	"kb":  KByte,
	"mib": MiByte,
	"mb":  MByte,
	"gib": GiByte,
	"gb":  GByte,
	"tib": TiByte,
	"tb":  TByte,
	"pib": PiByte,
	"pb":  PByte,
	"eib": EiByte,
	"eb":  EByte,
	// Without suffix
	"":   Byte,
	"ki": KiByte,
	"k":  KByte,
	"mi": MiByte,
	"m":  MByte,
	"gi": GiByte,
	"g":  GByte,
	"ti": TiByte,
	"t":  TByte,
	"pi": PiByte,
	"p":  PByte,
	"ei": EiByte,
	"e":  EByte,
}

func logn(,  float64) float64 {
	return math.Log() / math.Log()
}

func humanateBytes( uint64,  float64,  []string) string {
	if  < 10 {
		return fmt.Sprintf("%d B", )
	}
	 := math.Floor(logn(float64(), ))
	 := [int()]
	 := math.Floor(float64()/math.Pow(, )*10+0.5) / 10
	 := "%.0f %s"
	if  < 10 {
		 = "%.1f %s"
	}

	return fmt.Sprintf(, , )
}

// Bytes produces a human readable representation of an SI size.
//
// See also: ParseBytes.
//
// Bytes(82854982) -> 83 MB
func ( uint64) string {
	 := []string{"B", "kB", "MB", "GB", "TB", "PB", "EB"}
	return humanateBytes(, 1000, )
}

// IBytes produces a human readable representation of an IEC size.
//
// See also: ParseBytes.
//
// IBytes(82854982) -> 79 MiB
func ( uint64) string {
	 := []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"}
	return humanateBytes(, 1024, )
}

// ParseBytes parses a string representation of bytes into the number
// of bytes it represents.
//
// See Also: Bytes, IBytes.
//
// ParseBytes("42 MB") -> 42000000, nil
// ParseBytes("42 mib") -> 44040192, nil
func ( string) (uint64, error) {
	 := 0
	 := false
	for ,  := range  {
		if !(unicode.IsDigit() ||  == '.' ||  == ',') {
			break
		}
		if  == ',' {
			 = true
		}
		++
	}

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

	,  := strconv.ParseFloat(, 64)
	if  != nil {
		return 0, 
	}

	 := strings.ToLower(strings.TrimSpace([:]))
	if ,  := bytesSizeTable[];  {
		 *= float64()
		if  >= math.MaxUint64 {
			return 0, fmt.Errorf("too large: %v", )
		}
		return uint64(), nil
	}

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