/*
DESCRIPTION
  options.go provides option functions that can be provided to the MTS encoders
  constructor NewEncoder for encoder configuration. These options include media
  type, PSI insertion strategy and intended access unit rate.

AUTHOR
  Saxon Nelson-Milton <saxon@ausocean.org>

LICENSE
  Copyright (C) 2017-2020 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 mts

import (
	"errors"
	"time"
)

var (
	ErrUnsupportedMedia = errors.New("unsupported media type")
	ErrInvalidRate      = errors.New("invalid access unit rate")
)

// PacketBasedPSI is an option that can be passed to NewEncoder to select
// packet based PSI writing, i.e. PSI are written to the destination every
// sendCount packets.
func PacketBasedPSI(sendCount int) func(*Encoder) error {
	return func(e *Encoder) error {
		e.psiMethod = psiMethodPacket
		e.psiSendCount = sendCount
		e.pktCount = e.psiSendCount
		e.log.Debug("configured for packet based PSI insertion", "count", sendCount)
		return nil
	}
}

// TimeBasedPSI is another option that can be passed to NewEncoder to select
// time based PSI writing, i.e. PSI are written to the destination every dur
// (duration). The defualt is 2 seconds.
func TimeBasedPSI(dur time.Duration) func(*Encoder) error {
	return func(e *Encoder) error {
		e.psiMethod = psiMethodTime
		e.psiTime = 0
		e.psiSetTime = dur
		e.startTime = time.Now()
		e.log.Debug("configured for time based PSI insertion")
		return nil
	}
}

// MediaType is an option that can be passed to NewEncoder. It is used to
// specifiy the media type/codec of the data we are packetising using the
// encoder. Currently supported options are EncodeH264, EncodeH265, EncodeMJPEG
// and EncodeAudio.
func MediaType(mt int) func(*Encoder) error {
	return func(e *Encoder) error {
		switch mt {
		case EncodeAudio:
			e.mediaPID = PIDAudio
			e.streamID = streamIDAudio
			e.log.Debug("configured for audio packetisation")
		case EncodeH265:
			e.mediaPID = PIDVideo
			e.streamID = streamIDH265
			e.log.Debug("configured for h.265 packetisation")
		case EncodeH264:
			e.mediaPID = PIDVideo
			e.streamID = streamIDH264
			e.log.Debug("configured for h.264 packetisation")
		case EncodeMJPEG:
			e.mediaPID = PIDVideo
			e.streamID = streamIDMJPEG
			e.log.Debug("configured for MJPEG packetisation")
		default:
			return ErrUnsupportedMedia
		}
		e.continuity = map[uint16]byte{PatPid: 0, PmtPid: 0, e.mediaPID: 0}
		return nil
	}
}

// Rate is an option that can be passed to NewEncoder. It is used to specifiy
// the rate at which the access units should be played in playback. This will
// be used to create timestamps and counts such as PTS and PCR.
func Rate(r int) func(*Encoder) error {
	return func(e *Encoder) error {
		if r < 1 || r > 60 {
			return ErrInvalidRate
		}
		e.writePeriod = time.Duration(float64(time.Second) / float64(r))
		return nil
	}
}