/*
 * $Id$
 *
 * Copyright 1996-2008 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */
package com.sun.javatest.exec;

import com.sun.javatest.tool.UIFactory;
import com.sun.javatest.util.HTMLWriter;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageInputStream;
import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MidiFileFormat;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.RepaintManager;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.Document;
import javax.swing.text.EditorKit;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.HTMLFrameHyperlinkEvent;
import javax.swing.text.rtf.RTFEditorKit;

/**
 *
 * @author Sergey Borodin
 */
public class MultiFormatPane extends JPanel implements Printable {

    public MultiFormatPane(UIFactory uif) {
        this.uif = uif;

        listener = new Listener();
        initGUI();

        modesToPanes = new HashMap();

        addMediaPane(TEXT, textPane);
        addMediaPane(AUDIO, musicPane);
        addMediaPane(IMAGE, imagePane);
        addMediaPane(ERROR, errorPane);

    }

    public void setNoteField(JTextField noteField) {
        this.noteField = noteField;
    }

    public void setNavigationPane(NavigationPane navPane) {
        this.navPane = navPane;
    }

    public void addMediaPane(int mode, MediaPane pane) {
        modesToPanes.put(mode, pane);
    }

    public MediaPane getMediaPane(int mode) {
        return (MediaPane)modesToPanes.get(mode);
    }

    public void clear() {
        currURL = null;
        if(navPane != null) {
            navPane.clear();
        }
        musicPane.stopAudio();
    }

    public URL getPage() {
        return currURL;
    }

    public int getCurrentMode() {
        return getCurrentPane().getMode();
    }

    public MediaPane getCurrentPane() {
        return (MediaPane)scrllBody.getViewport().getComponent(0);
    }

    // Base directory is root directory for displayable content
    // if it set, all filenames will be relative to this directory
    void setBaseDirectory(File base) {
        baseDir = base;
    }

    File getBaseDirectory() {
        return baseDir;
    }

    void setDefaultView() {
        textPane.setDocument(new HTMLDocument());
        textPane.showTextArea();
    }

