/*
 * @(#)JAIRecognizer.java  1.2  2006-07-20
 *
 * Copyright (c) 1999-2006 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.activation;

import com.sun.media.jai.codec.ImageCodec;

import java.io.*;
import java.net.*;
import java.util.Enumeration;

/**
 * This content type detector uses the JAI (Java Advanced Imaging API)
 * to detect file types.
 *
 * @author  Werner Randelshofer, Hausmatt 10, CH-6405 Immensee, Switzerland.
 * @version 1.2 2006-07-20 Reworked for Java 1.5.
 * <br>1.1 2002-02-12 Return application/octet-stream' for unknown file types.
 * <br>1.0.1  1999-13-12  Macintosh Runtime for Java crashes when
 *                                the Java advanced Imaging API is not available.
 *<br>history  1.0  1998-10-19
 */
public class JAIRecognizer
implements Recognizer {
    private int numHeaderBytes = -1;
    private static boolean error = false;
    private static JAIRecognizer instance;
    
    protected JAIRecognizer() {
    }
    
    public synchronized static JAIRecognizer getInstance() {
        // create the instance lazily.
        if (instance == null) {
            instance = new JAIRecognizer();
            
            try {
                Class.forName("com.sun.media.jai.codec.ImageCodec");
            } catch (Throwable e) {
                error = true;
            }
        }
        return instance;
    }
    
    
    /**
     * Return the number of bytes needed to
     * determine the content type.
     */
    public int getMinimalDeterminableDataLength() {
        if (error) {
            return 0;
        }
        
        try {
            if (numHeaderBytes == -1) {
                Enumeration enm = ImageCodec.getCodecs();
                while (enm.hasMoreElements()) {
                    numHeaderBytes = Math.max(numHeaderBytes, ((ImageCodec) enm.nextElement()).getNumHeaderBytes());
                }
            }
            return numHeaderBytes;
        } catch (Throwable e) {
            error = true;
            return 0;
        }
    }
    
    /**
     * Return the base MIME Type of this data. This method is
     * expected to ALWAYS return a valid (non-null) MIME Type.
     *
     * @param  dataSnippet the first few bytes of the data file.
     * @return MIME Type or application/octet-stream' if content type
     * can not be determined.
     */
    public String getContentType(byte[] dataSnippet) {
        try {
            if (! error) {
                ImageCodec codec = getCodec(dataSnippet);
                if (codec != null) {
                    return "image/"+codec.getFormatName();
                }
            }
        } catch (Error e) {
            error = true;
        }
        
        return Recognizer.CONTENT_TYPE_OCTET_STREAM;
    }
    
    public ImageCodec getCodec(byte[] dataSnippet) {
        try {
            if (! error) {
                Enumeration enm = ImageCodec.getCodecs();
                while (enm.hasMoreElements()) {
                    ImageCodec codec = (ImageCodec) enm.nextElement();
                    if (codec.isFormatRecognized(dataSnippet)) {
                        return codec;
                    }
                }
            }
        } catch (Error e) {
            error = true;
        }
        return null;
    }
}
