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

/** This class does bit blitting of RGB images. */
public class ColorBlitter implements Blitter {

    private ColorProcessor ip;
    private int width, height;
    private int[] pixels;
    private int transparent = 0xffffff;
    
    /** Constructs a ColorBlitter from a ColorProcessor. */
    public ColorBlitter(ColorProcessor ip) {
        this.ip = ip;
        width = ip.getWidth();
        height = ip.getHeight();
        pixels = (int[])ip.getPixels();
    }

    public void setTransparentColor(Color c) {
        transparent = c.getRGB()&0xffffff;
    }

    /** Copies the RGB image in 'ip' to (x,y) using the specified mode. */
    public void copyBits(ImageProcessor ip, int xloc, int yloc, int mode) {
        int srcIndex, dstIndex;
        int xSrcBase, ySrcBase;
        int[] srcPixels;
        
        int srcWidth = ip.getWidth();
        int srcHeight = ip.getHeight();
        Rectangle rect1 = new Rectangle(srcWidth, srcHeight);
        rect1.setLocation(xloc, yloc);
        Rectangle rect2 = new Rectangle(width, height);
        if (!rect1.intersects(rect2))
            return;
        if (ip instanceof ByteProcessor) {
            byte[] pixels8 = (byte[])ip.getPixels();
            ColorModel cm = ip.getColorModel();
            if (ip.isInvertedLut())
                cm = ip.getDefaultColorModel();
            int size = ip.getWidth()*ip.getHeight();
            srcPixels = new int[size];
            int v;
            for (int i=0; i<size; i++)
                srcPixels[i] = cm.getRGB(pixels8[i]&255);
        } else
            srcPixels = (int[])ip.getPixels();
        rect1 = rect1.intersection(rect2);
        xSrcBase = (xloc<0)?-xloc:0;
        ySrcBase = (yloc<0)?-yloc:0;
        int c1, c2, r1, g1, b1, r2, g2, b2;
        int src, dst;
        
        if (mode==COPY||mode==COPY_TRANSPARENT|| mode==COPY_ZERO_TRANSPARENT) {
            for (int y=rect1.y; y<(rect1.y+rect1.height); y++) {
                srcIndex = (y-yloc)*srcWidth + (rect1.x-xloc);
                dstIndex = y * width + rect1.x;
                int trancolor = mode==COPY_ZERO_TRANSPARENT?0:transparent;
                if (mode==COPY) {
                    for (int i=rect1.width; --i>=0;)
                        pixels[dstIndex++] = srcPixels[srcIndex++];
                } else {
                    for (int i=rect1.width; --i>=0;) {
                        src = srcPixels[srcIndex++];
                        dst = pixels[dstIndex];
                        pixels[dstIndex++] = (src&0xffffff)==trancolor?dst:src;
                    }
                } 
            }
            return;
        }
        
        for (int y=rect1.y; y<(rect1.y+rect1.height); y++) {
            srcIndex = (y-yloc)*srcWidth + (rect1.x-xloc);
            dstIndex = y * width + rect1.x;
            for (int i=rect1.width; --i>=0;) {
                c1 = srcPixels[srcIndex++];
                r1 = (c1&0xff0000)>>16;
                g1 = (c1&0xff00)>>8;
                b1 = c1&0xff;
                c2 = pixels[dstIndex];
                r2 = (c2&0xff0000)>>16;
                g2 = (c2&0xff00)>>8;
                b2 = c2&0xff;
                switch (mode) {
                    case COPY_INVERTED:
                        break;
                    case ADD:
                            r2=r1+r2; g2=g1+g2; b2=b1+b2;
                            if (r2>255) r2=255; if (g2>255) g2=255; if (b2>255) b2=255;
                        break;
                    case AVERAGE:
                            r2=(r1+r2)/2; g2=(g1+g2)/2; b2=(b1+b2)/2;
                        break;
                    case SUBTRACT:
                            r2=r2-r1; g2=g2-g1; b2=b2-b1;
                            if (r2<0) r2=0; if (g2<0) g2=0; if (b2<0) b2=0;
                        break;
                    case DIFFERENCE:
                            r2=r2-r1; if (r2<0) r2=-r2;
                            g2=g2-g1; if (g2<0) g2=-g2;
                            b2=b2-b1; if (b2<0) b2=-b2;
                        break;
                    case MULTIPLY:
                            r2=r1*r2; g2=g1*g2; b2=b1*b2;
                            if (r2>255) r2=255; if (g2>255) g2=255; if (b2>255) b2=255;
                        break;
                    case DIVIDE:
                            if (r1==0) r2=255; else r2=r2/r1;
                            if (g1==0) g2=255; else g2=g2/g1;
                            if (b1==0) b2=255; else b2=b2/b1;
                        break;
                    case AND:
                        r2=r1&r2; g2=g1&g2; b2=b1&b2;
                        break;
                    case OR:
                        r2=r1|r2; g2=g1|g2; b2=b1|b2;
                        break;
                    case XOR:
                        r2=r1^r2; g2=g1^g2; b2=b1^b2;
                        break;
                    case MIN:
                        if (r1<r2) r2 = r1;
                        if (g1<g2) g2 = g1;
                        if (b1<b2) b2 = b1;
                        break;
                    case MAX:
                        if (r1>r2) r2 = r1;
                        if (g1>g2) g2 = g1;
                        if (b1>b2) b2 = b1;
                        break;
                }
                pixels[dstIndex++] = 0xff000000 + (r2<<16) + (g2<<8) + b2;
            }
        }
    }
}