import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import javax.media.*;
import javax.swing.*;


/**
 * A JPanel that contains a media processor 
 * (using the Java Media Framework)
 *
 * @version 1.0
 * @author  Prof. David Bernstein, James Madison University
 *
 */
public class ProcessorPanel extends    JPanel
			    implements ControllerListener
{
    protected boolean       transitionOK;
    protected Object        synchronizer;
    protected Processor     processor;


    /**
     * Constructor
     *
     */
    public ProcessorPanel()
    {
	processor = null;

	synchronizer = new Object();
	transitionOK = true;

	setLayout(new BorderLayout());
    }



    /**
     * Get the Processor associated with this ProcessorPanel
     *
     * @return  The Processor
     */
    public Processor getProcessor()
    {
	return processor;
    }


    /**
     * Configure the Processor
     *
     * @return true of the Processor was realized
     */
    public boolean configure()
    {
	boolean status;

	status = false;
	    
	    // Put the Processor into the configured state
	    processor.configure();

	    if (waitFor(processor.Configured)) {

		
		// Set the content descriptor to null so that the
		// processor can be used as a player
		processor.setContentDescriptor(null);

		status = true;

	    } else {

		JOptionPane.showMessageDialog(this, 
		    "Unable to configure the processor!");
		
	    }

	return status;
    }








    /**
     * Handle controllerUpdate events 
     * (required by ControllerListener)
     *
     * @param evt   The ControllerEvent
     */
    public synchronized void controllerUpdate(ControllerEvent evt) 
    {
	if ( (evt instanceof ConfigureCompleteEvent) ||
	     (evt instanceof RealizeCompleteEvent) || 
	     (evt instanceof PrefetchCompleteEvent) ) {

	    // Synchronize this block
	    synchronized(synchronizer) {
		
		transitionOK = true;
		synchronizer.notifyAll();
	    }

	} else if (evt instanceof ResourceUnavailableEvent) {

	    // Synchronize this block
	    synchronized(synchronizer) {
		
		transitionOK = false;
		synchronizer.notifyAll();
	    }
	}
    }






    /**
     * Load and start a media file
     *
     * @param fn  The name of the file
     */
    public void loadAndStart(String fn)
    {
	boolean     status;

	status = loadFile(fn);
	if (status) status = configure();
	if (status) status = realize();


    }




    /**
     * Load a media file
     *
     * @param fn  The name of the file
     * @return    true if the process completed successfully
     */
    public boolean loadFile(String fn)
    {
	boolean         status;
	URL             url;

	status = false;
	try {
	    
	    url = new URL("file:"+
				  System.getProperty("user.dir")+
				  "/"+fn);

	    if (url != null) {

		processor = Manager.createProcessor(url);
		processor.addControllerListener(this);
		status = true;

	    }

	} catch (NoProcessorException npe) {
	    
	    JOptionPane.showMessageDialog(this,
				 "Unable to create a processor!");
	} catch (IOException ioe) {
	    
	    JOptionPane.showMessageDialog(this,
				 "Unable to connect to source!");
	}

	return status;
    }







    /**
     * Realize the Processor
     *
     */
    public boolean realize()
    {
	boolean         status;
	Component       c;


	status = false;

	    // Put the Processor into the realized state
	    processor.prefetch();
	    
	    if (waitFor(processor.Prefetched)) {
		
		// The Processor has been realized so the
		// components can be layed out
		c = processor.getVisualComponent();
		if (c != null) add(c, BorderLayout.CENTER);
		c = processor.getControlPanelComponent();
		if (c != null) add(c, BorderLayout.SOUTH);
		validate();
		
		
		// Start the Processor
		processor.start();

		status = true;
			
	    } else {
			
		JOptionPane.showMessageDialog(this, 
			     "Unable to realize the processor!");
	    }

	return status;
    }





    /**
     * Block the thread of execution until the Processor has 
     * transitioned into the given state.
     *
     * @param state   The state to wait for
     * @return        false if the transition failed, true otherwise
     */
    protected boolean waitFor(int state)
    {
	// Make this block synchronized
	synchronized(synchronizer) {

	    try {

		while ((processor.getState() != state) && 
                      (transitionOK)) {

		    synchronizer.wait();
		}

	    } catch (InterruptedException ie) {

		// Ignore it
	    }
	}

	return transitionOK;
    }

}


