import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.io.*;
import javax.swing.*;
import javax.sound.sampled.AudioFormat;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;

import com.brackeen.javagamebook.graphics.NullRepaintManager;
import com.brackeen.javagamebook.sound.*;
import com.brackeen.javagamebook.test.GameCore;

/**
    Klasa SoundManagerTest demonstruje działanie klasy
    SoundManager. Zrealizowane zostąły następujące demonstracje:
    <ul>
    <li>Odtwarzanie sekwencji Midi.
    <li>Przełączanie ścieżki sekwencji Midi.
    <li>Odtwarzanie dźwięku.
    <li>Odtwarzanie dźwięku z filtrem Echo..
    <li>Zapętlanie dźwięku.
    <li>Odtwarzanier jednocześnie maksymalnej liczby dźwięków.
    <li>Pauza wszystkich dźwięków.
    </ul>
    <p>Klasa ta nie jest zamieszczona w ksiażce.
    @see SoundManager
    @see Sound
    @see SoundFilter
*/
public class SoundManagerTest extends GameCore
    implements ActionListener
{
    public static void main(String[] args) {
        new SoundManagerTest().run();
    }

    // nieskompresowany, 44100 Hz, 16-bitowy, mono, ze znakiem, 
    // rosnący porządek bitów
    private static final AudioFormat PLAYBACK_FORMAT =
        new AudioFormat(44100, 16, 1, true, false);

    private static final int MANY_SOUNDS_COUNT =
        SoundManager.getMaxSimultaneousSounds(PLAYBACK_FORMAT);

    private static final int DRUM_TRACK = 1;

    private static final String EXIT = "Koniec";
    private static final String PAUSE = "Pauza";
    private static final String PLAY_MUSIC = "Odtwarzanie muzyki";
    private static final String MUSIC_DRUMS = "Przełączanie bębnów";
    private static final String PLAY_SOUND = "Odtwarzanie dźwięku";
    private static final String PLAY_ECHO_SOUND = "Odtwarzanie dźwięku z echem";
    private static final String PLAY_LOOPING_SOUND =
        "Odtwarzanie dźwięku w pętli";
    private static final String PLAY_MANY_SOUNDS =
        "Odtwarzanie " + MANY_SOUNDS_COUNT + " dźwięków";


    private SoundManager soundManager;
    private MidiPlayer midiPlayer;
    private Sequence music;
    private Sound boop;
    private Sound bzz;
    private InputStream lastloopingSound;

    public void init() {
        super.init();
        initSounds();
        initUI();
    }

    /**
        Ładowanie dźwięku i muzyki.
    */
    public void initSounds() {
        midiPlayer = new MidiPlayer();
        soundManager = new SoundManager(PLAYBACK_FORMAT);
        music = midiPlayer.getSequence("../sounds/music.midi");
        boop = soundManager.getSound("../sounds/boop.wav");
        bzz = soundManager.getSound("../sounds/fly-bzz.wav");
    }


    /**
        Tworzenie interfejsu użytkownika, którym jest wiersz przycisków.
    */
    public void initUI() {
        // Upewnij się, że komponenty Swing się nie rysują
        NullRepaintManager.install();

        JFrame frame = super.screen.getFullScreenWindow();
        Container contentPane = frame.getContentPane();

        contentPane.setLayout(new FlowLayout());
        contentPane.add(createButton(PAUSE, true));
        contentPane.add(createButton(PLAY_MUSIC, true));
        contentPane.add(createButton(MUSIC_DRUMS, false));
        contentPane.add(createButton(PLAY_SOUND, false));
        contentPane.add(createButton(PLAY_ECHO_SOUND, false));
        contentPane.add(createButton(PLAY_LOOPING_SOUND, true));
        contentPane.add(createButton(PLAY_MANY_SOUNDS, false));
        contentPane.add(createButton(EXIT, false));

        // jawne układanie komponentów (potrzebne w niektórych systemach)
        frame.validate();
    }

    /**
        Rysowanie wszystkich komponentów Swing
    */
    public void draw(Graphics2D g) {
        JFrame frame = super.screen.getFullScreenWindow();
        frame.getLayeredPane().paintComponents(g);
    }

    /**
        Tworzenie przycisku (JButton lub JToggleButton).
    */
    public AbstractButton createButton(String name,
        boolean canToggle)
    {
        AbstractButton button;

        if (canToggle) {
            button = new JToggleButton(name);
        }
        else {
            button = new JButton(name);
        }
        button.addActionListener(this);
        button.setIgnoreRepaint(true);
        button.setFocusable(false);

        return button;
    }

    /**
        Wykonywanie akcji po naciśnięciu przycisku.
    */
    public void actionPerformed(ActionEvent e) {
        String command = e.getActionCommand();
        AbstractButton button = (AbstractButton)e.getSource();
        if (command == EXIT) {
            midiPlayer.close();
            soundManager.close();
            stop();
        }
        else if (command == PAUSE) {
            // pauzowanie dźwięku
            soundManager.setPaused(button.isSelected());
            midiPlayer.setPaused(button.isSelected());
        }
        else if (command == PLAY_MUSIC) {
            // włączanie i wyłączanie muzyki
            if (button.isSelected()) {
                midiPlayer.play(music, true);
            }
            else {
                midiPlayer.stop();
            }
        }
        else if (command == MUSIC_DRUMS) {
            // włączanie i wyłączanie bębnów
            Sequencer sequencer = midiPlayer.getSequencer();
            if (sequencer != null) {
                 boolean mute = sequencer.getTrackMute(DRUM_TRACK);
                 sequencer.setTrackMute(DRUM_TRACK, !mute);
            }
        }
        else if (command == PLAY_SOUND) {
            // odtwarzanie normalnego dźwięku
            soundManager.play(boop);
        }
        else if (command == PLAY_ECHO_SOUND) {
            // odtwarzanie dźwięku z echem
            EchoFilter filter = new EchoFilter(11025, .6f);
            soundManager.play(boop, filter, false);
        }
        else if (command == PLAY_LOOPING_SOUND) {
            // odtwarzanie lub zatrzymywanie zapętlonego dźwięku
            if (button.isSelected()) {
                lastloopingSound = soundManager.play(bzz, null, true);
            }
            else if (lastloopingSound != null) {
                try {
                    lastloopingSound.close();
                }
                catch (IOException ex) { }
                lastloopingSound = null;
            }
        }
        else if (command == PLAY_MANY_SOUNDS) {
            // Odtwarzanie jednocześnie kilku dźwięków w celu przetestowania systemu
            for (int i=0; i<MANY_SOUNDS_COUNT; i++) {
                soundManager.play(boop);
            }
        }
    }

}
