/*
 * Swogl - Swing meets OpenGL
 * 
 * Copyright 2007-2011 Marco Hutter - http://swogl.javagl.de
 */

package de.javagl.swogl.samples;


import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import javax.media.CannotRealizeException;
import javax.media.Manager;
import javax.media.NoPlayerException;
import javax.media.Player;
import javax.media.Time;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JToggleButton;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import de.javagl.swogl.MouseEventConditions;
import de.javagl.swogl.SwoglApplication;
import de.javagl.swogl.SwoglApplications;
import de.javagl.swogl.SwoglComponent;
import de.javagl.swogl.SwoglComponents;
import de.javagl.swogl.SwoglContainer;
import de.javagl.swogl.Texture;
import de.javagl.swogl.Textures;
import de.javagl.swogl.geometry.Geometry;
import de.javagl.swogl.interaction.ArcballCameraBehavior;
import de.javagl.swogl.interaction.ArcballCameraControl;

/**
 * A sample application that plays back a video using a Java Media Framework
 * video player, on an animated SwoglComponent.
 */
public class JMFSowglSample extends JFrame
{
    /**
     * The video file name
     */
    private static String FILE_NAME = "sampleVideo.avi";
    
    /**
     * The entry point of this sample
     * 
     * @param args Not used
     */
    public static void main(String[] args) 
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                new JMFSowglSample().setVisible(true);
            }
        });
    }
    
    /**
     * The JMF player
     */
    private Player player;
    
    /**
     * Create the Sample
     */
    public JMFSowglSample()
    {
        super("Swogl JMF");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().setLayout(new BorderLayout());

        // Create a SwoglApplication
        SwoglApplication swoglApplication = 
            SwoglApplications.createSwoglApplication();

        // Create a SwoglContainer for the SwoglApplication
        SwoglContainer swoglContainer = 
            SwoglContainer.create(swoglApplication);

        // Try to create a JMF player with a lightweight renderer
        Manager.setHint(Manager.LIGHTWEIGHT_RENDERER, true);
        createPlayer();

        // Create the Swing component containing the player
        // component and a control panel
        JPanel videoComponent = new JPanel(new BorderLayout());
        Component visualComponent = player.getVisualComponent();
        visualComponent.setPreferredSize(new Dimension(384, 288));
        videoComponent.add(visualComponent, BorderLayout.CENTER);
        JComponent controlPanel = createControlPanel();
        videoComponent.add(controlPanel, BorderLayout.SOUTH);

        // Create a SwoglComponent that contains the Swing component
        Dimension dim = videoComponent.getPreferredSize();
        Geometry geometry = SwoglDemoComponents.createAnimatedGeometry(
            dim.width, dim.height, swoglApplication.getRenderComponent()); 
        Texture texture = Textures.create(dim.width, dim.height);
        SwoglComponent swoglComponent = SwoglComponents.create(
            geometry, texture, videoComponent);
        swoglContainer.add(swoglComponent);

        // Init the interaction: An arcball that may be
        // controlled when SHIFT is pressed
        swoglContainer.setMouseEventDispatchingConditions(
            MouseEventConditions.shiftDownCondition(), null);
        ArcballCameraBehavior arcballCameraBehavior = 
            new ArcballCameraBehavior(
                swoglApplication.getView(), 
                swoglApplication.getCamera());
        ArcballCameraControl arcballCameraControl = 
            new ArcballCameraControl(arcballCameraBehavior);
        arcballCameraControl.attachTo(
            swoglContainer.getMainComponent());

        // Assemble the frame contents.
        getContentPane().add(
            swoglContainer.getMainComponent(), BorderLayout.CENTER);
        getContentPane().add(
            player.getControlPanelComponent(), BorderLayout.SOUTH);
        
        setSize(800,800);
    }
    

    /**
     * Tries to create a media player. Many things may go wrong here, so this
     * call only wraps all possible exceptions into a RuntimeException.
     */
    private void createPlayer()
    {
        try
        {
            URL url = new File(FILE_NAME).toURI().toURL();
            player = Manager.createRealizedPlayer( url );
            player.start();
        }
        catch (MalformedURLException e)
        {
            throw new RuntimeException("Could not create player", e);
        }
        catch (NoPlayerException e)
        {
            throw new RuntimeException("Could not create player", e);
        }
        catch (CannotRealizeException e)
        {
            throw new RuntimeException("Could not create player", e);
        }
        catch (IOException e)
        {
            throw new RuntimeException("Could not create player", e);
        }
    }
    
    /**
     * Create a simple control panel for the current player
     *  
     * @return The control panel
     */
    private JComponent createControlPanel()
    {
        JPanel controlPanel = new JPanel(new BorderLayout());
        
        // Create a play/pause toggle button
        final JToggleButton playButton = new JToggleButton("||");
        playButton.setSelected(true);
        playButton.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                if (playButton.isSelected())
                {
                    playButton.setText("||");
                    player.start();
                }
                else
                {
                    playButton.setText(">");
                    player.stop();
                }
            }
        });
        controlPanel.add(playButton, BorderLayout.WEST);
        
        // Create a slider for setting the media time
        int milliseconds = 
            (int)(player.getDuration().getNanoseconds() / 1.e6);
        final JSlider slider = new JSlider(0, milliseconds);
        slider.addChangeListener(new ChangeListener()
        {
            @Override
            public void stateChanged(ChangeEvent e)
            {
                if (!slider.getValueIsAdjusting())
                {
                    int milliseconds = slider.getValue();
                    long nanoseconds = (long)(milliseconds * 1e6);
                    player.setMediaTime(new Time(nanoseconds));
                }
            }
        });
        controlPanel.add(slider, BorderLayout.CENTER);

        // Create a timer that updates the slider regularly 
        Timer timer = new Timer(50, new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                int milliseconds = 
                    (int)(player.getMediaTime().getNanoseconds() / 1e6);
                if (!slider.getValueIsAdjusting())
                {
                    if (slider.getValue() != milliseconds)
                    {
                        slider.setValueIsAdjusting(true);
                        slider.setValue(milliseconds);
                        slider.setValueIsAdjusting(false);
                    }
                }
            }
        });
        timer.start();
        
        return controlPanel;
    }
}

