package protocol

import (
	"bytes"
	"dlt645-server/utils"
	"encoding/binary"
	"golang.org/x/text/encoding/simplifiedchinese"
	"golang.org/x/text/transform"
	"io"
	"io/ioutil"
	"time"
)

type Writer struct {
	b *bytes.Buffer
}

func NewWriter() Writer {
	return Writer{b: bytes.NewBuffer(nil)}
}

func (writer *Writer) Bytes() []byte {
	return writer.b.Bytes()
}

func (writer *Writer) Write(p []byte, size ...int) *Writer {
	if len(size) == 0 {
		writer.b.Write(p)
		return writer
	}

	if len(p) >= size[0] {
		writer.b.Write(p[:size[0]])
	} else {
		writer.b.Write(p)
		end := size[0] - len(p)
		for i := 0; i < end; i++ {
			writer.b.WriteByte(0)
		}
	}
	return writer
}

func (writer *Writer) WriteByte(b byte) *Writer {
	writer.b.WriteByte(b)
	return writer
}

func (writer *Writer) WriteUint16(n uint16) *Writer {
	var buf [2]byte
	binary.BigEndian.PutUint16(buf[:], n)
	writer.b.Write(buf[:])
	return writer
}

func (writer *Writer) WriteUint32(n uint32) *Writer {
	var buf [4]byte
	binary.BigEndian.PutUint32(buf[:], n)
	writer.b.Write(buf[:])
	return writer
}

func (writer *Writer) WriteBcdTime(t time.Time) *Writer {
	writer.b.Write(utils.ToBCDTime(t))
	return writer
}

func (writer *Writer) WritString(str string, size ...int) error {
	reader := bytes.NewReader([]byte(str))
	data, err := ioutil.ReadAll(
		transform.NewReader(reader, simplifiedchinese.GB18030.NewEncoder()))
	if err != nil {
		return err
	}
	writer.Write(data, size...)
	return nil
}

type Reader struct {
	d []byte
	r *bytes.Reader
}

func NewReader(data []byte) Reader {
	return Reader{d: data, r: bytes.NewReader(data)}
}

func (reader *Reader) Len() int {
	return reader.r.Len()
}

func (reader *Reader) Read(size ...int) ([]byte, error) {
	num := reader.r.Len()
	if len(size) > 0 {
		num = size[0]
	}

	if num > reader.r.Len() {
		return nil, io.ErrUnexpectedEOF
	}

	curr := len(reader.d) - reader.r.Len()
	buf := reader.d[curr : curr+num]
	reader.r.Seek(int64(num), io.SeekCurrent)
	return buf, nil
}

func (reader *Reader) ReadByte() (byte, error) {
	return reader.r.ReadByte()
}

func (reader *Reader) ReadUint16() (uint16, error) {
	if reader.r.Len() < 2 {
		return 0, io.ErrUnexpectedEOF
	}

	var buf [2]byte
	n, err := reader.r.Read(buf[:])
	if err != nil {
		return 0, err
	}
	if n != len(buf) {
		return 0, io.ErrUnexpectedEOF
	}
	return binary.BigEndian.Uint16(buf[:]), nil
}

func (reader *Reader) ReadUint32() (uint32, error) {
	if reader.r.Len() < 4 {
		return 0, io.ErrUnexpectedEOF
	}

	var buf [4]byte
	n, err := reader.r.Read(buf[:])
	if err != nil {
		return 0, err
	}
	if n != len(buf) {
		return 0, io.ErrUnexpectedEOF
	}
	return binary.BigEndian.Uint32(buf[:]), nil
}

//LittleEndian高位到低位读取
func (reader *Reader) ReadUint64() (uint64, error) {
	if reader.r.Len() < 8 {
		return 0, io.ErrUnexpectedEOF
	}

	var buf [8]byte
	n, err := reader.r.Read(buf[:])
	if err != nil {
		return 0, err
	}
	if n != len(buf) {
		return 0, io.ErrUnexpectedEOF
	}
	return binary.BigEndian.Uint64(buf[:]), nil
}

func (reader *Reader) ReadBcdTime() (time.Time, error) {
	if reader.r.Len() < 6 {
		return time.Time{}, io.ErrUnexpectedEOF
	}

	var buf [6]byte
	n, err := reader.r.Read(buf[:])
	if err != nil {
		return time.Time{}, err
	}
	if n != len(buf) {
		return time.Time{}, io.ErrUnexpectedEOF
	}
	return utils.FromBCDTime(buf[:])
}

func (reader *Reader) ReadString(size ...int) (string, error) {
	data, err := reader.Read(size...)
	if err != nil {
		return "", err
	}

	text, err := ioutil.ReadAll(transform.NewReader(
		bytes.NewReader(data), simplifiedchinese.GB18030.NewDecoder()))
	if err != nil {
		return "", err
	}
	return utils.BytesToString(text), nil

}