    private void initGUI() {
        uif.initPanel(this, "mfp", false);

        textPane = new TextPane(uif, "mfp.textPane", null);
        textPane.addHyperlinkListener(listener);

        scrllBody = uif.createScrollPane(textPane,
                                 JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
                                 JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

        textPane.setParent(scrllBody);

        musicPane = new MusicPane(uif, "mfp.audioPane", scrllBody);
        imagePane = new ImagePane(uif, "mfp.imagePanelbl", scrllBody);
        errorPane = new ErrorFormatPane(uif, "mfp.errorPane", scrllBody);

        scrllBody.setViewportView(textPane);

        setLayout(new BorderLayout());

        add(scrllBody, BorderLayout.CENTER);

    }


    //Loads everything by URL
    public void loadPage(URL url) {
        // avoid recursive callbacks from updating combo
        if (url.equals(currURL))
            return;

        currURL = url;

        String protocol = url.getProtocol();
        File file = new File(url.getFile());
        if (protocol.equals("file") && file.isDirectory()) {
            String list = listLocalDirectory(file);
            textPane.showText(list, "text/html");
            ((HTMLDocument)textPane.getDocument()).setBase(url);
        }
        else if (ImagePane.isImageResource(url)) {
            imagePane.showImage(url);
        }
        else if(MusicPane.isAudioResource(url)) {
            musicPane.showAudio(url);
        }
        else if(isMediaResourceCorrupted(url)) {
            errorPane.showError(uif.getI18NString("mfp.errorPaneLbl.corrupted"));
        }
        else if(TextPane.isTextResource(url)){
            textPane.showText(url);
        }
        else {
            int response = uif.showYesNoDialog("mfp.unknownTypeDlg");
            if(response == JOptionPane.YES_OPTION) {
                textPane.showText(url);
            }
            else {
                errorPane.showError(uif.getI18NString("mfp.errorPaneLbl.unsupported"));
            }
        }

        if(navPane != null) {
            navPane.processURL(url);
        }
    }


    public void showText(String text, String MIME) {
        textPane.showText(text, MIME);
        currURL = null;
    }

    public void showText(URL url) {
        textPane.showText(url);
    }

    public void showAudio(URL url) {
        musicPane.showAudio(url);
    }

    public void stopAudio() {
        musicPane.stopAudio();
    }

    public void showImage(URL url) {
        imagePane.showImage(url);
    }

    public void showError(String errorMessage) {
        errorPane.showError(errorMessage);
    }


    private boolean isMediaResourceSupported(URL url) {
        return ImagePane.isImageResource(url) || MusicPane.isAudioResource(url);
    }

    private boolean isMediaResourceCorrupted(URL url) {
        String filename = url.getFile();
        String ext = filename.substring(filename.lastIndexOf('.') + 1);
        ext = ext.toLowerCase();

        return (SUPPORTED_MEDIA_RESOURCE_EXTENSIONS.indexOf(ext) != -1) &&
                !isMediaResourceSupported(url);
    }


    private String listLocalDirectory(File dir) {
        if (!dir.isAbsolute())
            dir = dir.getAbsoluteFile();

        String displayPath = dir.getPath();
        // if contains base dir, only show path relative to baseDir
        if (baseDir != null) {
            String p = baseDir.getParent();
            if (p != null
                && displayPath.startsWith(p) &&
                (displayPath.length() > p.length())) {
                displayPath = displayPath.substring(p.length());
                // in case of Unix
                if (displayPath.startsWith(File.separator)) {
                    displayPath = displayPath.substring(1);
                }
            }
        }

        String[] filelist = dir.list();

        StringWriter sw = new StringWriter();
        try {
            HTMLWriter out = new HTMLWriter(sw, uif.getI18NResourceBundle());

            out.startTag(HTMLWriter.HTML);
            out.startTag(HTMLWriter.HEAD);
            out.startTag(HTMLWriter.TITLE);
            out.write(displayPath);
            out.endTag(HTMLWriter.TITLE);
            out.endTag(HTMLWriter.HEAD);
            out.startTag(HTMLWriter.BODY);
            out.writeStyleAttr("font-family: SansSerif; font-size: 12pt");
            out.startTag(HTMLWriter.H3);
            out.writeI18N("mfp.head", displayPath);
            out.endTag(HTMLWriter.H3);
            out.startTag(HTMLWriter.UL);
            out.writeStyleAttr("margin-left:0");

            File parent = dir.getParentFile();
            if (parent != null) {
                out.startTag(HTMLWriter.LI);
                out.startTag(HTMLWriter.OBJECT);
                out.writeAttr(HTMLWriter.CLASSID, "com.sun.javatest.tool.IconLabel");
                out.writeParam("type", "up");
                out.endTag(HTMLWriter.OBJECT);
                out.writeEntity("&nbsp;");
                try {
                    out.startTag(HTMLWriter.A);
                    out.writeAttr(HTMLWriter.HREF, parent.toURL().toString());
                    out.writeI18N("mfp.parent");
                    out.endTag(HTMLWriter.A);
                }
                catch (MalformedURLException e) {
                    out.writeI18N("mfp.parent");
                }
            }

            for (int i = 0; i < filelist.length; i++) {
                File file = new File(dir, filelist[i]);
                out.startTag(HTMLWriter.LI);
                out.startTag(HTMLWriter.OBJECT);
                out.writeAttr(HTMLWriter.CLASSID, "com.sun.javatest.tool.IconLabel");
                out.writeParam("type", (file.isDirectory() ? "folder" : "file"));
                out.endTag(HTMLWriter.OBJECT);
                out.writeEntity("&nbsp;");
                try {
                    out.writeLink(file.toURL(), file.getName());
                }
                catch (MalformedURLException e) {
                    out.write(file.getName());
                }
            }

            out.endTag(HTMLWriter.UL);
            out.endTag(HTMLWriter.BODY);
            out.endTag(HTMLWriter.HTML);
            out.close();
        }
        catch (IOException e) {
            // should not happen, writing to StringWriter
        }

        return sw.toString();
    }

    public interface MediaPane {

        public int getMode();

        public void changeURL(URL url);

        public void setParent(JScrollPane pane);
    }

// Print this panel
    public int print (Graphics g, PageFormat pf, int pageIndex) {

        int response = NO_SUCH_PAGE;

        Graphics2D g2 = (Graphics2D) g;

        Component componentToBePrinted = scrllBody.getComponent(0);
        int mode = getCurrentMode();
        switch(mode) {
            case TEXT:
                componentToBePrinted = textPane;
                break;
            case IMAGE:
                componentToBePrinted = imagePane;
                break;
            default:
                break;
        }

        //  for faster printing, turn off double buffering
        disableDoubleBuffering(componentToBePrinted);

        Dimension d = componentToBePrinted.getSize();
        double panelWidth = d.width;
        double panelHeight = d.height;

        double pageHeight = pf.getImageableHeight();
        double pageWidth = pf.getImageableWidth();

        double scale = pageWidth / panelWidth;
        int totalNumPages = (int) Math.ceil(scale * panelHeight / pageHeight);

        if (pageIndex >= totalNumPages) {
          response = NO_SUCH_PAGE;
        }
        else {

          //  shift Graphic to line up with beginning of print-imageable region
          g2.translate(pf.getImageableX(), pf.getImageableY());

          //  shift Graphic to line up with beginning of next page to print
          g2.translate(0f, -pageIndex * pageHeight);

          g2.scale(scale, scale);

          componentToBePrinted.paint(g2);

          enableDoubleBuffering(componentToBePrinted);
          response = Printable.PAGE_EXISTS;
        }
        return response;
    }

    private void disableDoubleBuffering(Component c) {
        RepaintManager currentManager = RepaintManager.currentManager(c);
        currentManager.setDoubleBufferingEnabled(false);
      }

    private void enableDoubleBuffering(Component c) {
        RepaintManager currentManager = RepaintManager.currentManager(c);
        currentManager.setDoubleBufferingEnabled(true);
    }
// END of printing

    private class Listener implements HyperlinkListener {
        public void hyperlinkUpdate(HyperlinkEvent e) {
            HyperlinkEvent.EventType et = e.getEventType();
            if (et == HyperlinkEvent.EventType.ACTIVATED) {
                if (e instanceof HTMLFrameHyperlinkEvent) {
//                  HTMLDocument doc = (HTMLDocument)
//                      ((JEditorPane) e.getSource()).getDocument();
//                  doc.processHTMLFrameHyperlinkEvent((HTMLFrameHyperlinkEvent) e);
                    processFrameLink(e);
                }
                else {
                    musicPane.stopAudio();
//                    String s = e.getDescription();
//                    URL correctURL = e.getURL();
//                    HTMLDocument doc = (HTMLDocument)((JEditorPane)e.getSource()).getDocument();
//                    if(doc != null && currURL != null && !doc.getBase().equals(currURL))
//                        currURL = doc.getBase();
//                    // JEditorPane doesn't allows javascript, so we delete this parameter and load
//                    // root page of help package
//                    if(correctURL.getProtocol().equals("file")) {

//                        int pos = correctURL.toString().indexOf("?");
//                        if (pos >= 0) {
//                            try {
//                                correctURL = new URL(correctURL.toString().substring(0, pos));
//                            } catch (MalformedURLException ex) {
//                                // NONE
//                            }
//                        }
//                    }
//                    // end of fix
//                    loadPage(correctURL);
                    if(e.getURL() == null && e.getDescription().startsWith("#")) {
                        processSharpLink(e);
                    }
                    else {
                        processGeneralLink(e);
                    }
                }
            }
            else if (et == HyperlinkEvent.EventType.ENTERED) {
                URL u = e.getURL();
                if (u != null) {
                    textPane.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
                    if(noteField != null) {
                        noteField.setText(u.toString());
                    }
                }
            }
            else if (et == HyperlinkEvent.EventType.EXITED) {
                textPane.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
                if(noteField != null) {
                    noteField.setText("");
                }
            }
        }

        private void processFrameLink(HyperlinkEvent e) {
            HTMLDocument doc = (HTMLDocument)
                ((JEditorPane) e.getSource()).getDocument();
            doc.processHTMLFrameHyperlinkEvent((HTMLFrameHyperlinkEvent) e);
        }

        private void processSharpLink(HyperlinkEvent e) {
            String desc = e.getDescription();
            if (!(desc.startsWith("#")))
                return;
            textPane.scrollToReference(desc.substring(1));
        }

        private void processGeneralLink(HyperlinkEvent e) {
            URL correctURL = e.getURL();
            HTMLDocument doc = (HTMLDocument)((JEditorPane)e.getSource()).getDocument();
            if(doc != null && currURL != null && !doc.getBase().equals(currURL))
                currURL = doc.getBase();
            // fix of CR 6451318, CR 6442782 and CR 6447246
            // JDTS use '?' notation to pass parameter (currently loaded page of one of frames)
            // to javascript.
            // JEditorPane doesn't allows javascript, so we delete this parameter and load
            // root page of help package
            if(correctURL.getProtocol().equals("file")) {
                int pos = correctURL.toString().indexOf("?");
                if (pos >= 0) {
                    try {
                        correctURL = new URL(correctURL.toString().substring(0, pos));
                    } catch (MalformedURLException ex) {
                        // NONE
                    }
                }
            }
            // end of fix
            loadPage(correctURL);
        }
    }




    private static final String SUPPORTED_MEDIA_RESOURCE_EXTENSIONS =
            ".wav .au .aif .mid .midi .rmf .jpeg .jpg .gif .png";
    private JScrollPane scrllBody;
    public static final int TEXT = 0;
    public static final int IMAGE = 1;
    public static final int AUDIO = 2;
    public static final int ERROR = 3;

    private File baseDir;
    private URL currURL;

    private TextPane textPane;
    private MusicPane musicPane;
    private ImagePane imagePane;
    private ErrorFormatPane errorPane;

    private UIFactory uif;
    private String uiKey;

    private Listener listener;

    private JTextField noteField;
    private NavigationPane navPane;

    private HashMap modesToPanes;
}


class TextPane extends JEditorPane implements MultiFormatPane.MediaPane {

