/*
RFC 3550.  RTP: A Transport Protocol for Real-Time Applications
*/
package icspacketparser

import (
	"encoding/binary"
	"fmt"

	"gitlab.com/cinnamon/voiceagent/icserror"
	"gitlab.com/cinnamon/voiceagent/icsnet"
)

type RTP struct {
	Version     int
	PayloadType PayloadType
	Seq         uint16
	Timestamp   uint32
	SSID        uint32
	PayloadLen  int
	Payload     []byte
	SrcAddr     *icsnet.IcsNetAddr
	DstAddr     *icsnet.IcsNetAddr
}

type RTPHeader struct {
	v    byte   //2bits
	m    byte   //1
	pt   byte   //7
	seq  []byte //16
	ts   []byte //4
	ssrc []byte //4
}
type PayloadType int

const RTPHeaderLen = 12

const (
	PCMU = 0
	PCMA = 8
	G729 = 18
)

func NewRTP() RTP {
	rtp := RTP{}
	return rtp
}

func (r *RTP) RTPParser(data []byte) *icserror.IcsError {
	datalen := len(data)
	if datalen <= RTPHeaderLen {
		return icserror.ICSERRRTPNo
	}

	//fmt.Println(data)

	r.PayloadLen = datalen - RTPHeaderLen
	//fmt.Println("Payload Len:", r.PayloadLen)

	header := RTPHeader{}

	//RTP version 2bit
	header.v = data[0] >> 6
	r.Version = int(header.v)
	if r.Version != 2 {
		return icserror.ICSERRRTPNo
	}
	//fmt.Println("Version", r.Version)

	//mark 1bit
	header.m = data[1] >> 7
	//fmt.Println("Mark", header.m)

	//payload type 7bit
	ptint := data[1]
	ptint = ptint << 1
	header.pt = ptint >> 1
	r.PayloadType = PayloadType(header.pt)
	//fmt.Println("PayloadType:", r.PayloadType)
	if r.PayloadType == 18 { //g729
		if datalen != 32 {
			return icserror.ICSERRRTPNo
		}
	}

	header.seq = make([]byte, 2)
	copy(header.seq, data[2:4])
	r.Seq = binary.BigEndian.Uint16(header.seq[0:])
	//fmt.Println("SEQ:", r.Seq)

	header.ts = make([]byte, 4)
	copy(header.ts, data[4:8])
	r.Timestamp = binary.BigEndian.Uint32(header.ts[0:])
	//fmt.Println("Timestamp:", r.Timestamp)

	header.ssrc = make([]byte, 4)
	copy(header.ssrc, data[8:12])
	r.SSID = binary.BigEndian.Uint32(header.ssrc[0:])
	//fmt.Println("SSID:", r.SSID)

	r.Payload = make([]byte, r.PayloadLen)
	copy(r.Payload, data[12:])
	//fmt.Println("Payload data:", r.Payload)

	return nil
}

//implm interface Packeter
func (r *RTP) GetPacketData(addr []*icsnet.IcsNetAddr, packet []byte) *icserror.IcsError {
	r.SrcAddr = addr[0]
	r.DstAddr = addr[1]
	//fmt.Println("RTP GetPacketData()", r.SrcAddr, r.DstAddr)

	if err := r.RTPParser(packet); err != nil {
		//err.Print()
		return err
	}

	return nil
}

func (r RTP) GetPayloadType() PayloadType {
	return r.PayloadType
}

func (r RTP) GetPayloadLen() int {
	return r.PayloadLen
}

func (r RTP) String() string {
	return fmt.Sprintf("ssrc: %d, seq: %d, ts: %d, pt: %d, payload len: %d", r.SSID, r.Seq, r.Timestamp, r.PayloadType, r.PayloadLen)
}