package wsutil

import (
	
	
	

	
)

// ErrNoFrameAdvance means that Reader's Read() method was called without
// preceding NextFrame() call.
var ErrNoFrameAdvance = errors.New("no frame advance")

// ErrFrameTooLarge indicates that a message of length higher than
// MaxFrameSize was being read.
var ErrFrameTooLarge = errors.New("frame too large")

// FrameHandlerFunc handles parsed frame header and its body represented by
// io.Reader.
//
// Note that reader represents already unmasked body.
type FrameHandlerFunc func(ws.Header, io.Reader) error

// Reader is a wrapper around source io.Reader which represents WebSocket
// connection. It contains options for reading messages from source.
//
// Reader implements io.Reader, which Read() method reads payload of incoming
// WebSocket frames. It also takes care on fragmented frames and possibly
// intermediate control frames between them.
//
// Note that Reader's methods are not goroutine safe.
type Reader struct {
	Source io.Reader
	State  ws.State

	// SkipHeaderCheck disables checking header bits to be RFC6455 compliant.
	SkipHeaderCheck bool

	// CheckUTF8 enables UTF-8 checks for text frames payload. If incoming
	// bytes are not valid UTF-8 sequence, ErrInvalidUTF8 returned.
	CheckUTF8 bool

	// Extensions is a list of negotiated extensions for reader Source.
	// It is used to meet the specs and clear appropriate bits in fragment
	// header RSV segment.
	Extensions []RecvExtension

	// MaxFrameSize controls the maximum frame size in bytes
	// that can be read. A message exceeding that size will return
	// a ErrFrameTooLarge to the application.
	//
	// Not setting this field means there is no limit.
	MaxFrameSize int64

	OnContinuation FrameHandlerFunc
	OnIntermediate FrameHandlerFunc

	opCode ws.OpCode        // Used to store message op code on fragmentation.
	frame  io.Reader        // Used to as frame reader.
	raw    io.LimitedReader // Used to discard frames without cipher.
	utf8   UTF8Reader       // Used to check UTF8 sequences if CheckUTF8 is true.
}

// NewReader creates new frame reader that reads from r keeping given state to
// make some protocol validity checks when it needed.
func ( io.Reader,  ws.State) *Reader {
	return &Reader{
		Source: ,
		State:  ,
	}
}

// NewClientSideReader is a helper function that calls NewReader with r and
// ws.StateClientSide.
func ( io.Reader) *Reader {
	return NewReader(, ws.StateClientSide)
}

// NewServerSideReader is a helper function that calls NewReader with r and
// ws.StateServerSide.
func ( io.Reader) *Reader {
	return NewReader(, ws.StateServerSide)
}

// Read implements io.Reader. It reads the next message payload into p.
// It takes care on fragmented messages.
//
// The error is io.EOF only if all of message bytes were read.
// If an io.EOF happens during reading some but not all the message bytes
// Read() returns io.ErrUnexpectedEOF.
//
// The error is ErrNoFrameAdvance if no NextFrame() call was made before
// reading next message bytes.
func ( *Reader) ( []byte) ( int,  error) {
	if .frame == nil {
		if !.fragmented() {
			// Every new Read() must be preceded by NextFrame() call.
			return 0, ErrNoFrameAdvance
		}
		// Read next continuation or intermediate control frame.
		,  := .NextFrame()
		if  != nil {
			return 0, 
		}
		if .frame == nil {
			// We handled intermediate control and now got nothing to read.
			return 0, nil
		}
	}

	,  = .frame.Read()
	if  != nil &&  != io.EOF {
		return , 
	}
	if  == nil && .raw.N != 0 {
		return , nil
	}

	// EOF condition (either err is io.EOF or r.raw.N is zero).
	switch {
	case .raw.N != 0:
		 = io.ErrUnexpectedEOF

	case .fragmented():
		 = nil
		.resetFragment()

	case .CheckUTF8 && !.utf8.Valid():
		// NOTE: check utf8 only when full message received, since partial
		// reads may be invalid.
		 = .utf8.Accepted()
		 = ErrInvalidUTF8

	default:
		.reset()
		 = io.EOF
	}

	return , 
}

