/*
 * $RCSfile: SerializerImpl.java,v $
 *
 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
 *
 * Use is subject to license terms.
 *
 * $Revision: 1.1 $
 * $Date: 2005/02/11 04:56:55 $
 * $State: Exp $
 */
package com.lightcrafts.media.jai.rmi;

import java.awt.RenderingHints;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import com.lightcrafts.mediax.jai.remote.RemoteImagingException;
import com.lightcrafts.mediax.jai.remote.SerializableState;
import com.lightcrafts.mediax.jai.remote.Serializer;
import com.lightcrafts.mediax.jai.remote.SerializerFactory;
import com.lightcrafts.mediax.jai.util.ImagingException;
import com.lightcrafts.mediax.jai.util.ImagingListener;
import com.lightcrafts.media.jai.util.ImageUtil;

/**
 * Framework class for automatically creating <code>Serializer</code>s
 * for <code>SerializableStateImpl</code> subclasses. Each subclass of
 * <code>SerializableStateImpl</code> should add a statement like
 * <pre>
 *       registerSerializers(MySerializableState.class);
 * </pre>
 * to the no-argument version of <code>registerSerializers()</code>.
 * This latter method is invoked by the static initializer of
 * <code>SerializerFactory</code>.
 *
 * @since 1.1
 */
public final class SerializerImpl implements Serializer {
    private Class theClass;
    private boolean areSubclassesPermitted;
    private Constructor ctor;

    /**
     * Registers all known <code>Serializer</code>s with the
     * <code>SerializerFactory</code>.
     */
    public static final void registerSerializers() {
        registerSerializers(ColorModelState.class);
        registerSerializers(DataBufferState.class);
        registerSerializers(HashSetState.class);
        registerSerializers(HashtableState.class);
        registerSerializers(RasterState.class);
        registerSerializers(RenderedImageState.class);
        registerSerializers(RenderContextState.class);
        registerSerializers(RenderingHintsState.class);
        registerSerializers(RenderingKeyState.class);
        registerSerializers(SampleModelState.class);
        registerSerializers(VectorState.class);
        registerSerializers(ShapeState.class);
    }

    private static void registerSerializers(Class ssi) {
        if(ssi == null) {
            throw new IllegalArgumentException(JaiI18N.getString("Generic0"));
        }

        if(!SerializableStateImpl.class.isAssignableFrom(ssi)) {
            throw new IllegalArgumentException(JaiI18N.getString("SerializerImpl0"));
        }

        ImagingListener listener =
            ImageUtil.getImagingListener((RenderingHints)null);
        Class[] classes = null;
        try {
            Method m1 = ssi.getMethod("getSupportedClasses", null);
            classes = (Class[])m1.invoke(null, null);
        } catch(java.lang.NoSuchMethodException e) {
            String message = JaiI18N.getString("SerializerImpl1");
            listener.errorOccurred(message,
                                   new RemoteImagingException(message, e),
                                   SerializerImpl.class, false);
        } catch (java.lang.IllegalAccessException e) {
            String message = JaiI18N.getString("SerializerImpl1");
            listener.errorOccurred(message,
                                   new RemoteImagingException(message, e),
                                   SerializerImpl.class, false);
        } catch (java.lang.reflect.InvocationTargetException e) {
            String message = JaiI18N.getString("SerializerImpl1");
            listener.errorOccurred(message,
                                   new RemoteImagingException(message, e),
                                   SerializerImpl.class, false);
        }

        boolean supportsSubclasses = false;
        try {
            Method m2 = ssi.getMethod("permitsSubclasses", null);
            Boolean b = (Boolean)m2.invoke(null, null);
            supportsSubclasses = b.booleanValue();
        } catch(java.lang.NoSuchMethodException e) {
            String message = JaiI18N.getString("SerializerImpl4");
            listener.errorOccurred(message,
                                   new RemoteImagingException(message, e),
                                   SerializerImpl.class, false);
        } catch (java.lang.IllegalAccessException e) {
            String message = JaiI18N.getString("SerializerImpl4");
            listener.errorOccurred(message,
                                   new RemoteImagingException(message, e),
                                   SerializerImpl.class, false);
        } catch (java.lang.reflect.InvocationTargetException e) {
            String message = JaiI18N.getString("SerializerImpl4");
            listener.errorOccurred(message,
                                   new RemoteImagingException(message, e),
                                   SerializerImpl.class, false);
        }

        int numClasses = classes.length;
        for(int i = 0; i < numClasses; i++) {
            Serializer s = new SerializerImpl(ssi, classes[i],
                                              supportsSubclasses);
            SerializerFactory.registerSerializer(s);
        }
    }

    /**
     * Constructs a <code>SerializerImpl</code>.  The parameter <code>c</code>
     * is saved by reference.  The parameter <code>c</code> is used to
     * determine the standard <code>SerializableStateImpl</code> constructor
     * which is saved by reference.  The supplied parameters are not checked
     * as this class should never be instantiated except from within
     * <code>registerSerializers(Class)</code>.
     */
    protected SerializerImpl(Class ssi, // SerializableStateImpl subclass
                             Class c,
                             boolean areSubclassesPermitted) {
        theClass = c;
        this.areSubclassesPermitted = areSubclassesPermitted;

        try {
            Class[] paramTypes = new Class[] {Class.class,
                                              Object.class,
                                              RenderingHints.class};
            ctor = ssi.getConstructor(paramTypes);
        } catch(java.lang.NoSuchMethodException e) {
            String message =
                theClass.getName()+": "+ JaiI18N.getString("SerializerImpl2");
            sendExceptionToListener(message,
                                    new RemoteImagingException(message, e));
        }
    }

    /**
     * Creates a <code>SerializableState</code> using the
     * <code>SerializableStateImpl</code> subclass constructor obtained
     * by reflection.
     */
    public SerializableState getState(Object o, RenderingHints h) {
        Object state = null;
        try {
            state = ctor.newInstance(new Object[] {theClass, o, h});
        } catch(InstantiationException e) {
            String message =
                theClass.getName()+": "+ JaiI18N.getString("SerializerImpl3");
            sendExceptionToListener(message,
                                    new RemoteImagingException(message, e));
        } catch (IllegalAccessException e) {
            String message =
                theClass.getName()+": "+ JaiI18N.getString("SerializerImpl3");
            sendExceptionToListener(message,
                                    new RemoteImagingException(message, e));
        } catch (java.lang.reflect.InvocationTargetException e) {
            String message =
                theClass.getName()+": "+ JaiI18N.getString("SerializerImpl3");
            sendExceptionToListener(message,
                                    new RemoteImagingException(message, e));
        }

        return (SerializableState)state;
    }

    public Class getSupportedClass() {
        return theClass;
    }

    public boolean permitsSubclasses() {
        return areSubclassesPermitted;
    }

    private void sendExceptionToListener(String message, Exception e) {
        ImagingListener listener =
            ImageUtil.getImagingListener((RenderingHints)null);
        listener.errorOccurred(message,
                               new ImagingException(message, e),
                               this, false);
    }
}

