package protocol

import "io"
import "fmt"

// ReadInt reads a little-endian integer from a reader and returns it as result.
// It will read the amount of bytes specified by bytes.
func ReadInt (reader io.Reader, bytes int) (result uint, err error) {
	buf   := [1]byte { }
	shift := 0
	for {
		justRead := 0
		for justRead == 0 && err == nil {
			justRead, err = reader.Read(buf[:])
			if err != nil { break }
		}
		
		result += uint(buf[0]) << shift
		
		bytes --
		shift += 8
		if bytes == 0 {
			break
		}
	}

	return
}

func MaxIntOfSize (bytes int) (max uint) {
	for {
		max |= 0xFF
		bytes --
		if bytes > 0 {
			max <<= 8
		} else {
			break
		}
	}
	
	return
}

// ReadU8 reads an 8-bit integer.
func ReadU8 (reader io.Reader) (result uint8, err error) {
	untypedResult, err := ReadInt(reader, 1)
	return uint8(untypedResult), err
}

// ReadU16 reads a 16-bit integer.
func ReadU16 (reader io.Reader) (result uint16, err error) {
	untypedResult, err := ReadInt(reader, 2)
	return uint16(untypedResult), err
}

// ReadU24 reads a 24-bit integer.
func ReadU24 (reader io.Reader) (result uint32, err error) {
	untypedResult, err := ReadInt(reader, 3)
	return uint32(untypedResult), err
}

// ReadU32 reads a 32-bit integer.
func ReadU32 (reader io.Reader) (result uint32, err error) {
	untypedResult, err := ReadInt(reader, 4)
	return uint32(untypedResult), err
}

// WriteInt writes a little-endian integer to a writer. It will write the amount
// of bytes specified by bytes.
func WriteInt (writer io.Writer, bytes int, integer uint) (err error) {
	if integer > MaxIntOfSize(bytes) {
		panic(fmt.Sprintf("uint %d cannot fit in %d bytes", integer, bytes))
	}

	buf := [1]byte { }
	for {
		buf[0] = byte(integer & 0xFF)
		
		justWrote := 0
		for justWrote == 0 {
			justWrote, err = writer.Write(buf[:])
			if err != nil { return }
		}
		
		bytes --
		if bytes > 0 {
			integer >>= 8
		} else {
			break
		}
	}

	return
}

// WriteU8 writes an 8-bit integer.
func WriteU8 (writer io.Writer, integer uint8) error {
	return WriteInt(writer, 1, uint(integer))
}

// WriteU16 writes an 16-bit integer.
func WriteU16 (writer io.Writer, integer uint16) error {
	return WriteInt(writer, 2, uint(integer))
}

// WriteU24 writes an 24-bit integer.
func WriteU24 (writer io.Writer, integer uint32) error {
	return WriteInt(writer, 3, uint(integer))
}

// WriteU32 writes an 32-bit integer.
func WriteU32 (writer io.Writer, integer uint32) error {
	return WriteInt(writer, 4, uint(integer))
}
