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;
			}
			if (y%20==0)
				ip.showProgress((double)(y-rect1.y)/rect1.height);
		}
		ip.showProgress(1.0);
	}
}