    public TextPane(UIFactory uif, String uiKey, JScrollPane owner) {
        super();

        this.uif = uif;
        this.owner = owner;

        setName("text");
        setEditable(false);
        setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

        uif.setAccessibleInfo(this, uiKey);

        htmlKit = new HTMLEditorKit();
        defaultKit = new DefaultEditorKit();
        rtfKit = new RTFEditorKit();

    }

    public void changeURL(URL url) {}

    public void setParent(JScrollPane owner) {
        this.owner = owner;
    }

    public int getMode() {
        return MultiFormatPane.TEXT;
    }

    public void showText(String text, String MIME) {
        setContentType(MIME);

        EditorKit kit = getKitByMIME(MIME);
        Document doc = kit.createDefaultDocument();

        setDocument(doc);

        setText(text);

        showTextArea();
    }

    public void showText(URL url) {
        try {
            URL loaded = getPage();

            String mimeType = getMIMEType(url);
            if (mimeType == null) {
                mimeType = "text/plain";
            }

            boolean loadManually = false;
            if (mimeType.indexOf("plain") != -1) {
                loadManually = true;
            }

            EditorKit kit = getKitByMIME(mimeType);

            setContentType(mimeType);

            if (loaded == null || !loaded.sameFile(url)) {
                Document doc = kit.createDefaultDocument();
                setDocument(doc);
            }
            if (loadManually  && "file".equals(url.getProtocol())) {
                File file = new File(url.getFile());
                try {
                    Reader r = new BufferedReader(new FileReader(file));
                    read(r, url);
                    r.close();
                }
                catch (IOException e) {
                    uif.showError("mfp.load.error", new Object[] { url, e });
                }
            } else {
                setPage(url);
            }

            showTextArea();
        }
        catch (IOException e) {
            uif.showError("mfp.load.error", new Object[] { url, e });
        }
    }

