/*
 * @(#)ViewRegistry.java  1.3  2009-12-22
 *
 * Copyright (c) 2005-2009 Werner Randelshofer, Immensee, Switzerland.
 * All rights reserved.
 *
 * You may not use, copy or modify this file, except in compliance with the
 * license agreement you entered into with Werner Randelshofer.
 * For details see accompanying license terms.
 */
package ch.randelshofer.multishow;

import com.sun.media.util.Registry;
import ch.randelshofer.activation.*;
import ch.randelshofer.io.*;
import org.monte.media.jpeg.CMYKJPEGImageReaderSpi;
import org.monte.media.mpo.MPOImageReaderSpi;
import org.monte.media.pgm.PGMImageReaderSpi;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.OptionalDataException;

import java.util.*;
import javax.activation.*;
import javax.imageio.ImageIO;
import javax.imageio.spi.IIORegistry;
import javax.imageio.spi.ImageReaderSpi;
import javax.media.Manager;
import javax.swing.filechooser.FileFilter;
import org.monte.media.jmf.jpeg.MJPGImageReaderSpi;

/**
 * ViewRegistry.
 *
 * @author  Werner Randelshofer
 * @version 1.3 2009-12-22 Removed QuickTime for Java support.
 * <br>1.2 2006-07-23 Support for jffmpeg added.
 * <br>1.1 2005-01-09 RIFFRecognizer added.
 * <br>1.0  04 January 2005  Created.
 */
public class ViewRegistry {

    private static boolean isInitialized = false;

    public static void init() {
        if (!isInitialized) {
            isInitialized = true;
            initJMF();
            initJAI();
        }
    }
    /**
     * Maps FileFilter's of the file chooser to CommandInfo's.
     */
    private Map<FileFilter, CommandInfo> fileFilterMap;
    private boolean isViewsRegistered = false;

    /**
     * Returns a HashMap which maps FileFilter's to CommandInfo's.
     */
    public Map<FileFilter, CommandInfo> getFileFilterMap() {
        if (fileFilterMap == null) {
            fileFilterMap = new TreeMap<FileFilter, CommandInfo>();
            fileFilterMap.put(new AcceptAllFileFilter("Audio"), new CommandInfo("view", "ch.randelshofer.view.AudioView"));
            fileFilterMap.put(new AcceptAllFileFilter("Audio IFF 8SVX"), new CommandInfo("view", "ch.randelshofer.view.EightSVXView"));
            fileFilterMap.put(new AcceptAllFileFilter("Archive ZIP"), new CommandInfo("view", "ch.randelshofer.view.ZipView"));
            fileFilterMap.put(new AcceptAllFileFilter("Binary"), new CommandInfo("view", "ch.randelshofer.view.BinaryView"));
            fileFilterMap.put(new AcceptAllFileFilter("Image"), new CommandInfo("view", "ch.randelshofer.view.ImageView"));
            fileFilterMap.put(new AcceptAllFileFilter("Image IFF ILBM"), new CommandInfo("view", "ch.randelshofer.view.ILBMView"));
            fileFilterMap.put(new AcceptAllFileFilter("Image Javax Image IO (IIO)"), new CommandInfo("view", "ch.randelshofer.view.ImageIOView"));
            fileFilterMap.put(new AcceptAllFileFilter("Image Java Advanced Imaging (JAI)"), new CommandInfo("view", "ch.randelshofer.view.JAIView"));
            fileFilterMap.put(new AcceptAllFileFilter("Struct IFF"), new CommandInfo("view", "ch.randelshofer.view.IFFStructView"));
            fileFilterMap.put(new AcceptAllFileFilter("Struct JFIF"), new CommandInfo("view", "ch.randelshofer.view.JFIFStructView"));
            fileFilterMap.put(new AcceptAllFileFilter("Struct QuickTime"), new CommandInfo("view", "ch.randelshofer.view.QuickTimeStructView"));
            fileFilterMap.put(new AcceptAllFileFilter("Struct RIFF"), new CommandInfo("view", "ch.randelshofer.view.RIFFStructView"));
            fileFilterMap.put(new AcceptAllFileFilter("Text HTML"), new CommandInfo("view", "ch.randelshofer.view.HTMLView"));
            fileFilterMap.put(new AcceptAllFileFilter("Text PDF (JPDF)"), new CommandInfo("view", "ch.randelshofer.view.JPDFView"));
            fileFilterMap.put(new AcceptAllFileFilter("Text PDF (Adobe Acrobat)"), new CommandInfo("view", "ch.randelshofer.view.AdobeAcrobatPDFView"));
            fileFilterMap.put(new AcceptAllFileFilter("Text Rich Text (RTF)"), new CommandInfo("view", "ch.randelshofer.view.RTFView"));
            fileFilterMap.put(new AcceptAllFileFilter("Text Plain"), new CommandInfo("view", "ch.randelshofer.view.TextView"));
            fileFilterMap.put(new AcceptAllFileFilter("Video IFF ANIM"), new CommandInfo("view", "ch.randelshofer.view.ANIMVideoView"));
            fileFilterMap.put(new AcceptAllFileFilter("Video Java Media Framework (JMF)"), new CommandInfo("view", "ch.randelshofer.view.JMFVideoView"));
        }
        return fileFilterMap;
    }

