// Copyright 2024 Martin Riedl
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gomp4

import "encoding/binary"

// TrackFragmentHeaderBox Track Fragment Header
//
// 8.8.7 Track Fragment Header Box
// Box Type: ‘tfhd’
// Container: Track Fragment Box ('traf')
// Mandatory: Yes
// Quantity: Exactly one
//
// Each movie fragment can add zero or more fragments to each track; and a track fragment can add zero
// or more contiguous runs of samples. The track fragment header sets up information and defaults used
// for those runs of samples.
//
// The base‐data‐offset, if explicitly provided, is a data offset that is identical to a chunk offset in the Chunk
// Offset Box, i.e. applying to the complete file (e.g. starting with a file‐type box and movie box). In
// circumstances when the complete file does not exist or its size is unknown, it may be impossible to use
// an explicit base‐data‐offset; then, offsets need to be established relative to the movie fragment.
type TrackFragmentHeaderBox struct {
	*FullBox
	TrackID uint32
	// the base offset to use when calculating data offsets
	BaseDataOffset         uint64
	SampleDescriptionIndex uint32
	DefaultSampleDuration  uint32
	DefaultSampleSize      uint32
	DefaultSampleFlags     uint32
}

// BoxTypeTrackFragmentHeader Track Fragment Header
const BoxTypeTrackFragmentHeader = "tfhd"

func init() {
	BoxDefinitions = append(BoxDefinitions, BoxDefinition{
		Type:        BoxTypeTrackFragmentHeader,
		ParentTypes: []string{BoxTypeTrackFragment},
		Parser:      ParseTrackFragmentHeaderBox,
	})
}

const (
	// TrackFragmentHeaderBoxFlagBaseDataOffsetPresent Base Offset Present Flag
	//
	// indicates the presence of the base‐data‐offset field. This
	// provides an explicit anchor for the data offsets in each track run (see below). If not provided and
	// if the default‐base‐is‐moof flag is not set, the base‐data‐offset for the first track in the movie
	// fragment is the position of the first byte of the enclosing Movie Fragment Box, and for second
	// and subsequent track fragments, the default is the end of the data defined by the preceding
	// track fragment. Fragments 'inheriting' their offset in this way must all use the same data‐
	// reference (i.e., the data for these tracks must be in the same file)
	TrackFragmentHeaderBoxFlagBaseDataOffsetPresent uint32 = 0x00000001

	// TrackFragmentHeaderBoxFlagSampleDescriptionIndexPresent Sample Description Index Present Flag
	//
	// indicates the presence of this field, which over‐rides,
	// in this fragment, the default set up in the Track Extends Box.
	TrackFragmentHeaderBoxFlagSampleDescriptionIndexPresent uint32 = 0x00000002

	// TrackFragmentHeaderBoxFlagDefaultSampleDurationPresent Default Sample Duration Present Flag
	TrackFragmentHeaderBoxFlagDefaultSampleDurationPresent uint32 = 0x00000008

	// TrackFragmentHeaderBoxFlagDefaultSampleSize Default Sample Size Present Flag
	TrackFragmentHeaderBoxFlagDefaultSampleSize uint32 = 0x00000010

	// TrackFragmentHeaderBoxFlagDefaultSampleFlags Default Sample Flags Present Flag
	TrackFragmentHeaderBoxFlagDefaultSampleFlags uint32 = 0x00000020

	// TODO: define other flags
)

// ParseTrackFragmentHeaderBox creates a new track fragment header box struct
func ParseTrackFragmentHeaderBox(parser *Parser, filePosition uint64, headerSize uint32, content []byte) (any, error) {
	box := &TrackFragmentHeaderBox{FullBox: newFullBox(&Box{filePosition, headerSize}, content[0:4])}
	position := 4

	// parse track ID
	box.TrackID = binary.BigEndian.Uint32(content[position : position+4])
	position += 4

	// TODO: check other flags

	return box, nil
}
