package net.sf.fmj.ejmf.toolkit.util;

import java.applet.Applet;
import java.awt.Component;
import java.awt.Image;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import javax.media.Control;
import javax.media.Controller;
import javax.media.GainControl;
import javax.media.MediaLocator;
import javax.media.Player;
import javax.media.Time;
import javax.swing.GrayFilter;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;

/**
 * Static utilites for common JMF routines
 * 
 * From the book: Essential JMF, Gordon, Talley (ISBN 0130801046).  Used with permission.
 *
 * @author     Steve Talley & Rob Gordon
 */
public class Utility {
 




    /**
     * Converts an applet argument to a MediaLocator.
     *
     * @return     A MediaLocator for the given argument.
     */
    public static MediaLocator appletArgToMediaLocator(
        Applet applet,
        String arg)
    {
        URL url = null;

        //  Check if arg is a valid url
        try {
            return new MediaLocator(
                new URL(arg) );
        } catch( MalformedURLException e ) {}

        //  Check if arg + doc base is a valid url
        try {
            return new MediaLocator(
                new URL( applet.getDocumentBase(), arg) );
        } catch( MalformedURLException e ) {}

        return new MediaLocator(arg);
    }

    /**
     * Convert a File to a URL using file: protocol.
     *
     * @param      fileName
     *             The file to convert
     *
     * @return     a java.net.URL representing file named by
     *             input File argument.
     */
    public static URL fileToURL(String fileName)
        throws IOException, MalformedURLException
    {
        File file = new File(fileName);

        if( ! file.exists() ) {
            throw new IOException(
                "File " + fileName + " does not exist.");
        }

        //  Prepend file protocol + "/" and create url
        return new URL( "file:///" + file.getCanonicalPath() );
    }

    /**
     * Converts a string to a URL.  Tries first to convert the
     * string itself to a URL.  If not successful, assumes arg
     * is a file and tries to create a file URL using the full
     * path name of the specified file.  The return value of this
     * routine should be checked to ensure that a URL was
     * successfully created.
     *
     * @param          arg
     *                 the url string to convert
     * @return         a URL if successful, null otherwise
     */
    public static MediaLocator appArgToMediaLocator(String arg) {
        URL url = null;

        //  Check if arg is a valid url
        try {
            return new MediaLocator(
                new URL(arg) );
        } catch( MalformedURLException e ) {}

        // Check if it is a file name
        try {
            return new MediaLocator(
                fileToURL(arg) );
        }
        catch( MalformedURLException e ) {}
        catch( IOException e ) {}

        // Default MediaLocator
        return new MediaLocator(arg);
    }

    /**
     * Convert a Controller state to a string
     *
     * @param          state
     *                 the state to convert
     * @return         a String representing the given state
     */
    public static String stateToString(int state) {
        switch(state) {
            case Controller.Unrealized:  return "Unrealized";
            case Controller.Realizing:   return "Realizing";
            case Controller.Realized:    return "Realized";
            case Controller.Prefetching: return "Prefetching";
            case Controller.Prefetched:  return "Prefetched";
            case Controller.Started:     return "Started";
        }
        return null;
    }

     /**
      * Given an array of Controllers, calculate the maximum
      * startup latency in seconds.  If a Controller reports
      * LATENCY_UNKNOWN, its value is ignored.
      * <p>
      * All Controllers must be at least in the Realized state.
      * If a Controller is not in the realized state, its value
      * is ignored.
      * <p>
      * If all Controllers report LATENCY_UNKNOWN, return
      * LATENCY_UNKNOWN and let the caller worry about what to
      * do.
      * <p>
      * @param      controllers
      *             An array of javax.media.Controller objects
      *             all at least realized.
      * <p>
      * @return     javax.media.Time object representing the
      *             maximum startup latency across all the input
      *             Controllers.
      */
    public static Time getMaximumLatency(Controller[] controllers) { 
        Time    maxLatency = new Time(0.0);
        Time    thisTime;
        double  maxSeconds = 0.0;

        for (int i = 0; i < controllers.length; i++) {
            if (controllers[i].getState() < Controller.Realized ||
               (thisTime = controllers[i].getStartLatency()) 
                    == Controller.LATENCY_UNKNOWN)
            {
                continue;
            }

            double thisSeconds = thisTime.getSeconds();
            if (thisSeconds > maxSeconds)
                maxLatency = thisTime;
        }
        return maxLatency;
    }

    /**
      * Given a File object, return a String representing
      * the file's extension. If there is no extension, return null.
      *
      * @param f A java.io.File object
      * @return A String representing file extension
      */
    public static String getExtension(File f) {
        return getExtension(f.getName());
    }

    /**
      * Given a String representing a file name, return a String representing
      * the file's extension. If there is no extension, return null.
      *
      * @param filename A filename as a java.lang.String object
      * @return A String representing file extension
      */
    public static String getExtension(String filename) {
        String ext = null;
        int i = filename.lastIndexOf('.');
        if (i > 0 &&  i < filename.length() - 1) {
            ext = filename.substring(i+1).toLowerCase();
        }
        return ext;
    }

    /**
     * Displays each Control not currently being shown.
     */
    public static void showControls(Controller controller) {

        // Show all Controls not yet being shown
        Control[] controls = controller.getControls();

        for(int i = 0; i < controls.length; i++) {
            Component c =
                controls[i].getControlComponent();

            if( c != null && ! c.isShowing() ) {

                JFrame frame = new JFrame(
                    controls[i].getClass().getName() );

                frame.getContentPane().add(c);
                frame.pack();
                frame.setVisible(true);
            }
        } 
    }

    /**
     * Pick a master Player for an array of Players.
     * Return first Player that has a gain control.
     * If no Player has a gain control, return 
     * 0.
     *
     * All the input Players are assumed to be realized, else
     * they will return a null gain control.
     *
     * @param players an array of Players
     * @return an index into the Player array of the Player
     * chosen as the master Player.
     *
     */
    public static int pickAMaster(Player[] players) {
        for(int i = 0; i < players.length; i++) {
            GainControl gain =
                players[i].getGainControl();

            if( gain != null &&
                gain.getControlComponent() != null )
            {
                return i;
            }
        }
        return 0;
    }

    /** 
     * Create a disabled icon using a gray filter.
     */
    public static Icon createDisabledIcon(ImageIcon imageIcon) {
        Image i =
            GrayFilter.createDisabledImage(
                imageIcon.getImage() );

        return new ImageIcon(i);
    }

}
