package volume

/*
 #cgo CFLAGS: -x objective-c
 #cgo LDFLAGS: -framework CoreAudio
 #include <CoreAudio/CoreAudio.h>
*/
import "C"
import (
	"unsafe"
)

type OSStatus C.OSStatus

const (
	AudioHardwareNoError = C.kAudioHardwareNoError
)

type AudioObjectID uint32

func GetDefaultOutputDevice() (AudioObjectID, OSStatus) {
	properties := C.AudioObjectPropertyAddress{
		C.kAudioHardwarePropertyDefaultOutputDevice,
		C.kAudioObjectPropertyScopeGlobal,
		C.kAudioObjectPropertyElementMain,
	}

	var data C.AudioObjectID
	dataSize := C.UInt32(unsafe.Sizeof(data))

	result := C.AudioObjectGetPropertyData(
		C.kAudioObjectSystemObject,
		&properties,
		C.UInt32(0),
		unsafe.Pointer(nil),
		&dataSize,
		unsafe.Pointer(&data),
	)

	return AudioObjectID(data), OSStatus(result)
}

func GetVolume(objectID AudioObjectID) (float32, OSStatus) {

	properties := C.AudioObjectPropertyAddress{
		C.kAudioDevicePropertyVolumeScalar,
		C.kAudioDevicePropertyScopeOutput,
		0, //main channel
	}

	var data C.Float32
	dataSize := C.UInt32(unsafe.Sizeof(data))

	result := C.AudioObjectGetPropertyData(
		C.AudioObjectID(objectID),
		&properties,
		C.UInt32(0),
		unsafe.Pointer(nil),
		&dataSize,
		unsafe.Pointer(&data),
	)

	return float32(data), OSStatus(result)
}

func SetVolume(objectID AudioObjectID, volume float32) OSStatus {

	properties := C.AudioObjectPropertyAddress{
		C.kAudioDevicePropertyVolumeScalar,
		C.kAudioDevicePropertyScopeOutput,
		0, //main channel
	}

	data := C.Float32(volume)

	result := C.AudioObjectSetPropertyData(
		C.AudioObjectID(objectID),
		&properties,
		C.UInt32(0),
		unsafe.Pointer(nil),
		C.UInt32(unsafe.Sizeof(data)),
		unsafe.Pointer(&data),
	)

	return OSStatus(result)
}

func GetMute(objectID AudioObjectID) (bool, OSStatus) {

	properties := C.AudioObjectPropertyAddress{
		C.kAudioDevicePropertyMute,
		C.kAudioDevicePropertyScopeOutput,
		0, //main channel
	}

	var data C.UInt32
	dataSize := C.UInt32(unsafe.Sizeof(data))

	result := C.AudioObjectGetPropertyData(
		C.AudioObjectID(objectID),
		&properties,
		C.UInt32(0),
		unsafe.Pointer(nil),
		&dataSize,
		unsafe.Pointer(&data),
	)

	dataAsBool := uint32(data) != 0
	return dataAsBool, OSStatus(result)
}

func SetMute(objectID AudioObjectID, mute bool) OSStatus {

	properties := C.AudioObjectPropertyAddress{
		C.kAudioDevicePropertyMute,
		C.kAudioDevicePropertyScopeOutput,
		0, //main channel
	}

	data := C.UInt32(0)
	if mute {
		data = C.UInt32(1)
	}

	result := C.AudioObjectSetPropertyData(
		C.AudioObjectID(objectID),
		&properties,
		C.UInt32(0),
		unsafe.Pointer(nil),
		C.UInt32(unsafe.Sizeof(data)),
		unsafe.Pointer(&data),
	)
	return OSStatus(result)
}
