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 jp.sourceforge.nicoro.FailAnalyzeSwfException;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Shader;

public class FILLSTYLE {
	public static final byte SOLID_FILL = 0x00;
	public static final byte LINEAR_GRADIENT_FILL = 0x10;
	public static final byte RADIAL_GRADIENT_FILL = 0x12;
	public static final byte FOCAL_RADIAL_GRADIENT_FILL = 0x13;
	public static final byte REPEATING_BITMAP_FILL = 0x40;
	public static final byte CLIPPED_BITMAP_FILL = 0x41;
	public static final byte NONSMOOTHED_REPEATING_BITMAP = 0x42;
	public static final byte NONSMOOTHED_CLIPPED_BITMAP = 0x43;

	public byte fillStyleType;		// UI8
	public int color;		// RGBA (Shape3), RGB (Shape1 or Shape2)
	public MATRIX gradientMatrix;
	public GRADIENT gradient;
	public FOCALGRADIENT gradientFocal;
	public short bitmapId;		// UI16
	public MATRIX bitmapMatrix;

    public int read(byte[] bufferArray, int offset, int tagType) {
    	FILLSTYLE fillStyle = this;

		if (DEBUG_LOGD) {
			Log.d(LOG_TAG, Log.buf().append("readFILLSTYLE: offset=")
					.append(offset).toString());
		}

		fillStyle.fillStyleType = bufferArray[offset];
    	if (DEBUG_LOGD) {
    		Log.d(LOG_TAG, Log.buf().append("FillStyleType=")
    				.append(Integer.toHexString(fillStyle.fillStyleType & 0xff)).toString());
    	}

    	int offsetNext = offset + 1;
    	// Color
    	if (fillStyle.fillStyleType == FILLSTYLE.SOLID_FILL) {
    		switch (tagType) {
    		case RECORDHEADER.SWFTAG_DEFINESHAPE:
    		case RECORDHEADER.SWFTAG_DEFINESHAPE2:
    			fillStyle.color = Color.rgb(
    					bufferArray[offsetNext + 0],
    					bufferArray[offsetNext + 1],
    					bufferArray[offsetNext + 2]);
    			offsetNext += 3;
    			break;
    		case RECORDHEADER.SWFTAG_DEFINESHAPE3:
    			fillStyle.color = Color.argb(
    					bufferArray[offsetNext + 3],
    					bufferArray[offsetNext + 0],
    					bufferArray[offsetNext + 1],
    					bufferArray[offsetNext + 2]);
    			offsetNext += 4;
    			break;
    		default:
    			Log.w(LOG_TAG, Log.buf().append("FILLSTYLE: record tag type mismatch=")
    					.append(tagType).toString());
    			break;
    		}
        	if (DEBUG_LOGD) {
        		Log.d(LOG_TAG, Log.buf().append("Color=")
        				.append(Integer.toHexString(fillStyle.color)).toString());
        	}
    	}

    	// GradientMatrix & Gradient
    	switch (fillStyle.fillStyleType) {
    	case FILLSTYLE.LINEAR_GRADIENT_FILL:
    	    fillStyle.gradientMatrix = new MATRIX();
    	    fillStyle.gradient = new GRADIENT();
    		offsetNext = fillStyle.gradientMatrix.read(bufferArray, offsetNext);
    		offsetNext = fillStyle.gradient.read(bufferArray, offsetNext, tagType);
    		break;
    	case FILLSTYLE.RADIAL_GRADIENT_FILL:
            fillStyle.gradientMatrix = new MATRIX();
            fillStyle.gradient = new GRADIENT();
    		offsetNext = fillStyle.gradientMatrix.read(bufferArray, offsetNext);
    		offsetNext = fillStyle.gradient.read(bufferArray, offsetNext, tagType);
    		break;
    	case FILLSTYLE.FOCAL_RADIAL_GRADIENT_FILL:
            fillStyle.gradientMatrix = new MATRIX();
            fillStyle.gradientFocal = new FOCALGRADIENT();
    		offsetNext = fillStyle.gradientMatrix.read(bufferArray, offsetNext);
    		offsetNext = fillStyle.gradientFocal.read(bufferArray, offsetNext, tagType);
    		break;
    	}

    	// Bitmap
    	switch (fillStyle.fillStyleType) {
    	case FILLSTYLE.REPEATING_BITMAP_FILL:
    	case FILLSTYLE.CLIPPED_BITMAP_FILL:
    	case FILLSTYLE.NONSMOOTHED_REPEATING_BITMAP:
    	case FILLSTYLE.NONSMOOTHED_CLIPPED_BITMAP:
    		fillStyle.bitmapId = (short) ((bufferArray[offsetNext + 0] & 0xff) | ((bufferArray[offsetNext + 1] & 0xff) << 8));
        	if (DEBUG_LOGD) {
        		Log.d(LOG_TAG, Log.buf().append("BitmapId=")
        				.append(fillStyle.bitmapId).toString());
        	}
        	offsetNext += 2;
        	fillStyle.bitmapMatrix = new MATRIX();
    		offsetNext = fillStyle.bitmapMatrix.read(bufferArray, offsetNext);
    		break;
    	}

		return offsetNext;
    }

