/*******************************************************************************
 * Copyright (c) 2000, 2011 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.swt.internal.image;


import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;

public class PngTrnsChunk extends PngChunk {
	static final int TRANSPARENCY_TYPE_PIXEL = 0;
	static final int TRANSPARENCY_TYPE_ALPHAS = 1;
	static final int RGB_DATA_LENGTH = 6;

PngTrnsChunk(RGB rgb) {
	super(RGB_DATA_LENGTH);
	setType(TYPE_tRNS);
	setInt16(DATA_OFFSET, rgb.red);
	setInt16(DATA_OFFSET + 2, rgb.green);
	setInt16(DATA_OFFSET + 4, rgb.blue);
	setCRC(computeCRC());
}

PngTrnsChunk(byte[] reference){
	super(reference);
}

@Override
int getChunkType() {
	return CHUNK_tRNS;
}

void validateLength(PngIhdrChunk header, PngPlteChunk paletteChunk) {
	boolean valid;
	switch (header.getColorType()) {
		case PngIhdrChunk.COLOR_TYPE_RGB:
			// Three 2-byte values (RGB)
			valid = getLength() == 6;
			break;
		case PngIhdrChunk.COLOR_TYPE_PALETTE:
			// Three 2-byte values (RGB)
			valid = getLength() <= paletteChunk.getLength();
			break;
		case PngIhdrChunk.COLOR_TYPE_GRAYSCALE:
			// One 2-byte value
			valid = getLength() == 2;
			break;
		// Cannot use both Alpha and tRNS
		case PngIhdrChunk.COLOR_TYPE_RGB_WITH_ALPHA:
		case PngIhdrChunk.COLOR_TYPE_GRAYSCALE_WITH_ALPHA:
		default:
			valid = false;
	}
	if (!valid) {
		SWT.error(SWT.ERROR_INVALID_IMAGE);
	}
}

/**
 * Answer whether the chunk is a valid tRNS chunk.
 */
void validate(PngFileReadState readState, PngIhdrChunk headerChunk, PngPlteChunk paletteChunk) {
	if (!readState.readIHDR
		|| (headerChunk.getMustHavePalette() && !readState.readPLTE)
		|| readState.readIDAT
		|| readState.readIEND)
	{
		SWT.error(SWT.ERROR_INVALID_IMAGE);
	} else {
		readState.readTRNS = true;
	}

	validateLength(headerChunk, paletteChunk);

	super.validate(readState, headerChunk);
}


int getTransparencyType(PngIhdrChunk header) {
	if (header.getColorType() == PngIhdrChunk.COLOR_TYPE_PALETTE) {
		return TRANSPARENCY_TYPE_ALPHAS;
	}
	return TRANSPARENCY_TYPE_PIXEL;
}

/**
 * Answer the transparent pixel RGB value.
 * This is not valid for palette color types.
 * This is not valid for alpha color types.
 * This will convert a grayscale value into
 * a palette index.
 * It will compress a 6 byte RGB into a 3 byte
 * RGB.
 */
int getSwtTransparentPixel(PngIhdrChunk header) {
	switch (header.getColorType()) {
		case PngIhdrChunk.COLOR_TYPE_GRAYSCALE:
			int gray = ((reference[DATA_OFFSET] & 0xFF) << 8)
				+ (reference[DATA_OFFSET + 1] & 0xFF);
			if (header.getBitDepth() > 8) {
				return PNGFileFormat.compress16BitDepthTo8BitDepth(gray);
			}
			return gray & 0xFF;
		case PngIhdrChunk.COLOR_TYPE_RGB:
			int red = ((reference[DATA_OFFSET] & 0xFF) << 8)
				| (reference[DATA_OFFSET + 1] & 0xFF);
			int green = ((reference[DATA_OFFSET + 2] & 0xFF) << 8)
				| (reference[DATA_OFFSET + 3] & 0xFF);
			int blue = ((reference[DATA_OFFSET + 4] & 0xFF) << 8)
				| (reference[DATA_OFFSET + 5] & 0xFF);
			if (header.getBitDepth() > 8) {
				red = PNGFileFormat.compress16BitDepthTo8BitDepth(red);
				green = PNGFileFormat.compress16BitDepthTo8BitDepth(green);
				blue = PNGFileFormat.compress16BitDepthTo8BitDepth(blue);
			}
			return (red << 16) | (green << 8) | blue;
		default:
			SWT.error(SWT.ERROR_INVALID_IMAGE);
			return -1;
	}
}

/**
 * Answer an array of Alpha values that correspond to the
 * colors in the palette.
 * This is only valid for the COLOR_TYPE_PALETTE color type.
 */
byte[] getAlphaValues(PngIhdrChunk header, PngPlteChunk paletteChunk) {
	if (header.getColorType() != PngIhdrChunk.COLOR_TYPE_PALETTE) {
		SWT.error(SWT.ERROR_INVALID_IMAGE);
	}
	byte[] alphas = new byte[paletteChunk.getPaletteSize()];
	int dataLength = getLength();
	int i = 0;
	for (i = 0; i < dataLength; i++) {
		alphas[i] = reference[DATA_OFFSET + i];
	}
	/**
	 * Any palette entries which do not have a corresponding
	 * alpha value in the tRNS chunk are spec'd to have an
	 * alpha of 255.
	 */
	for (int j = i; j < alphas.length; j++) {
		alphas[j] = (byte) 255;
	}
	return alphas;
}
}
