
// LoadersTests.java
// Andrew Davison, April 2005, ad@fivedots.coe.psu.ac.th

/* Aplikace LoadersTests demonstruje použití tříd MidisLoader a ClipsLoader.
   Midi-sekvence klipy lze přehrát, pozastavit, opětovně spusti, 
   stopnout a přehrávat cyklicky.

   Díky způsobu, jakým se objekty typu Clip spouštějí může 
   hrát Více klipů současně. V jednom okamžiku ovšem může hrát jen 
   jediná midi-sekvence, protože třída MidisLoader vytváří pouze
   jeden objekt typu Seqencer.

   Při přehrávání midi-sekvence lze spouštět celou řadu klipů.

   Tématem této ukázkové aplikace je farma. Zkuste spustit sekvenci
   'Starý McDonald' a současně nastavit cyklické přehrávání klipů
   se psem, ovečkou a dalšími.
*/

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.border.*;



public class LoadersTests extends JFrame 
				implements ActionListener, ItemListener, SoundsWatcher
{
  // krátká jména pro midi-sekvence
  private final static String[] shortSongNames =
           {"farmer", "mary", "mcdonald", "baa"};

  // dlouhá jména pro zobrazení uživateli
  private final static String[] songNames = 
           {"The Farmer in the Dell", "Mary had a Little Lamb",
            "Old McDonald had a Farm", "Bach Sheep"};

  // názvy obrázků jednotlivých klipů (used to label the checkboxes)
  private final static String[] names = {"dog", "cat", "sheep", "chicken"};

  // soubory s údaji o klipech jsou umístěny v podadresáři Sounds/
  private final static String SNDS_FILE = "clipsInfo.txt";
  private final static String MIDIS_FILE = "midisInfo.txt";

  // pro obarvení tlačítka "Přehrát cyklicky" při jeho aktivaci
  private final static Color grayGreen = new Color(88, 110, 84);
  private final static Color lightGreen = new Color(90, 120, 20);

  // ovládací prvky GUI
  private JButton playJbut, pauseJbut, stopJbut, loopJbut;
  private JCheckBox dogJck, catJck, sheepJck, chickenJck;
  private JComboBox namesJcb;

  // příznaky cyklického přehrávání klipů, uložené v tomto pořadí:
  //               "dog", "cat", "sheep", "chicken"
  private boolean[] clipLoops = {false, false, false, false};

  private boolean isPauseButton;   // pro midi-songy

  private Color background;  // uchovává barvu pozadí tlačítka

  private ClipsLoader clipsLoader;
  private MidisLoader midisLoader;


  public LoadersTests()
  {
    super( "Sounds Tests" );
    Container c = getContentPane();
    c.setLayout( new BorderLayout() );   

    SoundsPanel sp = new SoundsPanel(this);   // kreslící plocha pro obrázky
    c.add( sp, BorderLayout.CENTER);
    initGUI(c);                        // zbývající ovládací prvky

    // inicializuj načítací objekty
    clipsLoader = new ClipsLoader(SNDS_FILE); 
    clipsLoader.setWatcher("dog", this);     // hlídej klip "dog"

    midisLoader = new MidisLoader(MIDIS_FILE);
    midisLoader.setWatcher(this);            // hlídej přehrávání midi

    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent ev) {
        midisLoader.close();   // uzavři sekvencer
        System.exit(0);
      }
    });

    pack();
    setResizable(false);    // rozměry okna jsou pevně dány
    centerFrame();
    setVisible(true);
  } // konec metody: LoadersTests()


  private void centerFrame()
  // Umístí toto okno typu JFrame doprostřed obrazovky
  {
    Toolkit tk = Toolkit.getDefaultToolkit();
    Dimension sd = tk.getScreenSize();
    Dimension fd = getSize();
    setLocation(sd.width/2 - fd.width/2, sd.height/2 - fd.height/2);
  }  // konec metody: centerFrame()


  private void initGUI(Container c)
  /*  Na pravé straně je řada 4 zaškrtávacích polí pro cyklické
      přehrávání klipů.

      Na levé straně je řada tlačítek pro přehrání,
      pozastavení/spuštění, stopnutí a cyklické přehrání
      zvolené midi-sekvence. Seznam sekvencí je k dispozici
      v roletovém menu.
  */
  {
    // pravá stran ovládacího panelu

    // zaškrtávací pole pro cyklické přehrávání klipů
    JPanel p1 = new JPanel();
    p1.setLayout( new GridLayout(2,2));

    dogJck = new JCheckBox(names[0]);    // pro obrázek psa
    dogJck.addItemListener(this);
    p1.add(dogJck);

    catJck = new JCheckBox(names[1]);    // kočky
    catJck.addItemListener(this);
    p1.add(catJck);

    sheepJck = new JCheckBox(names[2]);   // ovce
    sheepJck.addItemListener(this);
    p1.add(sheepJck);

    chickenJck = new JCheckBox(names[3]); // kuřete
    chickenJck.addItemListener(this); 
    p1.add(chickenJck);

    // 'Cyklické přehrávání klipů'
    Border blackline = BorderFactory.createLineBorder(Color.black);
    TitledBorder loopTitle = BorderFactory.createTitledBorder(
                              blackline, "Cyklické přehrávání klipů");

    
    // dej všech části pravé strany dohromady
    JPanel rightPanel = new JPanel();
    rightPanel.setLayout( new BoxLayout(rightPanel, BoxLayout.Y_AXIS) );
    rightPanel.add( p1);
    rightPanel.setBorder(loopTitle); 


    // -----------------------------------
    // levá strana ovládacího panelu
    JPanel leftPanel = new JPanel();
    leftPanel.setLayout( new BoxLayout(leftPanel, BoxLayout.Y_AXIS) );

    // první řádek midi-tlačítek
    JPanel p2 = new JPanel();
    p2.setLayout( new BoxLayout(p2, BoxLayout.X_AXIS) );

    // ovládací tlačítka midi
    playJbut = new JButton("Hrát jednou");
    playJbut.addActionListener(this);
    p2.add(playJbut);

    pauseJbut = new JButton("Pokračuj");  // tento text pomáhá nastavit maximální rozměry
    Dimension d = pauseJbut.getMaximumSize();
    pauseJbut.setPreferredSize( d );   // oprav rozměry tlačítka
    pauseJbut.setMinimumSize( d );
    pauseJbut.setMaximumSize( d );
    pauseJbut.setText("Pozastav");     // změň text
    pauseJbut.setEnabled(false);    // zpočátku není aktivní
    pauseJbut.addActionListener(this);
    p2.add(pauseJbut);
    isPauseButton = true;

    stopJbut = new JButton("Zastavit");
    stopJbut.addActionListener(this);
    p2.add(stopJbut);
    stopJbut.setEnabled(false);    // zpočátku není aktivní

    leftPanel.add(p2);   // první řádek midi-tlačítek


    // tlačítko pro cyklické přehrávání midi-sekvencí je na druhém řádku
    loopJbut = new JButton("Hrát dokola");
    loopJbut.addActionListener(this);

    JPanel p3 = new JPanel();   // aby byla tlačítka zarovnána vlevo
    p3.setLayout( new FlowLayout(FlowLayout.LEFT));
    p3.add(loopJbut);
    leftPanel.add(p3);

    // roletové menu se jmény písní
    namesJcb = new JComboBox(songNames);
    leftPanel.add(namesJcb);

    // ------------------------------------
    // zkombinuj obě strany ovládacího panelu
    JPanel controlPanel = new JPanel();
    controlPanel.setLayout( new BoxLayout(controlPanel, BoxLayout.X_AXIS) );
    controlPanel.add(leftPanel);
    controlPanel.add(rightPanel);
   
    c.add( controlPanel, BorderLayout.SOUTH);
  } // konec metody: initGUI()



  public void actionPerformed(ActionEvent e)
  /* Spouští se stisky tlačítek.
     Zavolá relevantní metodu objektu typu MidisLoader.
     Velká část kódu se stará o aktivaci/deaktivaci tlačítek.
  */
  {
    // která piseň je právě zvolená?
    String songName = shortSongNames[ namesJcb.getSelectedIndex() ];

    if (e.getSource() == playJbut) {    // stisknuto tlačítko "Hraj jednou"
      midisLoader.play(songName, false);    // přehraj sekvenci bez cyklení
      playJbut.setEnabled(false);
      loopJbut.setEnabled(false);
      pauseJbut.setEnabled(true);
      stopJbut.setEnabled(true); 
    }
    else if (e.getSource() == loopJbut) {    // stisknuto tlačítko "Hraj dokola"
      midisLoader.play(songName, true);   // cyklicky přehraj sekvenci
      playJbut.setEnabled(false);
      background = loopJbut.getBackground();
      loopJbut.setBackground(lightGreen);  // zvýrazni talčítko pro cyklické přehrávání
      loopJbut.setEnabled(false);
      pauseJbut.setEnabled(true);
      stopJbut.setEnabled(true); 
    }
    else if (e.getSource() == pauseJbut) {    // stisknuto tlačítko "Pozastav/Pokračuj"
      if (isPauseButton) {   
        midisLoader.pause();    // pozastav sekvenci
        pauseJbut.setText("Pokračuj");      // Pozastav --> Pokračuj
        stopJbut.setEnabled(false); 
     }
      else {
        midisLoader.resume();  // pokračuj v přehrávání sekvence
        pauseJbut.setText("Pozastav");      // Pokračuj --> Pozastav
        stopJbut.setEnabled(true); 
      }
      isPauseButton = !isPauseButton;
    }
    else if (e.getSource() == stopJbut) {  // stisknuto tlačítko "Stop"
      midisLoader.stop();   // zastav sekvenci
      playJbut.setEnabled(true);
      loopJbut.setEnabled(true);
      loopJbut.setBackground(background); // zruš zvýraznění tlačítka pro cyklické přehrávání
      pauseJbut.setEnabled(false);
      stopJbut.setEnabled(false); 
    }
    else
      System.out.println("Neznámá akce");
  }  // konec metody: actionPerformed()



  public void itemStateChanged(ItemEvent e)
  /* Spouští se výběrem/zrušením zaškrtávacího políčka klipu.
     Zavolá správnou metodu objektu typu ClipsLoader.
  */
  {  // které zaškrtávací pole bylo zvoleno?
    String name = ((JCheckBox)e.getItem()).getText();
    boolean isSelected = (e.getStateChange() == e.SELECTED) ? true : false ;
    // System.out.println("Klepnuto na " + name + ": " + isSelected);

    boolean switched = false;
    for (int i=0; i < names.length; i++)
      if (names[i].equals(name)) {
        clipLoops[i] = !clipLoops[i];   // aktualizuj příznaky cyklického přehrávání klipu
        switched = true;
        break;
      }
    if (!switched)
      System.out.println("Neznámé políčko");
    else {
      if (!isSelected)   //  uživatel právě vypnul cyklické přehrávání
        clipsLoader.stop(name);    // takže zastav přehrávání příslušného klipu
    }
  }  // konec metody: itemStateChanged()


  public void atSequenceEnd(String name, int status)
  // může být volána objekty typu ClipsLoader a MidisLoader
  {
    if (status == SoundsWatcher.STOPPED)
      System.out.println(name + " dohrála");
    else if (status == SoundsWatcher.REPLAYED)
      System.out.println(name + " hraje znovu");
    else
      System.out.println(name + " status: " + status);
  }  // konec metody: atSequenceEnd()


  // -------------------- manipulace se zvukem ------------


  public void playClip(String name, int i)
  // volá se ze třídy SoundsPanel a slouží pro přehrání daného klipu
// (ať už k jednorázovému či k cyklickému hraní)
  {  clipsLoader.play(name, clipLoops[i]);  }


// ------------------------------------------------------

   public static void main( String args[] )
   { new LoadersTests();  } 

} // konec třídy: LoadersTests
