"use strict";

//
//  audioDeviceExample.js
//  examples
//
//  Created by Brad Hefta-Gaub on 3/22/14
//  Copyright 2013 High Fidelity, Inc.
//
//  This is an example script that demonstrates use of the Menu object
//
//  Distributed under the Apache License, Version 2.0.
//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//

(function() { // BEGIN LOCAL_SCOPE

const INPUT = "Input";
const OUTPUT = "Output";

//
// VAR DEFINITIONS
//
var debugPrintStatements = true;
const INPUT_DEVICE_SETTING = "audio_input_device";
const OUTPUT_DEVICE_SETTING = "audio_output_device";
var audioDevicesList = []; // placeholder for menu items
var wasHmdActive = false; // assume it's not active to start
var switchedAudioInputToHMD = false;
var switchedAudioOutputToHMD = false;
var previousSelectedInputAudioDevice = "";
var previousSelectedOutputAudioDevice = "";

var interfaceInputDevice = "";
var interfaceOutputDevice = "";

//
// BEGIN FUNCTION DEFINITIONS
//
function debug() {
    if (debugPrintStatements) {
        print.apply(null, [].concat.apply(["selectAudioDevice.js:"], [].map.call(arguments, JSON.stringify)));
    }
}


function setupAudioMenus() {
    // menu events can be triggered asynchronously; skip them for 200ms to avoid recursion and false switches
    removeAudioMenus();

    // Setup audio input devices
    Menu.addSeparator("Audio", "Input Audio Device");
    var currentInputDevice = AudioDevice.getInputDevice()
    for (var i = 0; i < AudioDevice.inputAudioDevices.length; i++) {
        var audioDeviceMenuString = "Use " + AudioDevice.inputAudioDevices[i] + " for Input";
        Menu.addMenuItem({
            menuName: "Audio",
            menuItemName: audioDeviceMenuString,
            isCheckable: true,
            isChecked: AudioDevice.inputAudioDevices[i] == currentInputDevice
        });
        audioDevicesList.push(audioDeviceMenuString);
    }

    // Setup audio output devices
    Menu.addSeparator("Audio", "Output Audio Device");
    var currentOutputDevice = AudioDevice.getOutputDevice()
    for (var i = 0; i < AudioDevice.outputAudioDevices.length; i++) {
        var audioDeviceMenuString = "Use " + AudioDevice.outputAudioDevices[i] + " for Output";
        Menu.addMenuItem({
            menuName: "Audio",
            menuItemName: audioDeviceMenuString,
            isCheckable: true,
            isChecked: AudioDevice.outputAudioDevices[i] == currentOutputDevice
        });
        audioDevicesList.push(audioDeviceMenuString);
    }
}

function removeAudioMenus() {
    Menu.removeSeparator("Audio", "Input Audio Device");
    Menu.removeSeparator("Audio", "Output Audio Device");

    for (var index = 0; index < audioDevicesList.length; index++) {
        if (Menu.menuItemExists("Audio", audioDevicesList[index])) {
            Menu.removeMenuItem("Audio", audioDevicesList[index]);
        }
    }

    Menu.removeMenu("Audio > Devices");

    audioDevicesList = [];
}

function onDevicechanged() {
    debug("System audio devices changed. Removing and replacing Audio Menus...");
    setupAudioMenus();
}

function onMenuEvent(audioDeviceMenuString) {
    if (Menu.isOptionChecked(audioDeviceMenuString) &&
            (audioDeviceMenuString !== interfaceInputDevice &&
             audioDeviceMenuString !== interfaceOutputDevice)) {
        AudioDevice.setDeviceFromMenu(audioDeviceMenuString)
    }
}

function onCurrentDeviceChanged() {
    debug("System audio device switched. ");
    interfaceInputDevice = "Use " + AudioDevice.getInputDevice() + " for Input";
    interfaceOutputDevice = "Use " + AudioDevice.getOutputDevice() + " for Output";
    for (var index = 0; index < audioDevicesList.length; index++) {
        if (audioDevicesList[index] === interfaceInputDevice ||
                audioDevicesList[index] === interfaceOutputDevice) {
            if (Menu.isOptionChecked(audioDevicesList[index]) === false)
                Menu.setIsOptionChecked(audioDevicesList[index], true);
        } else {
            if (Menu.isOptionChecked(audioDevicesList[index]) === true)
                Menu.setIsOptionChecked(audioDevicesList[index], false);
        }
    }
}

function restoreAudio() {
    if (switchedAudioInputToHMD) {
        debug("Switching back from HMD preferred audio input to: " + previousSelectedInputAudioDevice);
        AudioDevice.setInputDeviceAsync(previousSelectedInputAudioDevice)
        switchedAudioInputToHMD = false;
    }
    if (switchedAudioOutputToHMD) {
        debug("Switching back from HMD preferred audio output to: " + previousSelectedOutputAudioDevice);
        AudioDevice.setOutputDeviceAsync(previousSelectedOutputAudioDevice)
        switchedAudioOutputToHMD = false;
    }
}

// Some HMDs (like Oculus CV1) have a built in audio device. If they
// do, then this function will handle switching to that device automatically
// when you goActive with the HMD active.
function checkHMDAudio() {
    // HMD Active state is changing; handle switching
    if (HMD.active != wasHmdActive) {
        debug("HMD Active state changed!");

        // We're putting the HMD on; switch to those devices
        if (HMD.active) {
            debug("HMD is now Active.");
            var hmdPreferredAudioInput = HMD.preferredAudioInput();
            var hmdPreferredAudioOutput = HMD.preferredAudioOutput();
            debug("hmdPreferredAudioInput: " + hmdPreferredAudioInput);
            debug("hmdPreferredAudioOutput: " + hmdPreferredAudioOutput);

            if (hmdPreferredAudioInput !== "") {
                debug("HMD has preferred audio input device.");
                previousSelectedInputAudioDevice = Settings.getValue(INPUT_DEVICE_SETTING);
                debug("previousSelectedInputAudioDevice: " + previousSelectedInputAudioDevice);
                if (hmdPreferredAudioInput != previousSelectedInputAudioDevice) {
                    switchedAudioInputToHMD = true;
                    AudioDevice.setInputDeviceAsync(hmdPreferredAudioInput)
                }
            }
            if (hmdPreferredAudioOutput !== "") {
                debug("HMD has preferred audio output device.");
                previousSelectedOutputAudioDevice = Settings.getValue(OUTPUT_DEVICE_SETTING);
                debug("previousSelectedOutputAudioDevice: " + previousSelectedOutputAudioDevice);
                if (hmdPreferredAudioOutput != previousSelectedOutputAudioDevice) {
                    switchedAudioOutputToHMD = true;
                    AudioDevice.setOutputDeviceAsync(hmdPreferredAudioOutput)
                }
            }
        } else {
            debug("HMD no longer active. Restoring audio I/O devices...");
            restoreAudio();
        }
    }
    wasHmdActive = HMD.active;
}

//
// END FUNCTION DEFINITIONS
//

//
// BEGIN SCRIPT BODY
//
// Wait for the C++ systems to fire up before trying to do anything with audio devices
Script.setTimeout(function () {
    debug("Connecting deviceChanged(), displayModeChanged(), and switchAudioDevice()...");
    AudioDevice.deviceChanged.connect(onDevicechanged);
    AudioDevice.currentInputDeviceChanged.connect(onCurrentDeviceChanged);
    AudioDevice.currentOutputDeviceChanged.connect(onCurrentDeviceChanged);
    HMD.displayModeChanged.connect(checkHMDAudio);
    Menu.menuItemEvent.connect(onMenuEvent);
    debug("Setting up Audio I/O menu for the first time...");
    setupAudioMenus();
    debug("Checking HMD audio status...")
    checkHMDAudio();
}, 300);

debug("Connecting scriptEnding()");
Script.scriptEnding.connect(function () {
    restoreAudio();
    removeAudioMenus();
    Menu.menuItemEvent.disconnect(onMenuEvent);
    HMD.displayModeChanged.disconnect(checkHMDAudio);
    AudioDevice.currentInputDeviceChanged.disconnect(onCurrentDeviceChanged);
    AudioDevice.currentOutputDeviceChanged.disconnect(onCurrentDeviceChanged);
    AudioDevice.deviceChanged.disconnect(onDevicechanged);
});

//
// END SCRIPT BODY
//

}()); // END LOCAL_SCOPE