    public CommandInfo getCommandInfo(javax.swing.filechooser.FileFilter filter) {
        return (filter == null || !(filter instanceof AcceptAllFileFilter))
                ? null
                : (CommandInfo) getFileFilterMap().get(filter);
    }

    /**
     * Makes all viewers known to the JavaBeans Activation Framework JAF.
     */
    protected synchronized void registerViews() {
        init();
        if (isViewsRegistered) {
            return;
        }
        isViewsRegistered = true;

        try {
            com.sun.media.codec.audio.mp3.JavaDecoder.main(new String[0]);
        } catch (Throwable t) {
            t.printStackTrace();
        }

        HierarchicCommandMap cm = new HierarchicCommandMap();

        // Add commands as specified by the commandmap.txt file
        try {
            InputStream in = ViewRegistry.class.getResourceAsStream("commandmap.txt");
            if (in != null) {
                cm.addCommands(new BufferedReader(new InputStreamReader(in, "UTF-8")));
                in.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }


        // Create file type maps
        // ---------------------
        MultiFileTypeMap multiMap = new MultiFileTypeMap();

        // Create map with strong file magic recognizers
        MultiRecognizer multiRecognizer = new MultiRecognizer();
        multiRecognizer.add(IFFRecognizer.getInstance());
        multiRecognizer.add(RIFFRecognizer.getInstance());
        multiRecognizer.add(AmigaGuideRecognizer.getInstance());
        multiRecognizer.add(ZipRecognizer.getInstance());
        multiRecognizer.add(MagicRecognizer.getInstance());
        RecognizerFileTypeMap recognizerMap = new RecognizerFileTypeMap();
        recognizerMap.setRecognizer(multiRecognizer);
        multiMap.add(recognizerMap);

        // Create map with strong mimetypes map
        MimetypesFileTypeMap mimeMap;
        InputStream in = null;
        try {
            in = ViewRegistry.class.getResourceAsStream("mimetypes.txt");
            mimeMap = new MimetypesFileTypeMap(in);
        } catch (NullPointerException e) {
            mimeMap = new MimetypesFileTypeMap();
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                // Should never happen, if ViewRegistry is bundled correctly
                e.printStackTrace();
            }
        }

        multiMap.add(mimeMap);

        // Create map with weak magic recognizers
        multiRecognizer = new MultiRecognizer();
        multiRecognizer.add(JAIRecognizer.getInstance());
        multiRecognizer.add(new URLConnectionRecognizer());
        recognizerMap = new RecognizerFileTypeMap();
        recognizerMap.setRecognizer(multiRecognizer);
        multiMap.add(recognizerMap);

        // Set file type maps in JAF
        // --------------------------
        CommandMap.setDefaultCommandMap(cm);
        FileTypeMap.setDefaultFileTypeMap(multiMap);
    }

    /** JAI does not always pick up my ImageReaderSpi file. */
    public static void initJAI() {
        IIORegistry r = IIORegistry.getDefaultInstance();
        r.registerServiceProvider(new PGMImageReaderSpi(), ImageReaderSpi.class);
        r.registerServiceProvider(new MPOImageReaderSpi(), ImageReaderSpi.class);
        r.registerServiceProvider(new MJPGImageReaderSpi(), ImageReaderSpi.class);
        r.registerServiceProvider(new CMYKJPEGImageReaderSpi(), ImageReaderSpi.class);

        // Improves performance of TGA image reader
        ImageIO.setUseCache(false);

    }

    public static boolean initJMF() {
        boolean success = false;
        InputStream in = null;
        try {
            in = ViewRegistry.class.getResourceAsStream("/jmf.properties");
            success = readJMFRegistry(in);
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                }
            }
        }
        
        Manager.setHint(Manager.LIGHTWEIGHT_RENDERER, true);

        return success;
    }

    private static final boolean readJMFRegistry(InputStream ris) {
        if (ris == null) {
            return false;
        }

        try {
            ObjectInputStream ois = new ObjectInputStream(ris);

            int tableSize = ois.readInt();
            int version = ois.readInt();
            if (version > 200) {
                System.err.println("Version number mismatch.\nThere could be"
                        + " errors in reading the registry");
            }
            HashMap<String, Object> hash = new HashMap<String, Object>();
            for (int i = 0; i < tableSize; i++) {
                String key = ois.readUTF();
                boolean failed = false;
                byte[] serObject;
                try {
                    Object value = ois.readObject();
                    hash.put(key, value);
                } catch (ClassNotFoundException cnfe) {
                    failed = true;
                } catch (OptionalDataException ode) {
                    failed = true;
                }
            }
            ois.close();
            ris.close();
            for (Map.Entry<String, Object> entry : hash.entrySet()) {
                /*
                if (entry.getValue() instanceof Object[]) {
                System.out.println("ViewRegistry.readJMFRegistry " + entry.getKey() + "=" + Arrays.asList(entry.getValue()));
                } else {
                System.out.println("ViewRegistry.readJMFRegistry " + entry.getKey() + "=" + entry.getValue());
                }*/
                Registry.set(entry.getKey(), entry.getValue());
            }

        } catch (IOException ioe) {
            System.err.println("IOException in ViewRegistry.readJMFRegistry: " + ioe);
            return false;
        } catch (Throwable t) {
            System.err.println("Throwable in ViewRegistry.readJMFRegistry: " + t);
            t.printStackTrace();
            return false;
        }

        return true;
    }
}
