package h264dec

import (
	"math"

	"bitbucket.org/ausocean/av/codec/h264/h264dec/bits"
)

// import "strings"

// Specification Page 46 7.3.2.2

type PPS struct {
	ID, SPSID                         int
	EntropyCodingMode                 int
	BottomFieldPicOrderInFramePresent bool
	NumSliceGroupsMinus1              int
	SliceGroupMapType                 int
	RunLengthMinus1                   []int
	TopLeft                           []int
	BottomRight                       []int
	SliceGroupChangeDirection         bool
	SliceGroupChangeRateMinus1        int
	PicSizeInMapUnitsMinus1           int
	SliceGroupId                      []int
	NumRefIdxL0DefaultActiveMinus1    int
	NumRefIdxL1DefaultActiveMinus1    int
	WeightedPred                      bool
	WeightedBipred                    int
	PicInitQpMinus26                  int
	PicInitQsMinus26                  int
	ChromaQpIndexOffset               int
	DeblockingFilterControlPresent    bool
	ConstrainedIntraPred              bool
	RedundantPicCntPresent            bool
	Transform8x8Mode                  int
	PicScalingMatrixPresent           bool
	PicScalingListPresent             []bool
	SecondChromaQpIndexOffset         int
}

func NewPPS(br *bits.BitReader, chromaFormat int) (*PPS, error) {
	pps := PPS{}
	r := newFieldReader(br)

	pps.ID = int(r.readUe())
	pps.SPSID = int(r.readUe())
	pps.EntropyCodingMode = int(r.readBits(1))
	pps.BottomFieldPicOrderInFramePresent = r.readBits(1) == 1
	pps.NumSliceGroupsMinus1 = int(r.readUe())

	if pps.NumSliceGroupsMinus1 > 0 {
		pps.SliceGroupMapType = int(r.readUe())

		if pps.SliceGroupMapType == 0 {
			for iGroup := 0; iGroup <= pps.NumSliceGroupsMinus1; iGroup++ {
				pps.RunLengthMinus1 = append(pps.RunLengthMinus1, int(r.readUe()))
			}
		} else if pps.SliceGroupMapType == 2 {
			for iGroup := 0; iGroup < pps.NumSliceGroupsMinus1; iGroup++ {
				pps.TopLeft[iGroup] = int(r.readUe())
				pps.BottomRight[iGroup] = int(r.readUe())
			}
		} else if pps.SliceGroupMapType > 2 && pps.SliceGroupMapType < 6 {
			pps.SliceGroupChangeDirection = r.readBits(1) == 1
			pps.SliceGroupChangeRateMinus1 = int(r.readUe())
		} else if pps.SliceGroupMapType == 6 {
			pps.PicSizeInMapUnitsMinus1 = int(r.readUe())

			for i := 0; i <= pps.PicSizeInMapUnitsMinus1; i++ {
				pps.SliceGroupId[i] = int(r.readBits(int(math.Ceil(math.Log2(float64(pps.NumSliceGroupsMinus1 + 1))))))
			}
		}

	}
	pps.NumRefIdxL0DefaultActiveMinus1 = int(r.readUe())
	pps.NumRefIdxL1DefaultActiveMinus1 = int(r.readUe())
	pps.WeightedPred = r.readBits(1) == 1
	pps.WeightedBipred = int(r.readBits(2))
	pps.PicInitQpMinus26 = int(r.readSe())
	pps.PicInitQsMinus26 = int(r.readSe())
	pps.ChromaQpIndexOffset = int(r.readSe())
	pps.DeblockingFilterControlPresent = r.readBits(1) == 1
	pps.ConstrainedIntraPred = r.readBits(1) == 1
	pps.RedundantPicCntPresent = r.readBits(1) == 1

	logger.Printf("debug: \tChecking for more PPS data")
	if moreRBSPData(br) {
		logger.Printf("debug: \tProcessing additional PPS data")
		pps.Transform8x8Mode = int(r.readBits(1))
		pps.PicScalingMatrixPresent = r.readBits(1) == 1

		if pps.PicScalingMatrixPresent {
			v := 6
			if chromaFormat != chroma444 {
				v = 2
			}
			for i := 0; i < 6+(v*pps.Transform8x8Mode); i++ {
				pps.PicScalingListPresent[i] = r.readBits(1) == 1
				if pps.PicScalingListPresent[i] {
					if i < 6 {
						scalingList(
							br,
							ScalingList4x4[i],
							16,
							DefaultScalingMatrix4x4[i])

					} else {
						scalingList(
							br,
							ScalingList8x8[i],
							64,
							DefaultScalingMatrix8x8[i-6])

					}
				}
			}
		}
		pps.SecondChromaQpIndexOffset = r.readSe()
		moreRBSPData(br)
		// rbspTrailingBits()
	}
	return &pps, nil
}