package uevent

import (
	"strconv"
	"syscall"
)

// KobjectAction represents enum kobject_action found in include/linux/kobject.h
// and their corresponding string representations in lib/kobject_uevent.c.
type KobjectAction uint32

// include/linux/kobject.h
const (
	KOBJ_ADD KobjectAction = iota
	KOBJ_REMOVE
	KOBJ_CHANGE
	KOBJ_MOVE
	KOBJ_ONLINE
	KOBJ_OFFLINE
	KOBJ_BIND
	KOBJ_UNBIND
)

// lib/kobject_uevent.c
var kobject_actions = [...]string{
	KOBJ_ADD:     "add",
	KOBJ_REMOVE:  "remove",
	KOBJ_CHANGE:  "change",
	KOBJ_MOVE:    "move",
	KOBJ_ONLINE:  "online",
	KOBJ_OFFLINE: "offline",
	KOBJ_BIND:    "bind",
	KOBJ_UNBIND:  "unbind",
}

// Valid returns whether the value of act is defined.
func (act KobjectAction) Valid() bool { return int(act) < len(kobject_actions) }

// String returns the corresponding string sent over netlink.
func (act KobjectAction) String() string {
	if !act.Valid() {
		return "unsupported kobject_action " + strconv.Itoa(int(act))
	}
	return kobject_actions[act]
}

func (act KobjectAction) AppendText(b []byte) ([]byte, error) {
	if !act.Valid() {
		return b, syscall.EINVAL
	}
	return append(b, act.String()...), nil
}

func (act KobjectAction) MarshalText() ([]byte, error) {
	return act.AppendText(nil)
}

// An UnsupportedActionError describes a string representation of [KobjectAction]
// not yet supported by this package.
type UnsupportedActionError string

var _ Recoverable = UnsupportedActionError("")

func (UnsupportedActionError) recoverable() {}
func (e UnsupportedActionError) Error() string {
	return "unsupported kobject_action " + strconv.Quote(string(e))
}

func (act *KobjectAction) UnmarshalText(data []byte) error {
	for v, s := range kobject_actions {
		if string(data) == s {
			*act = KobjectAction(v)
			return nil
		}
	}
	return UnsupportedActionError(data)
}
