package org.rebotted.cache.graphics;
import org.rebotted.cache.FileArchive;
import org.rebotted.draw.Rasterizer2D;
import org.rebotted.io.Buffer;

public final class IndexedImage extends Rasterizer2D {
	
	public byte palettePixels[];
	public final int[] palette;
	public int width;
	public int height;
	public int drawOffsetX;
	public int drawOffsetY;
	public int resizeWidth;	
	private int resizeHeight;

	public IndexedImage(FileArchive archive, String s, int i) {		
		Buffer image = new Buffer(archive.readFile(s + ".dat"));
		Buffer meta = new Buffer(archive.readFile("index.dat"));		
		meta.currentPosition = image.readUShort();
		resizeWidth = meta.readUShort();
		resizeHeight = meta.readUShort();
		
		int colorLength = meta.readUnsignedByte();		
		palette = new int[colorLength];
		
		for(int index = 0; index < colorLength - 1; index++) {
			palette[index + 1] = meta.readTriByte();			
		}
		
		for(int l = 0; l < i; l++) {			
			meta.currentPosition += 2;
			image.currentPosition += meta.readUShort() * meta.readUShort();
			meta.currentPosition++;
		}
		drawOffsetX = meta.readUnsignedByte();		
		drawOffsetY = meta.readUnsignedByte();		
		width = meta.readUShort();
		height = meta.readUShort();		
		int type = meta.readUnsignedByte();		
		int pixels = width * height;			
		palettePixels = new byte[pixels];
		
		if(type == 0) {
			for(int index = 0; index < pixels; index++) {
				palettePixels[index] = image.readSignedByte();
			}
		} else if(type == 1) {
			for(int x = 0; x < width; x++) {				
				for(int y = 0; y < height; y++) {					
					palettePixels[x + y * width] = image.readSignedByte();
				}
			}
		}
	}

	public void downscale() {
		resizeWidth /= 2;
		resizeHeight /= 2;
		byte raster[] = new byte[resizeWidth * resizeHeight];		
		int sourceIndex = 0;		
		for(int y  = 0; y  < height; y ++) {			
			for(int x = 0; x < width; x++) {				
				raster[(x + drawOffsetX >> 1) + (y  + drawOffsetY >> 1) * resizeWidth] = raster[sourceIndex++];
			}
		}
		this.palettePixels = raster;
		width = resizeWidth;
		height = resizeHeight;
		drawOffsetX = 0;
		drawOffsetY = 0;
	}

	public void resize() {
		if(width == resizeWidth && height == resizeHeight) {
			return;
		}
		
		byte raster[] = new byte[resizeWidth * resizeHeight];
		
		int i = 0;
		for(int y = 0; y < height; y++) {			
			for(int x = 0; x < width; x++) {				
				raster[x + drawOffsetX + (y + drawOffsetY) * resizeWidth] = raster[i++];
			}
		}
		this.palettePixels = raster;
		width = resizeWidth;
		height = resizeHeight;
		drawOffsetX = 0;
		drawOffsetY = 0;
	}

	public void flipHorizontally() {
		byte raster[] = new byte[width * height];		
		int pixel = 0;		
		for(int y = 0; y < height; y++) {			
			for(int x = width - 1; x >= 0; x--) {				
				raster[pixel++] = raster[x + y * width];
			}
		}
		this.palettePixels = raster;
		drawOffsetX = resizeWidth - width - drawOffsetX;
	}

	public void flipVertically() {
		byte raster[] = new byte[width * height];		
		int pixel = 0;		
		for(int y = height - 1; y >= 0; y--) {			
			for(int x = 0; x < width; x++) {				
				raster[pixel++] = raster[x + y * width];
			}
		}
		this.palettePixels = raster;
		drawOffsetY = resizeHeight - height - drawOffsetY;
	}

	public void offsetColor(int redOffset, int greenOffset, int blueOffset) {		
		for(int index = 0; index < palette.length; index++) {			
			int red = palette[index] >> 16 & 0xff;		
			red += redOffset;
			
			if(red < 0) {
				red = 0;
			} else if(red > 255) {
				red = 255;
			}
			
			int green = palette[index] >> 8 & 0xff;
		
			green += greenOffset;			
			if(green < 0) {
				green = 0;
			} else if(green > 255) {
				green = 255;
			}
			
			int blue = palette[index] & 0xff;
			
			blue += blueOffset;			
			if(blue < 0) {
				blue = 0;
			} else if(blue > 255) {
				blue = 255;
			}
			palette[index] = (red << 16) + (green << 8) + blue;
		}
	}

	public void draw(int x, int y) {		
		x += drawOffsetX;
		y += drawOffsetY;		
		int destOffset = x + y * Rasterizer2D.width;		
		int sourceOffset = 0;
		int height = this.height;
		int width = this.width;		
		int destStep = Rasterizer2D.width - width;		
		int sourceStep = 0;
		
		if(y < Rasterizer2D.topY) {
			int dy = Rasterizer2D.topY - y;			
			height -= dy;			
			y = Rasterizer2D.topY;
			sourceOffset += dy * width;			
			destOffset += dy * Rasterizer2D.width;
		}
		
		if(y + height > Rasterizer2D.bottomY) {
			height -= (y + height) - Rasterizer2D.bottomY;
		}
		
		if(x < Rasterizer2D.leftX) {
			int k2 = Rasterizer2D.leftX - x;
			width -= k2;
			x = Rasterizer2D.leftX;
			sourceOffset += k2;
			destOffset += k2;
			sourceStep += k2;
			destStep += k2;
		}
		
		if(x + width > Rasterizer2D.bottomX) {
			int dx = (x + width) - Rasterizer2D.bottomX;			
			width -= dx;
			sourceStep += dx;
			destStep += dx;
		}
		
		if(!(width <= 0 || height <= 0)) {			
			draw(height, Rasterizer2D.pixels, palettePixels, destStep, destOffset, width, sourceOffset, palette, sourceStep);
		}
		
	}

	private void draw(int i, int raster[], byte image[], int destStep, int destIndex, int width,  int sourceIndex, int ai1[], int sourceStep) {
		int minX = -(width >> 2);		
		width = -(width & 3);		
		for(int y = -i; y < 0; y++) {			
			for(int x = minX; x < 0; x++) {	
				
				byte pixel = image[sourceIndex++];
				
				if(pixel != 0) {
					raster[destIndex++] = ai1[pixel & 0xff];					
				} else {
					destIndex++;					
				}
				pixel = image[sourceIndex++];
				if(pixel != 0) {
					raster[destIndex++] = ai1[pixel & 0xff];
				} else {
					destIndex++;
				}
				pixel = image[sourceIndex++];				
				if(pixel != 0) {
					raster[destIndex++] = ai1[pixel & 0xff];
				} else {
					destIndex++;
				}
				pixel = image[sourceIndex++];
				if(pixel != 0) {
					raster[destIndex++] = ai1[pixel & 0xff];
				} else {
					destIndex++;
				}
			}
			for(int x = width; x < 0; x++) {				
				byte pixel = image[sourceIndex++];				
				if(pixel != 0) {
					raster[destIndex++] = ai1[pixel & 0xff];
				} else {
					destIndex++;
				}
			}
			destIndex += destStep;			
			sourceIndex += sourceStep;			
		}
	}
}