package udpmux

import (
	
	
	
	

	pool 
)

type packet struct {
	buf  []byte
	addr net.Addr
}

var _ net.PacketConn = &muxedConnection{}

const queueLen = 128

// muxedConnection provides a net.PacketConn abstraction
// over packetQueue and adds the ability to store addresses
// from which this connection (indexed by ufrag) received
// data.
type muxedConnection struct {
	ctx    context.Context
	cancel context.CancelFunc
	queue  chan packet
	mux    *UDPMux
	ufrag  string
}

var _ net.PacketConn = &muxedConnection{}

func newMuxedConnection( *UDPMux,  string) *muxedConnection {
	,  := context.WithCancel(.ctx)
	return &muxedConnection{
		ctx:    ,
		cancel: ,
		queue:  make(chan packet, queueLen),
		mux:    ,
		ufrag:  ,
	}
}

func ( *muxedConnection) ( []byte,  net.Addr) error {
	if .ctx.Err() != nil {
		return errors.New("closed")
	}
	select {
	case .queue <- packet{buf: , addr: }:
		return nil
	default:
		return errors.New("queue full")
	}
}

func ( *muxedConnection) ( []byte) (int, net.Addr, error) {
	select {
	case  := <-.queue:
		 := copy(, .buf) // This might discard parts of the packet, if p is too short
		if  < len(.buf) {
			log.Debugf("short read, had %d, read %d", len(.buf), )
		}
		pool.Put(.buf)
		return , .addr, nil
	case <-.ctx.Done():
		return 0, nil, .ctx.Err()
	}
}

func ( *muxedConnection) ( []byte,  net.Addr) ( int,  error) {
	return .mux.writeTo(, )
}

func ( *muxedConnection) () error {
	if .ctx.Err() != nil {
		return nil
	}
	// mux calls close to actually close the connection
	//
	// Removing the connection from the mux or closing the connection
	// must trigger the other.
	// Doing this here ensures we don't need to call both RemoveConnByUfrag
	// and close on all code paths.
	.mux.RemoveConnByUfrag(.ufrag)
	return nil
}

// closes the connection. Must only be called by the mux.
func ( *muxedConnection) () {
	.cancel()
	// drain the packet queue
	for {
		select {
		case  := <-.queue:
			pool.Put(.buf)
		default:
			return
		}
	}
}

func ( *muxedConnection) () net.Addr { return .mux.socket.LocalAddr() }

func (*muxedConnection) ( time.Time) error {
	// no deadline is desired here
	return nil
}

func (*muxedConnection) ( time.Time) error {
	// no read deadline is desired here
	return nil
}

func (*muxedConnection) ( time.Time) error {
	// no write deadline is desired here
	return nil
}