    public static boolean isTextResource(URL url) {
        String mimeType = getMIMEType(url);
        if (mimeType == null)
            return false;
        return (mimeType.equals("text/plain") || mimeType.equals("text/html") ||
                mimeType.equals("text/rtf"));
    }

    public static String getMIMEType(URL url) {
        String filename = url.getFile();
        String ext = filename.substring(filename.lastIndexOf('.') + 1);
        ext = ext.toLowerCase();

        return (String)extensionsToMIME.get(ext);
    }

    public void showTextArea() {
        owner.setViewportView(this);
        owner.revalidate();
        owner.repaint();
    }

    private EditorKit getKitByMIME(String mime) {
        if(mime.indexOf("rtf") != -1)
            return rtfKit;
        else if(mime.indexOf("html") != -1)
            return htmlKit;
        else {
            return defaultKit;
        }
    }

    private JScrollPane owner;
    private UIFactory uif;

    private HTMLEditorKit htmlKit;
    private DefaultEditorKit defaultKit;
    private RTFEditorKit rtfKit;


    private static HashMap extensionsToMIME;
    static {
        extensionsToMIME = new HashMap();
        extensionsToMIME.put("html", "text/html");
        extensionsToMIME.put("htm", "text/html");
        extensionsToMIME.put("htmls", "text/html");
        extensionsToMIME.put("htx", "text/html");
        extensionsToMIME.put("shtml", "text/html");
        extensionsToMIME.put("stm", "text/html");

        extensionsToMIME.put("text", "text/plain");
        extensionsToMIME.put("txt", "text/plain");
        extensionsToMIME.put("log", "text/plain");
        extensionsToMIME.put("list", "text/plain");
        extensionsToMIME.put("lst", "text/plain");
        extensionsToMIME.put("java", "text/plain");
        extensionsToMIME.put("xml", "text/plain");
        extensionsToMIME.put("jtr", "text/plain");
        extensionsToMIME.put("jti", "text/plain");
        extensionsToMIME.put("jtm", "text/plain");
        extensionsToMIME.put("css", "text/plain");

        extensionsToMIME.put("rtf", "text/rtf");
        extensionsToMIME.put("rtx", "text/rtf");

    }


}

class MusicPane extends JPanel implements MultiFormatPane.MediaPane {
    public MusicPane(UIFactory uif, String uiKey, JScrollPane owner) {
        super();

        this.uif = uif;
        this.owner = owner;

        initGUI(uiKey);
    }

