package jp.sourceforge.nicoro.swf;

import static jp.sourceforge.nicoro.swf.Log.DEBUG_LOGD;
import static jp.sourceforge.nicoro.swf.Log.LOG_TAG;

import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.util.zip.InflaterInputStream;

import android.graphics.Bitmap;
import android.graphics.Color;

import jp.gr.java_conf.shiseissi.commonlib.FileUtil;
import jp.sourceforge.nicoro.FailAnalyzeSwfException;
import jp.sourceforge.nicoro.PartialInputStreamRandomAccessWrapper;

public class DefineBitsLossless2 {
	public static final int BITMAPFORMAT_8BIT_COLORMAP = 3;
	public static final int BITMAPFORMAT_32BIT_ARGB = 5;

	public short characterID;		// UI16
	public short bitmapFormat;		// UI8
	public int bitmapWidth;		// UI16
	public int bitmapHeight;		// UI16
	public short bitmapColorTableSize;	// UI8

    public void readHeader(ByteBuffer buffer) {
    	DefineBitsLossless2 defineBitsLossless2 = this;

    	defineBitsLossless2.characterID = buffer.getShort();		// UI16
    	defineBitsLossless2.bitmapFormat = (short) (buffer.get() & 0xff);		// UI8
    	defineBitsLossless2.bitmapWidth = buffer.getShort() & 0xffff;		// UI16
    	defineBitsLossless2.bitmapHeight = buffer.getShort() & 0xffff;		// UI16
		if (DEBUG_LOGD) {
			Log.d(LOG_TAG, Log.buf()
					.append("CharacterID=").append(defineBitsLossless2.characterID)
					.append(" BitmapFormat=").append(defineBitsLossless2.bitmapFormat)
					.append(" BitmapWidth=").append(defineBitsLossless2.bitmapWidth)
					.append(" BitmapHeight=").append(defineBitsLossless2.bitmapHeight).toString());
		}
		defineBitsLossless2.bitmapColorTableSize = 0;
		if (defineBitsLossless2.bitmapFormat == BITMAPFORMAT_8BIT_COLORMAP) {
			defineBitsLossless2.bitmapColorTableSize = (short) (buffer.get() & 0xff);		// UI8
    		if (DEBUG_LOGD) {
    			Log.d(LOG_TAG, Log.buf().append("BitmapColorTableSize=")
    					.append(defineBitsLossless2.bitmapColorTableSize).toString());
    		}
		}
    }

    public void read(RandomAccessFile in, int length, SwfPlayer swfPlayer) throws IOException, FailAnalyzeSwfException {
    	DefineBitsLossless2 defineBitsLossless2 = this;

    	long begin = in.getFilePointer();
    	readHeader(in);

    	int dataLength = (int) (length - (in.getFilePointer() - begin));
    	BitmapLoader loader = new BitsLossless2Loader(
    			in, in.getFilePointer(), dataLength);
//    	Bitmap bitmap = loader.get();
    	in.seek(in.getFilePointer() + dataLength);
//		swfPlayer.putBitmapToDictionary(defineBitsLossless2.characterID, bitmap);
		swfPlayer.putBitmapToDictionary(defineBitsLossless2.characterID, loader);
    }

    private void readHeader(RandomAccessFile in) throws IOException {
    	DefineBitsLossless2 defineBitsLossless2 = this;

    	defineBitsLossless2.characterID = (short) FileUtil.readShortLE(in);		// UI16
    	defineBitsLossless2.bitmapFormat = (short) FileUtil.readByte(in);		// UI8
    	defineBitsLossless2.bitmapWidth = FileUtil.readShortLE(in);		// UI16
    	defineBitsLossless2.bitmapHeight = FileUtil.readShortLE(in);		// UI16
		if (DEBUG_LOGD) {
			Log.d(LOG_TAG, Log.buf()
					.append("CharacterID=").append(defineBitsLossless2.characterID)
					.append(" BitmapFormat=").append(defineBitsLossless2.bitmapFormat)
					.append(" BitmapWidth=").append(defineBitsLossless2.bitmapWidth)
					.append(" BitmapHeight=").append(defineBitsLossless2.bitmapHeight).toString());
		}
		defineBitsLossless2.bitmapColorTableSize = 0;
		if (defineBitsLossless2.bitmapFormat == BITMAPFORMAT_8BIT_COLORMAP) {
			defineBitsLossless2.bitmapColorTableSize = (short) FileUtil.readByte(in);		// UI8
    		if (DEBUG_LOGD) {
    			Log.d(LOG_TAG, Log.buf().append("BitmapColorTableSize=")
    					.append(defineBitsLossless2.bitmapColorTableSize).toString());
    		}
		}
    }