// Discard discards current message unread bytes.
// It discards all frames of fragmented message.
func ( *Reader) () ( error) {
	for {
		_,  = io.Copy(ioutil.Discard, &.raw)
		if  != nil {
			break
		}
		if !.fragmented() {
			break
		}
		if _,  = .NextFrame();  != nil {
			break
		}
	}
	.reset()
	return 
}

// NextFrame prepares r to read next message. It returns received frame header
// and non-nil error on failure.
//
// Note that next NextFrame() call must be done after receiving or discarding
// all current message bytes.
func ( *Reader) () ( ws.Header,  error) {
	,  = ws.ReadHeader(.Source)
	if  == io.EOF && .fragmented() {
		// If we are in fragmented state EOF means that is was totally
		// unexpected.
		//
		// NOTE: This is necessary to prevent callers such that
		// ioutil.ReadAll to receive some amount of bytes without an error.
		// ReadAll() ignores an io.EOF error, thus caller may think that
		// whole message fetched, but actually only part of it.
		 = io.ErrUnexpectedEOF
	}
	if  == nil && !.SkipHeaderCheck {
		 = ws.CheckHeader(, .State)
	}
	if  != nil {
		return , 
	}

	if  := .MaxFrameSize;  > 0 && .Length >  {
		return , ErrFrameTooLarge
	}

	// Save raw reader to use it on discarding frame without ciphering and
	// other streaming checks.
	.raw = io.LimitedReader{
		R: .Source,
		N: .Length,
	}

	 := io.Reader(&.raw)
	if .Masked {
		 = NewCipherReader(, .Mask)
	}

	for ,  := range .Extensions {
		,  = .UnsetBits()
		if  != nil {
			return , 
		}
	}

	if .fragmented() {
		if .OpCode.IsControl() {
			if  := .OnIntermediate;  != nil {
				 = (, )
			}
			if  == nil {
				// Ensure that src is empty.
				_,  = io.Copy(ioutil.Discard, &.raw)
			}
			return , 
		}
	} else {
		.opCode = .OpCode
	}
	if .CheckUTF8 && (.OpCode == ws.OpText || (.fragmented() && .opCode == ws.OpText)) {
		.utf8.Source = 
		 = &.utf8
	}

	// Save reader with ciphering and other streaming checks.
	.frame = 

	if .OpCode == ws.OpContinuation {
		if  := .OnContinuation;  != nil {
			 = (, )
		}
	}

	if .Fin {
		.State = .State.Clear(ws.StateFragmented)
	} else {
		.State = .State.Set(ws.StateFragmented)
	}

	return , 
}

func ( *Reader) () bool {
	return .State.Fragmented()
}

func ( *Reader) () {
	.raw = io.LimitedReader{}
	.frame = nil
	// Reset source of the UTF8Reader, but not the state.
	.utf8.Source = nil
}

func ( *Reader) () {
	.raw = io.LimitedReader{}
	.frame = nil
	.utf8 = UTF8Reader{}
	.opCode = 0
}

// NextReader prepares next message read from r. It returns header that
// describes the message and io.Reader to read message's payload. It returns
// non-nil error when it is not possible to read message's initial frame.
//
// Note that next NextReader() on the same r should be done after reading all
// bytes from previously returned io.Reader. For more performant way to discard
// message use Reader and its Discard() method.
//
// Note that it will not handle any "intermediate" frames, that possibly could
// be received between text/binary continuation frames. That is, if peer sent
// text/binary frame with fin flag "false", then it could send ping frame, and
// eventually remaining part of text/binary frame with fin "true" – with
// NextReader() the ping frame will be dropped without any notice. To handle
// this rare, but possible situation (and if you do not know exactly which
// frames peer could send), you could use Reader with OnIntermediate field set.
func ( io.Reader,  ws.State) (ws.Header, io.Reader, error) {
	 := &Reader{
		Source: ,
		State:  ,
	}
	,  := .NextFrame()
	if  != nil {
		return , nil, 
	}
	return , , nil
}