package nori

import (
	"encoding/binary"
	"io"
)

type Frame struct {
	Duration        uint32
	PlaneCount      uint32
	Planes          []*Plane
	CoordinateCount uint32
	Coordinates     [][2]uint32
	Unknown1        string
	SoundEffect     string
	Unknown2        string
	HasCamp         bool
	Camp            struct {
		Params [7]uint32
		Array  []byte
		Extra  string
	}

	Version int
}

func NewFrame(version int) *Frame {
	return &Frame{Version: version}
}

func (f *Frame) Decode(rd io.Reader) error {
	if err := binary.Read(rd, end, &f.Duration); err != nil {
		return err
	}
	if err := binary.Read(rd, end, &f.PlaneCount); err != nil {
		return err
	}
	f.Planes = make([]*Plane, int(f.PlaneCount))
	for i := range f.Planes {
		f.Planes[i] = &Plane{}
		if err := f.Planes[i].Decode(rd); err != nil {
			return err
		}
	}
	if f.Version != 300 {
		if err := binary.Read(rd, end, &f.CoordinateCount); err != nil {
			return err
		}
		f.Coordinates = make([][2]uint32, f.CoordinateCount)
		for i := range f.Coordinates {
			if err := binary.Read(rd, end, f.Coordinates[i][:]); err != nil {
				return err
			}
		}
	}
	switch f.Version {
	case 300, 301:
		if err := discardN(rd, 144); err != nil {
			return err
		}
	case 302, 303:
		if err := discardN(rd, 96); err != nil {
			return err
		}
	}
	if f.Version >= 302 {
		// entry blocks
		if err := discardN(rd, 28*6); err != nil {
			return err
		}
	}
	// unknown1
	if err := discardN(rd, 44); err != nil {
		return err
	}
	//sound_effect
	if err := discardN(rd, 18); err != nil {
		return err
	}
	// unknown2
	if err := discardN(rd, 18); err != nil {
		return err
	}
	if f.Version >= 303 {
		var cast uint32
		if err := binary.Read(rd, end, &cast); err != nil {
			return err
		}
		// camp
		f.HasCamp = cast > 0
		if f.HasCamp {
			if err := binary.Read(rd, end, f.Camp.Params[:]); err != nil {
				return err
			}
			sz := int(f.Camp.Params[1]) * int(f.Camp.Params[2])
			f.Camp.Array = make([]byte, sz)
			if _, err := io.ReadFull(rd, f.Camp.Array); err != nil {
				return err
			}
			if err := discardN(rd, 20); err != nil {
				return err
			}
		}
	}

	return nil
}