    private Bitmap readData(InputStream data) throws IOException, FailAnalyzeSwfException {
    	DefineBitsLossless2 defineBitsLossless2 = this;

		InputStream inZlibBitmapData = null;
		try {
			inZlibBitmapData = new InflaterInputStream(data);
    		Bitmap bitmap = null;
    		if (defineBitsLossless2.bitmapFormat == DefineBitsLossless2.BITMAPFORMAT_8BIT_COLORMAP) {
    			ALPHACOLORMAPDATA zlibBitmapData = new ALPHACOLORMAPDATA();
    			zlibBitmapData.colorTableRGB = new int[defineBitsLossless2.bitmapColorTableSize + 1];
    			for (int i = 0; i < zlibBitmapData.colorTableRGB.length; ++i) {
    				int r = inZlibBitmapData.read();
    				int g = inZlibBitmapData.read();
    				int b = inZlibBitmapData.read();
    				int a = inZlibBitmapData.read();
    				zlibBitmapData.colorTableRGB[i] = Color.argb(a, r, g, b);
    			}
    			// TODO バッファ作って作成だとOutOfMemoryErrorが出る場合が

//    			byte[] byteTemp = new byte[bitmapWidth * bitmapHeight];
//    			Util.readComplete(inZlibBitmapData, byteTemp, 0, byteTemp.length);
//    			int[] pixelData = new int[bitmapWidth * bitmapHeight];
//    			for (int i = 0; i < bitmapWidth * bitmapHeight; ++i) {
//    				int pos = byteTemp[i] & 0xff;
//    				pixelData[i] = zlibBitmapData.colorTableRGB[pos];
//    			}
//    			byteTemp = null;
//    			bitmap = Bitmap.createBitmap(pixelData, bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
////    			bitmap = Bitmap.createBitmap(pixelData, bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_4444);

    			bitmap = Bitmap.createBitmap(defineBitsLossless2.bitmapWidth,
    			        defineBitsLossless2.bitmapHeight,
    			        Bitmap.Config.ARGB_8888);
//    			bitmap = Bitmap.createBitmap(bitmapWidth,
//    			        bitmapHeight,
//    			        Bitmap.Config.ARGB_4444);
    			for (int y = 0; y < defineBitsLossless2.bitmapHeight; ++y) {
	    			for (int x = 0; x < defineBitsLossless2.bitmapWidth; ++x) {
	    				int pos = inZlibBitmapData.read() & 0xff;
	    				int color = zlibBitmapData.colorTableRGB[pos];
	    				bitmap.setPixel(x, y, color);
	    			}
    			}
    		} else if (defineBitsLossless2.bitmapFormat == DefineBitsLossless2.BITMAPFORMAT_32BIT_ARGB) {
    			ALPHABITMAPDATA zlibBitmapData = new ALPHABITMAPDATA();
    			zlibBitmapData.bitmapPixelData = new int[defineBitsLossless2.bitmapWidth * defineBitsLossless2.bitmapHeight];
    			byte[] byteTemp = new byte[defineBitsLossless2.bitmapWidth * defineBitsLossless2.bitmapHeight * 4];
    			FileUtil.readComplete(inZlibBitmapData, byteTemp, 0, byteTemp.length);
    			for (int i = 0; i < defineBitsLossless2.bitmapWidth * defineBitsLossless2.bitmapHeight; ++i) {
    				zlibBitmapData.bitmapPixelData[i] =
    					(byteTemp[i*4+0] << 24) | ((byteTemp[i*4+1] & 0xff) << 16) | ((byteTemp[i*4+2] & 0xff) << 8) | (byteTemp[i*4+3] & 0xff);
    			}
    			byteTemp = null;
    			bitmap = Bitmap.createBitmap(zlibBitmapData.bitmapPixelData,
    			        defineBitsLossless2.bitmapWidth,
    			        defineBitsLossless2.bitmapHeight,
    			        Bitmap.Config.ARGB_8888);
//                        Bitmap.Config.ARGB_4444);
    		} else {
    			throw new FailAnalyzeSwfException("BitmapFormat is invalid: " + defineBitsLossless2.bitmapFormat);
    		}
    		if (bitmap == null) {
        		throw new FailAnalyzeSwfException("tag block contents DefineBitsLossless2 bitmap create failed.");
    		}
    		return bitmap;
		} finally {
			if (inZlibBitmapData != null) {
				inZlibBitmapData.close();
			}
		}
    }

    private class BitsLossless2Loader extends BitmapLoader {
    	private final RandomAccessFile mIn;
    	private final long mFilePointer;
    	private final int mLength;

    	BitsLossless2Loader(RandomAccessFile in, long filePointer, int length) {
    		mIn = in;
    		mFilePointer = filePointer;
    		mLength = length;
    	}

		@Override
		public Bitmap load() throws IOException, FailAnalyzeSwfException {
			long last = mIn.getFilePointer();
			mIn.seek(mFilePointer);

			PartialInputStreamRandomAccessWrapper partialIn =
				new PartialInputStreamRandomAccessWrapper(mIn, mLength);
	    	Bitmap bitmap = readData(partialIn);

			mIn.seek(last);
			return bitmap;
		}
    }
}
