/*
 * $RCSfile: MlibAffineNearestOpImage.java,v $
 *
 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
 *
 * Use is subject to license terms.
 *
 * $Revision: 1.2 $
 * $Date: 2005/11/14 22:45:29 $
 * $State: Exp $
 */
package com.lightcrafts.media.jai.mlib;
import java.awt.Rectangle;
import java.awt.image.DataBuffer;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.WritableRaster;
import java.awt.geom.AffineTransform;
import com.lightcrafts.mediax.jai.ImageLayout;
import com.lightcrafts.mediax.jai.Interpolation;
import java.util.Map;
import com.lightcrafts.mediax.jai.BorderExtender;
import com.sun.medialib.mlib.*;

// import com.lightcrafts.media.jai.test.OpImageTester;

/**
 * An OpImage class to perform Nearest-Neighbour AffineTransform
 * on a source image.
 *
 */
public class MlibAffineNearestOpImage extends MlibAffineOpImage {

    /**
     * Creates a MlibAffineNearestOpImage given a ParameterBlock containing the
     * image source and the AffineTransform.  The image dimensions are derived
     * from the source image.  The tile grid layout, SampleModel, and
     * ColorModel may optionally be specified by an ImageLayout
     * object.
     *
     * @param source a RenderedImage.
     * @param layout an ImageLayout optionally containing the tile grid layout,
     *        SampleModel, and ColorModel, or null.
     * @param tr the AffineTransform.
     * @param interp the Interpolation to be used (Nearest-Neighbour)
     */
    public MlibAffineNearestOpImage(RenderedImage source,
				    BorderExtender extender,
				    Map config,
                                    ImageLayout layout,
                                    AffineTransform tr,
                                    Interpolation interp,
                                    double[] backgroundValues) {
	super(source,
              layout,
              config,
	      extender,
              tr,
              interp,
              backgroundValues);
    }

    /**
     * Performs nearest-neighbour affine transformation on a specified
     * rectangle.  The sources are cobbled.
     *
     * @param sources an array of source Rasters, guaranteed to provide all
     *                necessary source data for computing the output.
     * @param dest a WritableRaster tile containing the area to be computed.
     * @param destRect the rectangle within dest to be processed.
     */
    protected void computeRect(Raster[] sources,
                               WritableRaster dest,
                               Rectangle destRect) {

        Raster source = sources[0];
        Rectangle srcRect = source.getBounds();

        int formatTag = MediaLibAccessor.findCompatibleTag(sources,dest);

        MediaLibAccessor srcAccessor =
            new MediaLibAccessor(source,srcRect,formatTag);
        MediaLibAccessor dstAccessor =
            new MediaLibAccessor(dest,destRect,formatTag);

        //
        // The AffineTransform needs to be readjusted as per the
        // location of the current source & destination rectangles
        //

        // Clone the global transform so as not to write to an instance
        // variable as this method may be called from different threads.
        double[] medialib_tr = (double[])this.medialib_tr.clone();

        medialib_tr[2] = m_transform[0] * srcRect.x +
            m_transform[1] * srcRect.y +
            m_transform[2] -
            destRect.x;
        medialib_tr[5] = m_transform[3] * srcRect.x +
            m_transform[4] * srcRect.y +
            m_transform[5] -
            destRect.y;

	mediaLibImage srcML[], dstML[];

        switch (dstAccessor.getDataType()) {
        case DataBuffer.TYPE_BYTE:
        case DataBuffer.TYPE_USHORT:
        case DataBuffer.TYPE_SHORT:
        case DataBuffer.TYPE_INT:
	    srcML = srcAccessor.getMediaLibImages();
	    dstML = dstAccessor.getMediaLibImages();

            if (setBackground)
                Image.Affine2(dstML[0],
                              srcML[0],
                              medialib_tr,
                              Constants.MLIB_NEAREST,
                              Constants.MLIB_EDGE_DST_NO_WRITE,
                              intBackgroundValues);
            else
                Image.Affine(dstML[0],
                             srcML[0],
                             medialib_tr,
                             Constants.MLIB_NEAREST,
                             Constants.MLIB_EDGE_DST_NO_WRITE);
            break;

        case DataBuffer.TYPE_FLOAT:
        case DataBuffer.TYPE_DOUBLE:
	    srcML = srcAccessor.getMediaLibImages();
	    dstML = dstAccessor.getMediaLibImages();

            if (setBackground)
                Image.Affine2_Fp(dstML[0],
				 srcML[0],
                                 medialib_tr,
                                 Constants.MLIB_NEAREST,
                                 Constants.MLIB_EDGE_DST_NO_WRITE,
                                 backgroundValues);
            else
                Image.Affine_Fp(dstML[0],
                                srcML[0],
                                medialib_tr,
                                Constants.MLIB_NEAREST,
                                Constants.MLIB_EDGE_DST_NO_WRITE);
	    break;

        default:
            String className = this.getClass().getName();
            throw new RuntimeException(JaiI18N.getString("Generic2"));
        }

        if (dstAccessor.isDataCopy()) {
            dstAccessor.copyDataToRaster();
        }
    }

//     public static OpImage createTestImage(OpImageTester oit) {
// 	Interpolation interp = new InterpolationNearest();
//         AffineTransform tr = new AffineTransform(0.707107,
//                                                  -0.707106,
//                                                  0.707106,
//                                                  0.707107,
//                                                  0.0,
//                                                  0.0);
//         return new MlibAffineNearestOpImage(oit.getSource(), null,
//                                             new ImageLayout(oit.getSource()),
//                                             tr,
//                                             interp);
//     }

//     // Calls a method on OpImage that uses introspection, to make this
//     // class, discover it's createTestImage() call, call it and then
//     // benchmark the performance of the created OpImage chain.
//     public static void main (String args[]) {
//         String classname = "com.lightcrafts.media.jai.mlib.MlibAffineNearestOpImage";
//         OpImageTester.performDiagnostics(classname, args);
//     }
}