    private void initGUI(String uiKey) {
        setName(uiKey);
        uif.setAccessibleInfo(this, uiKey);

        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();

        btnStart = uif.createButton(uiKey + ".btnStart");
        btnStop = uif.createButton(uiKey + ".btnStop");
        btnLoop = uif.createButton(uiKey + ".btnLoop");

        add(btnStart, gbc);
        add(btnStop, gbc);
        add(btnLoop, gbc);

        btnStart.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if(isSampledAudioResource(currURL)) {
                    loadSample(currURL);
                    clip.start();
                }
                else if(isMidiAudioResource(currURL)) {
                    loadSequence(currURL);
                    sequencer.start();
                }
            }
        });

        btnStop.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                stopAudio();
            }
        });

        btnLoop.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if(isSampledAudioResource(currURL)) {
                    loadSample(currURL);
                    clip.loop(Clip.LOOP_CONTINUOUSLY);
                }
            }
        });

    }

    public void showAudio(URL url) {
        changeURL(url);

        owner.setViewportView(this);
        owner.revalidate();
        owner.repaint();
    }

    public void changeURL(URL url) {
        currURL = url;

        if(isMidiAudioResource(url)) {
            btnLoop.setEnabled(false);
        }
        else if(isSampledAudioResource(url)) {
            btnLoop.setEnabled(true);
        }

    }

    public void setParent(JScrollPane owner) {
        this.owner = owner;
    }

    public int getMode() {
        return MultiFormatPane.AUDIO;
    }

    public static boolean isAudioResource(URL url) {
        return isSampledAudioResource(url) || isMidiAudioResource(url);
    }

    public void stopAudio() {
        if(clip != null && clip.isRunning()) {
            clip.stop();
            clip.flush();
            clip.close();
        }
        if(sequencer != null && sequencer.isRunning())
            sequencer.stop();
    }

    private void loadSample(URL url) {
        try {
            AudioInputStream stream = AudioSystem.getAudioInputStream(url);
            AudioFormat format = stream.getFormat();

            DataLine.Info info = new DataLine.Info(
                Clip.class, stream.getFormat(), ((int)stream.getFrameLength()*format.getFrameSize()));

            clip = (Clip) AudioSystem.getLine(info);
            clip.open(stream);
            clip.addLineListener(new LineListener() {
               public void update(LineEvent e) {
                   if(e.getType() == LineEvent.Type.STOP) {
                       clip.stop();
                   }
               }
            });
        } catch (Exception e) {
            clip.close();
        }
    }

    private void loadSequence(URL url) {
        try {
            Sequence sequence = MidiSystem.getSequence(url);

            // Create a sequencer for the sequence
            sequencer = MidiSystem.getSequencer();
            sequencer.open();
            sequencer.setSequence(sequence);

        } catch (Exception e) {}

    }

    private static boolean isSampledAudioResource(URL url) {
        try{
            AudioFileFormat fformat = AudioSystem.getAudioFileFormat(url);
            return AudioSystem.isFileTypeSupported(fformat.getType());
        } catch (UnsupportedAudioFileException unsuppExc) {
            return false;
        } catch (IOException ioExc) {
            return false;
        }
    }

    private static boolean isMidiAudioResource(URL url) {
        try {
            MidiFileFormat fformat = MidiSystem.getMidiFileFormat(url);
            Sequence sequence = MidiSystem.getSequence(url);
            return MidiSystem.isFileTypeSupported(fformat.getType());
        } catch (InvalidMidiDataException invalidDataExc) {
            return false;
        } catch (IOException ioExc) {
            return false;
        }
        catch (Exception exc) {
            return false;
        }
    }


    private UIFactory uif;
    private JScrollPane owner;

    private JButton btnStart;
    private JButton btnStop;
    private JButton btnLoop;

    private URL currURL;
    private Clip clip;
    private Sequencer sequencer;

}

