/*
NAME
  pes.go -
DESCRIPTION
  See Readme.md

AUTHOR
  Saxon A. Nelson-Milton <saxon.milton@gmail.com>

LICENSE
  pes.go is Copyright (C) 2017 the Australian Ocean Lab (AusOcean)

  It is free software: you can redistribute it and/or modify them
  under the terms of the GNU General Public License as published by the
  Free Software Foundation, either version 3 of the License, or (at your
  option) any later version.

  It is distributed in the hope that it will be useful, but WITHOUT
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 for more details.

  You should have received a copy of the GNU General Public License
  along with revid in gpl.txt.  If not, see http://www.gnu.org/licenses.
*/

package pes

const MaxPesSize = 10000

/*
The below data struct encapsulates the fields of an PES packet. Below is
the formatting of a PES packet for reference!

													PES Packet Formatting
============================================================================
| octet no | bit 0 | bit 1 | bit 2 | bit 3 | bit 4 | bit 5 | bit 6 | bit 7 |
============================================================================
| octet 0  | 0x00                                                          |
----------------------------------------------------------------------------
| octet 1  | 0x00                                                          |
----------------------------------------------------------------------------
| octet 2  | 0x01                                                          |
----------------------------------------------------------------------------
| octet 3  | Stream ID (0xE0 for video)                                    |
----------------------------------------------------------------------------
| octet 4  | PES Packet Length (no of bytes in packet after this field)    |
----------------------------------------------------------------------------
| octet 5  | PES Length cont.                                              |
----------------------------------------------------------------------------
| octet 6  | 0x2           |  SC           | Prior | DAI   | Copyr | Copy  |
----------------------------------------------------------------------------
| octet 7  | PDI           | ESCRF | ESRF  | DSMTMF| ACIF  | CRCF  | EF    |
----------------------------------------------------------------------------
| octet 8  | PES Header Length                                             |
----------------------------------------------------------------------------
| optional | optional fields (determined by flags above) (variable Length) |
----------------------------------------------------------------------------
| -        | ...                                                           |
----------------------------------------------------------------------------
| optional | stuffing bytes (varible length)                               |
----------------------------------------------------------------------------
| -        | ...                                                           |
----------------------------------------------------------------------------
| Optional | Data (variable length)                                        |
----------------------------------------------------------------------------
| -        | ...                                                           |
----------------------------------------------------------------------------
*/
// TODO: add DSMTM, ACI, CRC, Ext fields
type Packet struct {
	StreamID     byte   // Type of stream
	Length       uint16 // Pes packet length in bytes after this field
	SC           byte   // Scrambling control
	Priority     bool   // Priority Indicator
	DAI          bool   // Data alginment indicator
	Copyright    bool   // Copyright indicator
	Original     bool   // Original data indicator
	PDI          byte   // PTS DTS indicator
	ESCRF        bool   // Elementary stream clock reference flag
	ESRF         bool   // Elementary stream rate reference flag
	DSMTMF       bool   // Dsm trick mode flag
	ACIF         bool   // Additional copy info flag
	CRCF         bool   // Not sure
	EF           bool   // Extension flag
	HeaderLength byte   // Pes header length
	PTS          uint64 // Presentation time stamp
	DTS          uint64 // Decoding timestamp
	ESCR         uint64 // Elementary stream clock reference
	ESR          uint32 // Elementary stream rate reference
	Stuff        []byte // Stuffing bytes
	Data         []byte // Pes packet data
}

func (p *Packet) Bytes(buf []byte) []byte {
	if buf == nil || cap(buf) != MaxPesSize {
		buf = make([]byte, 0, MaxPesSize)
	}
	buf = buf[:0]
	buf = append(buf, []byte{
		0x00, 0x00, 0x01,
		p.StreamID,
		byte((p.Length & 0xFF00) >> 8),
		byte(p.Length & 0x00FF),
		(0x2<<6 | p.SC<<4 | boolByte(p.Priority)<<3 | boolByte(p.DAI)<<2 |
			boolByte(p.Copyright)<<1 | boolByte(p.Original)),
		(p.PDI<<6 | boolByte(p.ESCRF)<<5 | boolByte(p.ESRF)<<4 | boolByte(p.DSMTMF)<<3 |
			boolByte(p.ACIF)<<2 | boolByte(p.CRCF)<<1 | boolByte(p.EF)),
		p.HeaderLength,
	}...)
	if p.PDI == byte(2) {
		pts := 0x2100010001 | (p.PTS&0x1C0000000)<<3 | (p.PTS&0x3FFF8000)<<2 |
			(p.PTS&0x7FFF)<<1
		buf = append(buf, []byte{
			byte((pts & 0xFF00000000) >> 32),
			byte((pts & 0x00FF000000) >> 24),
			byte((pts & 0x0000FF0000) >> 16),
			byte((pts & 0x000000FF00) >> 8),
			byte(pts & 0x00000000FF),
		}...)
	}
	buf = append(buf, append(p.Stuff, p.Data...)...)
	return buf
}

func boolByte(b bool) byte {
	if b {
		return 1
	}
	return 0
}