package data

import (
	"errors"
	"io"
	"strconv"
	"strings"

	"code.ur.gs/lupine/ordoor/internal/util/asciiscan"
)

type Cell struct {
	X int // FIXME: This is just a guess, but I think it's a 3D coordinate system
	Y int
	Z int
}

type AnimatedObject struct {
	CentreCell     Cell
	Direction      int
	Type           int
	AnimationID    int
	AnimationGroup int
	AnimatedType   int
	AnimationIDs   CompassPoints // 8 of these, down to MoveBits. Compass points?
	InCells        CompassPoints
	VisualBits     CompassPoints
	MoveBits       CompassPoints
	Visibility     int
	Protection     int
	MinDelay       int // in milliseconds
	DelayRange     int // in milliseconds
}

func LoadAnimatedObjectDefinitions(filename string) ([]AnimatedObject, error) {
	var out []AnimatedObject

	s, err := asciiscan.New(filename)
	if err != nil {
		return nil, err
	}

	defer s.Close()

	for {
		obj, err := consumeAnimatedObjectDefinition(s)
		if err == io.EOF {
			return out, nil
		} else if err != nil {
			return nil, err
		}

		out = append(out, obj)
	}
}

func consumeAnimatedObjectDefinition(scanner *asciiscan.Scanner) (AnimatedObject, error) {
	var out AnimatedObject
	var err error

	out.CentreCell, err = consumeCell(scanner)
	if err != nil {
		return out, err
	}

	if err := scanner.ConsumeIntPtrs(
		&out.Direction, &out.Type, &out.AnimationID, &out.AnimationGroup, &out.AnimatedType,
	); err != nil {
		return out, err
	}

	// 8-int arrays
	out.AnimationIDs, err = consumeCompassPoints(scanner)
	if err != nil {
		return out, err
	}

	out.InCells, err = consumeCompassPoints(scanner)
	if err != nil {
		return out, err
	}

	out.VisualBits, err = consumeCompassPoints(scanner)
	if err != nil {
		return out, err
	}

	out.MoveBits, err = consumeCompassPoints(scanner)
	if err != nil {
		return out, err
	}

	if err := scanner.ConsumeIntPtrs(
		&out.Visibility, &out.Protection, &out.MinDelay, &out.DelayRange,
	); err != nil {
		return out, err
	}

	return out, nil
}

func consumeCell(scanner *asciiscan.Scanner) (Cell, error) {
	out := Cell{}
	str, err := scanner.ConsumeString()
	if err != nil {
		return out, err
	}

	parts := strings.Split(str, " ")
	if len(parts) != 3 {
		return out, errors.New("Malformed cell definition")
	}

	if out.X, err = strconv.Atoi(parts[0]); err != nil {
		return out, err
	}

	if out.Y, err = strconv.Atoi(parts[1]); err != nil {
		return out, err
	}

	if out.Z, err = strconv.Atoi(parts[2]); err != nil {
		return out, err
	}

	return out, nil
}
