package nori

import (
	"bufio"
	"encoding/binary"
	"io"
)

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

type Plane struct {
	BitmapId   uint32
	PlaneX     int32
	PlaneY     int32
	Opacity    uint32
	Blend      BlendMode
	FlagParam  uint32
	RenderFlag uint32
}
type Animation struct {
	Title [32]byte

	// std::vector<uint32> frame_offsets
	FrameCount uint32
	Frames     []*Frame
}

func (a *Animation) Decode(rd *bufio.Reader, version int) error {
	if err := binary.Read(rd, end, a.Title[:]); err != nil {
		return err
	}
	if err := binary.Read(rd, end, &a.FrameCount); err != nil {
		return err
	}
	if _, err := rd.Discard(4 * int(a.FrameCount)); err != nil {
		return err
	}
	a.Frames = make([]*Frame, int(a.FrameCount))
	for i := range a.Frames {
		cf := &Frame{}
		a.Frames[i] = cf
		if err := binary.Read(rd, end, &cf.Duration); err != nil {
			return err
		}
		if err := binary.Read(rd, end, &cf.PlaneCount); err != nil {
			return err
		}
		cf.Planes = make([]*Plane, int(cf.PlaneCount))
		for i := range cf.Planes {
			cp := &Plane{}
			cf.Planes[i] = cp
			if err := binary.Read(rd, end, &cp.BitmapId); err != nil {
				return err
			}
			if err := binary.Read(rd, end, &cp.PlaneX); err != nil {
				return err
			}
			if err := binary.Read(rd, end, &cp.PlaneY); err != nil {
				return err
			}
			if err := binary.Read(rd, end, &cp.Opacity); err != nil {
				return err
			}
			if err := binary.Read(rd, end, &cp.RenderFlag); err != nil {
				return err
			}
			if err := binary.Read(rd, end, &cp.Blend); err != nil {
				return err
			}
			if err := binary.Read(rd, end, &cp.FlagParam); err != nil {
				return err
			}
		}
		if version != 300 {
			if err := binary.Read(rd, end, &cf.CoordinateCount); err != nil {
				return err
			}
			cf.Coordinates = make([][2]uint32, cf.CoordinateCount)
			for i := range cf.Coordinates {
				if err := binary.Read(rd, end, &cf.Coordinates[i][0]); err != nil {
					return err
				}
				if err := binary.Read(rd, end, &cf.Coordinates[i][1]); err != nil {
					return err
				}
			}
		}
		switch version {
		case 300, 301:
			if _, err := rd.Discard(144); err != nil {
				return err
			}
		case 302, 303:
			if _, err := rd.Discard(96); err != nil {
				return err
			}
		}
		if version >= 302 {
			// entry blocks
			if _, err := rd.Discard(28 * 6); err != nil {
				return err
			}
		}
		// unknown1
		if _, err := rd.Discard(44); err != nil {
			return err
		}
		//sound_effect
		if _, err := rd.Discard(18); err != nil {
			return err
		}
		// unknown2
		if _, err := rd.Discard(18); err != nil {
			return err
		}
		var cast uint32
		if err := binary.Read(rd, end, &cast); err != nil {
			return err
		}
		if version >= 303 && (cast > 0) {
			cf.Camp = CampSection{}
			if err := binary.Read(rd, end, cf.Camp.Params[:]); err != nil {
				return err
			}
			sz := int(cf.Camp.Params[1]) * int(cf.Camp.Params[2])
			cf.Camp.Array = make([]byte, sz)
			if _, err := io.ReadFull(rd, cf.Camp.Array); err != nil {
				return err
			}
			if _, err := rd.Discard(20); err != nil {
				return err
			}
		}
	}
	return nil
}
