package network

import (
	"encoding/binary"
	"errors"
	"fmt"
)

var (
	bitMasksBig    = []byte{0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}
	bitMasksLittle = []byte{0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}
)

type BitSplit struct {
	p    []uint8
	size uint64
}

func (b *BitSplit) Size() uint64 {
	return b.size
}

func (b *BitSplit) All() []int {
	a := make([]int, len(b.p))
	for i := 0; i < len(b.p); i++ {
		a[i] = int(b.p[i])
	}
	return a
}

func (b *BitSplit) Is0(i uint64) bool {
	if i >= b.size {
		return false
	}
	return b.p[i] == 0
}

func (b *BitSplit) Is1(i uint64) bool {
	if i >= b.size {
		return false
	}
	return b.p[i] == 1
}

func (b *BitSplit) String() string {
	return fmt.Sprintf("%v", b.p)
}

func binarySplit(p []byte, bitMasks []byte) (*BitSplit, error) {
	if len(p) == 0 {
		return nil, errors.New("no data")
	}
	bs := new(BitSplit)
	bs.p = make([]uint8, 0, len(p)*8) // *8 是因为每个字节占 8 位
	for _, b := range p {
		for _, bm := range bitMasks {
			v := 0
			if b&bm > 0 {
				v = 1
			}
			bs.p = append(bs.p, uint8(v))
		}
	}
	bs.size = uint64(len(bs.p))
	return bs, nil
}

type bigEndian struct{}

func (b *bigEndian) PutUint16(u uint16) []byte {
	p := make([]byte, 2)
	binary.BigEndian.PutUint16(p, u)
	return p
}

func (b *bigEndian) PutUint32(u uint32) []byte {
	p := make([]byte, 4)
	binary.BigEndian.PutUint32(p, u)
	return p
}

func (b *bigEndian) PutUint64(u uint64) []byte {
	p := make([]byte, 8)
	binary.BigEndian.PutUint64(p, u)
	return p
}

func (b *bigEndian) BitSplit(p []byte) (*BitSplit, error) {
	return binarySplit(p, bitMasksBig)
}

func (b *bigEndian) Int16(p []byte) int16 {
	if len(p) != 2 {
		return 0
	}
	return int16(p[1]) | int16(p[0])<<8
}

func (b *bigEndian) Int32(p []byte) int32 {
	if len(p) != 4 {
		return 0
	}
	_ = p[3]
	return int32(p[3]) | int32(p[2])<<8 | int32(p[1])<<16 | int32(p[0])<<24
}

func (b *bigEndian) Int64(p []byte) int64 {
	if len(p) != 8 {
		return 0
	}
	_ = p[7]
	return int64(p[7]) | int64(p[6])<<8 | int64(p[5])<<16 | int64(p[4])<<24 |
		int64(p[3])<<32 | int64(p[2])<<40 | int64(p[1])<<48 | int64(p[0])<<56
}

func (b *bigEndian) Uint16(p []byte) uint16 {
	if len(p) != 2 {
		return 0
	}
	return binary.BigEndian.Uint16(p)
}

func (b *bigEndian) Uint32(p []byte) uint32 {
	if len(p) != 4 {
		return 0
	}
	return binary.BigEndian.Uint32(p)
}

func (b *bigEndian) Uint64(p []byte) uint64 {
	if len(p) != 8 {
		return 0
	}
	return binary.BigEndian.Uint64(p)
}

type littleEndian struct{}

func (l *littleEndian) PutUint16(u uint16) []byte {
	p := make([]byte, 2)
	binary.LittleEndian.PutUint16(p, u)
	return p
}

func (l *littleEndian) PutUint32(u uint32) []byte {
	p := make([]byte, 4)
	binary.LittleEndian.PutUint32(p, u)
	return p
}

func (l *littleEndian) PutUint64(u uint64) []byte {
	p := make([]byte, 8)
	binary.LittleEndian.PutUint64(p, u)
	return p
}

func (l *littleEndian) BitSplit(p []byte) (*BitSplit, error) {
	return binarySplit(p, bitMasksLittle)
}

func (l *littleEndian) Int16(p []byte) int16 {
	if len(p) != 2 {
		return 0
	}
	return int16(p[0]) | int16(p[1])<<8
}

func (l *littleEndian) Uint16(b []byte) uint16 {
	if len(b) != 2 {
		return 0
	}
	return binary.LittleEndian.Uint16(b)
}

func (l *littleEndian) Uint32(b []byte) uint32 {
	if len(b) != 4 {
		return 0
	}
	return binary.LittleEndian.Uint32(b)
}

func (l *littleEndian) Uint64(b []byte) uint64 {
	if len(b) != 8 {
		return 0
	}
	return binary.LittleEndian.Uint64(b)
}

// 举例:
// 数值 0x22 0x11 使用两个字节储存: 高位字节是 0x22, 低位字节是 0x11
// BigEndian 高位字节在前, 低位字节在后. 即 0x2211
// LittleEndian 低位字节在前, 高位字节在后. 即 0x1122
// 只有读取的时候才必须区分字节序, 其他情况都不用考虑
var (
	BigEndian    = &bigEndian{}
	LittleEndian = &littleEndian{}
)
