/*
 * $RCSfile: MlibAffineTableOpImage.java,v $
 *
 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
 *
 * Use is subject to license terms.
 *
 * $Revision: 1.3 $
 * $Date: 2005/12/15 18:35:46 $
 * $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 com.lightcrafts.mediax.jai.InterpolationTable;
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 an Affine using interpolation coefficients
 * represented in a Table, on a source image.
 *
 */
public class MlibAffineTableOpImage extends MlibAffineOpImage {

    /**
     * Creates a MlibAffineTableOpImage 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 (Table-based)
     */
    public MlibAffineTableOpImage(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) {

        // Cast the Interpolation object to InterpolationTable object
        InterpolationTable jtable = (InterpolationTable)interp;

        // The Medialib InterpolationTable class equivalent
        mediaLibImageInterpTable mlibInterpTable;

        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:
            mlibInterpTable =
                new mediaLibImageInterpTable(Constants.MLIB_INT,
                                             jtable.getWidth(),
                                             jtable.getHeight(),
                                             jtable.getLeftPadding(),
                                             jtable.getTopPadding(),
                                             jtable.getSubsampleBitsH(),
                                             jtable.getSubsampleBitsV(),
                                             jtable.getPrecisionBits(),
                                             jtable.getHorizontalTableData(),
                                             jtable.getVerticalTableData());

	    srcML = srcAccessor.getMediaLibImages();
	    dstML = dstAccessor.getMediaLibImages();

            if (setBackground)
                Image.AffineTable2(dstML[0],
                                   srcML[0],
                                   medialib_tr,
                                   mlibInterpTable,
                                   Constants.MLIB_EDGE_DST_NO_WRITE,
                                   intBackgroundValues);
            else
                Image.AffineTable(dstML[0],
                                  srcML[0],
                                  medialib_tr,
                                  mlibInterpTable,
                                  Constants.MLIB_EDGE_DST_NO_WRITE);
            MlibUtils.clampImage(dstML[0], getColorModel());
            break;

        case DataBuffer.TYPE_FLOAT:
             mlibInterpTable =
                new mediaLibImageInterpTable(Constants.MLIB_FLOAT,
                                             jtable.getWidth(),
                                             jtable.getHeight(),
                                             jtable.getLeftPadding(),
                                             jtable.getTopPadding(),
                                             jtable.getSubsampleBitsH(),
                                             jtable.getSubsampleBitsV(),
                                             jtable.getPrecisionBits(),
                                             jtable.getHorizontalTableDataFloat(),
                                             jtable.getVerticalTableDataFloat());

            srcML = srcAccessor.getMediaLibImages();
	    dstML = dstAccessor.getMediaLibImages();

            if (setBackground)
                Image.AffineTable2_Fp(dstML[0],
                                      srcML[0],
                                      medialib_tr,
                                      mlibInterpTable,
                                      Constants.MLIB_EDGE_DST_NO_WRITE,
                                      backgroundValues);
            else
                Image.AffineTable_Fp(dstML[0],
                                     srcML[0],
                                     medialib_tr,
                                     mlibInterpTable,
                                     Constants.MLIB_EDGE_DST_NO_WRITE);
	    break;

        case DataBuffer.TYPE_DOUBLE:
             mlibInterpTable =
                new mediaLibImageInterpTable(Constants.MLIB_DOUBLE,
                                             jtable.getWidth(),
                                             jtable.getHeight(),
                                             jtable.getLeftPadding(),
                                             jtable.getTopPadding(),
                                             jtable.getSubsampleBitsH(),
                                             jtable.getSubsampleBitsV(),
                                             jtable.getPrecisionBits(),
                                             jtable.getHorizontalTableDataDouble(),
                                             jtable.getVerticalTableDataDouble());

	    srcML = srcAccessor.getMediaLibImages();
	    dstML = dstAccessor.getMediaLibImages();

            if (setBackground)
                Image.AffineTable2_Fp(dstML[0],
                                      srcML[0],
                                      medialib_tr,
                                      mlibInterpTable,
                                      Constants.MLIB_EDGE_DST_NO_WRITE,
                                      backgroundValues);
            else
                Image.AffineTable_Fp(dstML[0],
                                     srcML[0],
                                     medialib_tr,
                                     mlibInterpTable,
                                     Constants.MLIB_EDGE_DST_NO_WRITE);
	    break;

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

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