package eu.midnightdust.yaytris.util.sound;

import eu.midnightdust.yaytris.Settings;

import javax.sound.sampled.*;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

public class SoundUtil {
    private static final Map<String, MusicThread> musicThreads = new HashMap<>();

    /**
     * Play the long audio file found at the specified location.
     *
     * @param fileLocation  the URI of the desired audio file (should be a .wav file)
     * @param looped        whether to repeat the song indefinitely after it finishes
     */
    public static void playMusic(String fileLocation, boolean looped) {
        if (musicThreads.containsKey(fileLocation)) stopMusic(fileLocation);
        MusicThread musicThread = new MusicThread(fileLocation, looped);
        musicThread.start();
        musicThreads.put(fileLocation, musicThread);
    }

    /**
     * Stop the long audio file found at the specified location, if it is playing.
     * Also has a nice smooth fade-out effect.
     *
     * @param fileLocation  the URI of the desired audio file (should be a .wav file)
     */
    public static void stopMusic(String fileLocation) {
        if (musicThreads.containsKey(fileLocation)) musicThreads.get(fileLocation).stopMusic();
    }

    /**
     * Play a short audio clip found at the specified location.
     * Adapted from: <a href="https://www.baeldung.com/java-play-sound">Baeldung</a>
     *
     * @param fileLocation  the URI of the desired audio file (should be a .wav file)
     */
    public static void playSoundClip(String fileLocation) {
        try (AudioInputStream stream = AudioSystem.getAudioInputStream(getResource(fileLocation))) { // FIXME: Support audio files from JAR. File streams won't work here for some reason.
            AudioFormat format = stream.getFormat();
            DataLine.Info info = new DataLine.Info(Clip.class, format);

            Clip audioClip = (Clip) AudioSystem.getLine(info);
            audioClip.addLineListener(new LineUpdateListener());
            audioClip.open(stream);
            audioClip.start();
            setVolume(audioClip, Settings.soundVolume);
        } catch (LineUnavailableException | IOException | UnsupportedAudioFileException e) {
            throw new RuntimeException(e);
        }
    }

    protected static URL getResource(String fileLocation) {
        return SoundUtil.class.getResource(fileLocation);
    }

    /**
     * Set the volume for the audio player.
     * Adapted from: <a href="https://stackoverflow.com/a/40698149">Steve Eynon on StackOverflow</a>
     *
     * @param line      the DataLine responsible for audio playback
     * @param volume    the requested volume in percent (0-100%)
     */
    protected static void setVolume(Line line, int volume) {
        if (volume < 0 || volume > 100)
            throw new IllegalArgumentException("Volume not valid: " + volume);
        FloatControl gainControl = (FloatControl) line.getControl(FloatControl.Type.MASTER_GAIN);
        gainControl.setValue(20f * (float) Math.log10(volume/100f));
    }
}
