package volume

/*
 #cgo CFLAGS: -x objective-c
 #cgo LDFLAGS: -framework AppKit
 #import <AppKit/AppKit.h>
NSEvent* createEvent(int k, bool down) {
    int flags = down ? 0xa00 : 0xb00;
    NSEvent* event = [NSEvent otherEventWithType:NSEventTypeSystemDefined
                                        location:NSZeroPoint
                                   modifierFlags:flags
                                       timestamp:0
                                    windowNumber:0
                                         context:nil
                                         subtype:8
                                           data1:(k << 16 | flags)
                                           data2:-1
    ];
    return event;
}

void pressKey(int k) {
    @autoreleasepool {
        NSEvent* down = createEvent(k, true);
        NSEvent* up = createEvent(k, false);

        CGEventPost(kCGHIDEventTap, down.CGEvent);
        usleep(100);
        CGEventPost(kCGHIDEventTap, up.CGEvent);
        usleep(100);
    }
}
*/
import "C"
import (
	"errors"
	"fmt"
)

/*
osascript -e 'output volume of (get volume settings)'
osascript -e 'set volume output volume 50'
osascript -e 'output muted of (get volume settings)'
osascript -e 'set volume output muted true'
*/
type VolumeSettings struct {
	OutputVolume int
	OutputMuted  bool
}

func GetVolumeSettings() (*VolumeSettings, error) {
	device, result := GetDefaultOutputDevice()

	if result != AudioHardwareNoError {
		return nil, errors.New(fmt.Sprintf("Unable to get device: %d", result))
	}

	return getVolumeSettings(device)
}

func getVolumeSettings(device AudioObjectID) (*VolumeSettings, error) {

	volume, result := GetVolume(device)
	if result != AudioHardwareNoError {
		return nil, errors.New(fmt.Sprintf("Unable to get volume: %d", result))
	}

	muted, result := GetMute(device)
	if result != AudioHardwareNoError {
		return nil, errors.New(fmt.Sprintf("Unable to get mute: %d", result))
	}

	settings := VolumeSettings{
		int(volume * 100),
		muted,
	}

	return &settings, nil
}

func ChangeVolume(ticks int) (*VolumeSettings, error) {

	device, result := GetDefaultOutputDevice()

	if result != AudioHardwareNoError {
		return nil, errors.New(fmt.Sprintf("Unable to get device: %d", result))
	}

	volume, result := GetVolume(device)
	if result != AudioHardwareNoError {
		return nil, errors.New(fmt.Sprintf("Unable to get volume: %d", result))
	}

	volume = volume * 64     //convert from fractional volume to 64 steps that mac supports
	volume += float32(ticks) //add number of ticks
	volume = volume / 64     //convert back to fractional volume that mac supports

	SetVolume(device, volume)

	return getVolumeSettings(device)
}

func ToggleMute() (*VolumeSettings, error) {
	device, result := GetDefaultOutputDevice()

	if result != AudioHardwareNoError {
		return nil, errors.New(fmt.Sprintf("Unable to get device: %d", result))
	}

	muted, result := GetMute(device)
	if result != AudioHardwareNoError {
		return nil, errors.New(fmt.Sprintf("Unable to get volume: %d", result))
	}

	SetMute(device, !muted)

	return getVolumeSettings(device)
}

func ChangeVolumeWithKeyboard(ticks int) {
	key := volumeup

	if ticks < 0 {
		key = volumedown
		ticks = -1 * ticks
	}

	for x := 0; x < ticks; x++ {
		C.pressKey(C.int(key))
	}
}

func ToggleMuteWithKeyboard() {
	C.pressKey(C.int(mute))
}

const (
	volumeup   = 0
	volumedown = 1
	mute       = 7
)

/*
	Get volume in applescript
	out, err := exec.Command("osascript", "-e", "get volume settings").Output()

	if err != nil {
		return nil, err
	}

	split1 := strings.Split(string(out), ",")

	settings := VolumeSettings{}

	for _, sub := range split1 {

		if strings.HasPrefix(sub, "output volume:") {
			outputVolume, err := strconv.Atoi(strings.Split(sub, ":")[1])
			if err != nil {
				log.Fatal(err)
				continue
			}

			settings.OutputVolume = outputVolume

		} else if strings.HasPrefix(sub, "output muted:") {

			outputMuted, err := strconv.ParseBool(strings.Split(sub, ":")[1])
			if err != nil {
				log.Fatal(err)
				continue
			}

			settings.OutputMuted = outputMuted

		}
	}
*/

/*
	set volume in applescript

	//script := "set volume output muted (not output muted of (get volume settings))"
	settings, err := GetVolumeSettings()

	if err != nil {
		return nil, err
	}

	volume := float64(settings.OutputVolume) * 64 / 100
	volume += float64(ticks)
	newVolume := int(math.Round(volume * 100 / 64))

	if newVolume > 100 {
		newVolume = 100
	}
	if newVolume < 0 {
		newVolume = 0
	}

	settings.OutputVolume = newVolume

	script := fmt.Sprintf("set volume output volume %d", newVolume)

	return settings, exec.Command("osascript", "-e", script).Run()
*/

//script := "set volume output muted (not output muted of (get volume settings))"
//return exec.Command("osascript", "-e", "set volume output muted (not output muted of (get volume settings))").Run()

	//osascript -e "get volume settings"
	//output volume:81, input volume:50, alert volume:100, output muted:false