    public Shader getShader(Paint paint, SwfPlayer swfPlayer) throws FailAnalyzeSwfException, IOException {
    	FILLSTYLE fillStyle = this;

    	Shader shader;
		Bitmap bitmap;
		Matrix matrix;
		switch (fillStyle.fillStyleType) {
		case FILLSTYLE.REPEATING_BITMAP_FILL:
			bitmap = swfPlayer.getBitmapFromDictionary(fillStyle.bitmapId);
			if (bitmap == null) {
				Log.d(LOG_TAG, Log.buf().append("Bitmap not found: BitmapId=")
						.append(fillStyle.bitmapId).toString());
			}
			shader = new BitmapShader(bitmap,
					Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
			matrix = new Matrix();
			fillStyle.bitmapMatrix.toMatrix(matrix);
			shader.setLocalMatrix(matrix);
			if (DEBUG_LOGD) {
				Log.d(LOG_TAG, Log.buf().append("Bitmap Matrix: ")
						.append(matrix.toString()).toString());
			}
			paint.setFilterBitmap(true);
			break;
		case FILLSTYLE.CLIPPED_BITMAP_FILL:
			bitmap = swfPlayer.getBitmapFromDictionary(fillStyle.bitmapId);
			if (bitmap == null) {
				Log.d(LOG_TAG, Log.buf().append("Bitmap not found: BitmapId=")
						.append(fillStyle.bitmapId).toString());
			}
			shader = new BitmapShader(bitmap,
					Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
			matrix = new Matrix();
			fillStyle.bitmapMatrix.toMatrix(matrix);
			shader.setLocalMatrix(matrix);
			if (DEBUG_LOGD) {
				Log.d(LOG_TAG, Log.buf().append("Bitmap Matrix: ")
						.append(matrix.toString()).toString());
			}
			paint.setFilterBitmap(true);
			break;
		case FILLSTYLE.NONSMOOTHED_REPEATING_BITMAP:
			bitmap = swfPlayer.getBitmapFromDictionary(fillStyle.bitmapId);
			if (bitmap == null) {
				Log.d(LOG_TAG, Log.buf().append("Bitmap not found: BitmapId=")
						.append(fillStyle.bitmapId).toString());
			}
			shader = new BitmapShader(bitmap,
					Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
			matrix = new Matrix();
			fillStyle.bitmapMatrix.toMatrix(matrix);
			shader.setLocalMatrix(matrix);
			if (DEBUG_LOGD) {
				Log.d(LOG_TAG, Log.buf().append("Bitmap Matrix: ")
						.append(matrix.toString()).toString());
			}
			paint.setFilterBitmap(false);
			break;
		case FILLSTYLE.NONSMOOTHED_CLIPPED_BITMAP:
			bitmap = swfPlayer.getBitmapFromDictionary(fillStyle.bitmapId);
			if (bitmap == null) {
				Log.d(LOG_TAG, Log.buf().append("Bitmap not found: BitmapId=")
						.append(fillStyle.bitmapId).toString());
			}
			shader = new BitmapShader(bitmap,
					Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
			matrix = new Matrix();
			fillStyle.bitmapMatrix.toMatrix(matrix);
			shader.setLocalMatrix(matrix);
			if (DEBUG_LOGD) {
				Log.d(LOG_TAG, Log.buf().append("Bitmap Matrix: ")
						.append(matrix.toString()).toString());
			}
			paint.setFilterBitmap(false);
			break;
		default:
			// TODO
			throw new FailAnalyzeSwfException("TODO: FillStyleType " + Integer.toHexString(fillStyle.fillStyleType) + " is umimplemented.");
		}

		return shader;
    }

}
