package codec

import (
	
	
	

	

	
)

// Full is full MTProto transport.
//
// See https://core.telegram.org/mtproto/mtproto-transports#full
type Full struct {
	wSeqNo int64
	rSeqNo int64
}

// WriteHeader sends protocol tag.
func ( *Full) ( io.Writer) ( error) {
	return nil
}

// ReadHeader reads protocol tag.
func ( *Full) ( io.Reader) ( error) {
	return nil
}

// Write encode to writer message from given buffer.
func ( *Full) ( io.Writer,  *bin.Buffer) error {
	if  := checkOutgoingMessage();  != nil {
		return 
	}

	if  := writeFull(, int(atomic.AddInt64(&.wSeqNo, 1)-1), );  != nil {
		return errors.Wrap(, "write full")
	}

	return nil
}

// Read fills buffer with received message.
func ( *Full) ( io.Reader,  *bin.Buffer) error {
	if  := readFull(, int(atomic.AddInt64(&.rSeqNo, 1)-1), );  != nil {
		return errors.Wrap(, "read full")
	}

	return checkProtocolError()
}

func ( io.Writer,  int,  *bin.Buffer) error {
	 := bin.Buffer{Buf: make([]byte, 0, 4+4+.Len()+4)}
	// Length: length+seqno+payload+crc length encoded as 4 length bytes
	// (little endian, the length of the length field must be included, too)
	.PutInt(4 + 4 + .Len() + 4)
	// Seqno: the TCP sequence number for this TCP connection (different from the MTProto sequence number):
	// the first packet sent is numbered 0, the next one 1, etc.
	.PutInt()
	// payload: MTProto payload
	.Put(.Raw())
	// crc: 4 CRC32 bytes computed using length, sequence number, and payload together.
	 := crc32.ChecksumIEEE(.Raw())
	.PutUint32()

	if ,  := .Write(.Raw());  != nil {
		return 
	}

	return nil
}

var errSeqNoMismatch = errors.New("seq_no mismatch")
var errCRCMismatch = errors.New("crc mismatch")

func ( io.Reader,  int,  *bin.Buffer) error {
	,  := readLen(, )
	if  != nil {
		return errors.Wrap(, "len")
	}

	// Put length, because it need to count CRC.
	.PutInt()
	.Expand( - bin.Word)
	 := &bin.Buffer{Buf: .Buf[bin.Word:]}

	// Reads tail of packet to the buffer.
	// Length already read.
	if ,  := io.ReadFull(, .Buf);  != nil {
		return errors.Wrap(, "read seqno, buffer and crc")
	}

	,  := .Int()
	if  != nil {
		return 
	}
	if  !=  {
		return errSeqNoMismatch
	}

	 :=  - 3*bin.Word
	.Skip()

	// Cut only crc part.
	,  := .Uint32()
	if  != nil {
		return 
	}

	// Compute crc using all buffer without last 4 bytes from server.
	 := crc32.ChecksumIEEE(.Buf[0 : -bin.Word])
	// Compare computed and read CRCs.
	if  !=  {
		return errCRCMismatch
	}

	// 				  n
	// Length | SeqNo | payload | CRC  |
	//  Word  |  Word | ....... | Word |
	copy(.Buf, .Buf[2*bin.Word:-bin.Word])
	.Buf = .Buf[:]
	return nil
}