class ImagePane extends JLabel implements MultiFormatPane.MediaPane {

    public ImagePane(UIFactory uif, String uiKey, JScrollPane owner) {
        super(uif.getI18NString(uiKey + ".lbl"));
//        setName(uiKey);

        this.owner = owner;
    }

    public void changeURL(URL url) {}

    public void setParent(JScrollPane owner) {
        this.owner = owner;
    }

    public int getMode() {
        return MultiFormatPane.IMAGE;
    }

    public void showImage(URL url) {
        if(isImageFormatSupported(url)) {
            ImageIcon img = new ImageIcon(url);
            setIcon(img);

            owner.setViewportView(this);
            owner.revalidate();
            owner.repaint();
        }
    }

    public static boolean isImageResource(URL url) {
        String file = url.getFile();
        String ext = file.substring(file.lastIndexOf('.')+1);
        Iterator iter = ImageIO.getImageReadersBySuffix(ext);
        return iter.hasNext();
    }

    public static boolean isImageFormatSupported(URL url) {
        try {
            ImageInputStream iis = ImageIO.createImageInputStream(new File(url.getFile()));
            Iterator iter = ImageIO.getImageReaders(iis);
            if(!iter.hasNext())
                return false;
        } catch (IOException exc) {
            exc.printStackTrace();
            return false;
        }
        return true;
    }

    private JScrollPane owner;
}

class ErrorFormatPane extends JPanel implements MultiFormatPane.MediaPane {
    public ErrorFormatPane(UIFactory uif, String uiKey, JScrollPane owner) {
        super();
        uif.initPanel(this, uiKey, true);

        this.owner = owner;

        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.anchor = gbc.CENTER;
        errorLabel = uif.createLabel("mfp.errorPaneLbl", true);
        add(errorLabel, gbc);

    }

    public void changeURL(URL url) {}

    public void setParent(JScrollPane owner) {
        this.owner = owner;
    }

    public int getMode() {
        return MultiFormatPane.ERROR;
    }

    public void showError(String errorMessage) {
        errorLabel.setText(errorMessage);

        owner.setViewportView(this);
        owner.revalidate();
        owner.repaint();
    }

    private JLabel errorLabel;
    private JScrollPane owner;
}
