package ij.process;
import java.awt.*;

/** This class does bit blitting of byte images. */
public class ByteBlitter implements Blitter {

    private ByteProcessor ip;
    private int width, height;
    private byte[] pixels;
    private int transparent = 255;
    
    /** Constructs a ByteBlitter from a ByteProcessor. */
    public ByteBlitter(ByteProcessor ip) {
        this.ip = ip;
        width = ip.getWidth();
        height = ip.getHeight();
        pixels = (byte[])ip.getPixels();
    }

    public void setTransparentColor(Color c) {
        transparent = ip.getBestIndex(c);
    }
    
    /** Copies the byte image in 'ip' to (x,y) using the specified mode. */
    public void copyBits(ImageProcessor ip, int xloc, int yloc, int mode) {
        Rectangle r1, r2;
        int srcIndex, dstIndex;
        int xSrcBase, ySrcBase;
        byte[] srcPixels;
        
        int srcWidth = ip.getWidth();
        int srcHeight = ip.getHeight();
        r1 = new Rectangle(srcWidth, srcHeight);
        r1.setLocation(xloc, yloc);
        r2 = new Rectangle(width, height);
        if (!r1.intersects(r2))
            return;
        if (ip instanceof ColorProcessor) {
            int[] pixels32 = (int[])ip.getPixels();
            int size = ip.getWidth()*ip.getHeight();
            srcPixels = new byte[size];
            if (this.ip.isInvertedLut())
                for (int i=0; i<size; i++)
                    srcPixels[i] = (byte)(255-pixels32[i]&255);
            else 
                for (int i=0; i<size; i++)
                    srcPixels[i] = (byte)(pixels32[i]&255);
        } else {
            ip = ip.convertToByte(true);
            srcPixels = (byte [])ip.getPixels();
        }
        r1 = r1.intersection(r2);
        xSrcBase = (xloc<0)?-xloc:0;
        ySrcBase = (yloc<0)?-yloc:0;
        int src, dst;
        for (int y=r1.y; y<(r1.y+r1.height); y++) {
            srcIndex = (y-yloc)*srcWidth + (r1.x-xloc);
            dstIndex = y * width + r1.x;
            switch (mode) {
                case COPY:
                    for (int i=r1.width; --i>=0;)
                        pixels[dstIndex++] = srcPixels[srcIndex++];
                    break;
                case COPY_INVERTED:
                    for (int i=r1.width; --i>=0;)
                        pixels[dstIndex++] = (byte)(255-srcPixels[srcIndex++]&255);
                    break;
                case COPY_TRANSPARENT:
                    for (int i=r1.width; --i>=0;) {
                        src = srcPixels[srcIndex++]&255;
                        if (src==transparent)
                            dst = pixels[dstIndex];
                        else
                            dst = src;
                        pixels[dstIndex++] = (byte)dst;
                    }
                    break;
                case COPY_ZERO_TRANSPARENT:
                    for (int i=r1.width; --i>=0;) {
                        src = srcPixels[srcIndex++]&255;
                        if (src==0)
                            dst = pixels[dstIndex];
                        else
                            dst = src;
                        pixels[dstIndex++] = (byte)dst;
                    }
                    break;
                case ADD:
                    for (int i=r1.width; --i>=0;) {
                        dst = (srcPixels[srcIndex++]&255)+(pixels[dstIndex]&255);
                        if (dst>255) dst = 255;
                        pixels[dstIndex++] = (byte)dst;
                    }
                    break;
                case AVERAGE:
                    for (int i=r1.width; --i>=0;) {
                        dst = ((srcPixels[srcIndex++]&255)+(pixels[dstIndex]&255))/2;
                        pixels[dstIndex++] = (byte)dst;
                    }
                    break;
                case SUBTRACT:
                    for (int i=r1.width; --i>=0;) {
                        dst = (pixels[dstIndex]&255)-(srcPixels[srcIndex++]&255);
                        if (dst<0) dst = 0;
                        pixels[dstIndex++] = (byte)dst;
                    }
                    break;
                case DIFFERENCE:
                    for (int i=r1.width; --i>=0;) {
                        dst = (pixels[dstIndex]&255)-(srcPixels[srcIndex++]&255);
                        if (dst<0) dst = -dst;
                        pixels[dstIndex++] = (byte)dst;
                    }
                    break;
                case MULTIPLY:
                    for (int i=r1.width; --i>=0;) {
                        dst = (srcPixels[srcIndex++]&255)*(pixels[dstIndex]&255);
                        if (dst>255) dst = 255;
                        pixels[dstIndex++] = (byte)dst;
                    }
                    break;
                case DIVIDE:
                    for (int i=r1.width; --i>=0;) {
                        src = srcPixels[srcIndex++]&255;
                        if (src==0)
                            dst = 255;
                        else
                            dst = (pixels[dstIndex]&255)/src;
                        pixels[dstIndex++] = (byte)dst;
                    }
                    break;
                case AND:
                    for (int i=r1.width; --i>=0;) {
                        dst = srcPixels[srcIndex++]&pixels[dstIndex];
                        pixels[dstIndex++] = (byte)dst;
                    }
                    break;
                case OR:
                    for (int i=r1.width; --i>=0;) {
                        dst = srcPixels[srcIndex++]|pixels[dstIndex];
                        pixels[dstIndex++] = (byte)dst;
                    }
                    break;
                case XOR:
                    for (int i=r1.width; --i>=0;) {
                        dst = srcPixels[srcIndex++]^pixels[dstIndex];
                        pixels[dstIndex++] = (byte)dst;
                    }
                    break;
                case MIN:
                    for (int i=r1.width; --i>=0;) {
                        src = srcPixels[srcIndex++]&255;
                        dst = pixels[dstIndex]&255;
                        if (src<dst) dst = src;
                        pixels[dstIndex++] = (byte)dst;
                    }
                    break;
                case MAX:
                    for (int i=r1.width; --i>=0;) {
                        src = srcPixels[srcIndex++]&255;
                        dst = pixels[dstIndex]&255;
                        if (src>dst) dst = src;
                        pixels[dstIndex++] = (byte)dst;
                    }
                    break;
            }
        }
    }
}