/**
 * 
 */
package jp.sourceforge.nicoro.swf;

import static jp.sourceforge.nicoro.swf.Log.DEBUG_LOGV;
import static jp.sourceforge.nicoro.swf.Log.DEBUG_LOGD;
import static jp.sourceforge.nicoro.swf.Log.LOG_TAG;
import jp.sourceforge.nicoro.BinUtil;
import android.graphics.Matrix;

public class MATRIX {
	public boolean hasScale;		// UB[1]
	public byte nScaleBits;			// UB[5]
	public int scaleX;				// FB[NScaleBits] 最長31bit
	public int scaleY;				// FB[NScaleBits] 最長31bit
	public boolean hasRotate;		// UB[1]
	public byte nRotateBits;		// UB[5]
	public int rotateSkew0;			// FB[NRotateBits] 最長31bit
	public int rotateSkew1;			// FB[NRotateBits] 最長31bit
	public byte nTranslateBits;		// UB[5]
	public int translateX;			// SB[NTranslateBits] 最長31bit
	public int translateY;			// SB[NTranslateBits] 最長31bit
	
    public int read(byte[] bufferArray, int offset) {
    	MATRIX matrix = this;
    	
		if (DEBUG_LOGD) {
			Log.d(LOG_TAG, Log.buf().append("readMATRIX: offset=")
					.append(offset).toString());
		}
    	matrix.hasScale = BinUtil.getBitFlag(bufferArray, offset * 8 + 0);
		if (DEBUG_LOGD) {
			Log.d(LOG_TAG, Log.buf().append("HasScale=")
					.append(matrix.hasScale).toString());
		}
		final int nextRotateOffsetBits;
    	if (matrix.hasScale) {
    		matrix.nScaleBits = (byte) ((bufferArray[offset] >> 2) & 0x1f);
    		if (DEBUG_LOGD) {
    			Log.d(LOG_TAG, Log.buf().append("NScaleBits=")
    					.append(matrix.nScaleBits).toString());
    		}
    		byte[] binary = BinUtil.toBinaryFromBytes(bufferArray, offset * 8 + 6, matrix.nScaleBits * 2);
    		matrix.scaleX = BinUtil.toSIntFromBinary(binary, 0, matrix.nScaleBits);
    		matrix.scaleY = BinUtil.toSIntFromBinary(binary, matrix.nScaleBits, matrix.nScaleBits);
    		if (DEBUG_LOGD) {
    			Log.d(LOG_TAG, Log.buf().append("ScaleX=").append(matrix.scaleX >> 16)
    					.append(".").append(matrix.scaleX & 0xffff)
    					.append(" ScaleY=").append(matrix.scaleY >> 16)
    					.append(".").append(matrix.scaleY & 0xffff).toString());
    		}
    		nextRotateOffsetBits = 1 + 5 + matrix.nScaleBits * 2;
    	} else {
    		nextRotateOffsetBits = 1;
    	}
    	
    	matrix.hasRotate = BinUtil.getBitFlag(bufferArray, offset * 8 + nextRotateOffsetBits);
		if (DEBUG_LOGD) {
			Log.d(LOG_TAG, Log.buf().append("HasRotate=")
					.append(matrix.hasRotate).toString());
		}
		final int nextTranslateOffsetBits;
		if (matrix.hasRotate) {
			byte[] binary = BinUtil.toBinaryFromBytes(bufferArray, offset * 8 + nextRotateOffsetBits + 1, 5);
			matrix.nRotateBits = BinUtil.toByteFromBinary(binary, 0, 5);
    		if (DEBUG_LOGD) {
    			Log.d(LOG_TAG, Log.buf().append("NRotateBits=")
    					.append(matrix.nRotateBits).toString());
    		}
    		binary = BinUtil.toBinaryFromBytes(bufferArray, offset * 8 + nextRotateOffsetBits + 6, matrix.nRotateBits * 2);
    		matrix.rotateSkew0 = BinUtil.toSIntFromBinary(binary, 0, matrix.nRotateBits);
    		matrix.rotateSkew1 = BinUtil.toSIntFromBinary(binary, matrix.nRotateBits, matrix.nRotateBits);
    		if (DEBUG_LOGD) {
    			Log.d(LOG_TAG, Log.buf().append("RotateSkew0=").append(matrix.rotateSkew0 >> 16)
    					.append(".").append(matrix.rotateSkew0 & 0xffff)
    					.append(" RotateSkew1=").append(matrix.rotateSkew1 >> 16)
    					.append(".").append(matrix.rotateSkew1 & 0xffff).toString());
    		}
    		nextTranslateOffsetBits = nextRotateOffsetBits + 1 + 5 + matrix.nRotateBits * 2;
		} else {
			nextTranslateOffsetBits = nextRotateOffsetBits + 1;
		}
    	
		byte[] binary = BinUtil.toBinaryFromBytes(bufferArray, offset * 8 + nextTranslateOffsetBits, 5);
		matrix.nTranslateBits = BinUtil.toByteFromBinary(binary, 0, 5);
		if (DEBUG_LOGD) {
			Log.d(LOG_TAG, Log.buf().append("NTranslateBits=")
					.append(matrix.nTranslateBits).toString());
		}
		binary = BinUtil.toBinaryFromBytes(bufferArray, offset * 8 + nextTranslateOffsetBits + 5, matrix.nTranslateBits * 2);
		matrix.translateX = BinUtil.toSIntFromBinary(binary, 0, matrix.nTranslateBits);
		matrix.translateY = BinUtil.toSIntFromBinary(binary, matrix.nTranslateBits, matrix.nTranslateBits);
		if (DEBUG_LOGD) {
			Log.d(LOG_TAG, Log.buf().append("TranslateX=").append(matrix.translateX)
					.append(" TranslateY=").append(matrix.translateY).toString());
		}
    	
    	return offset + (nextTranslateOffsetBits + 5 + matrix.nTranslateBits * 2 + 7) / 8;
    }

	public void toMatrix(Matrix to) {
		MATRIX from = this;
		
		to.reset();
		if (from.hasScale) {
			to.postScale(
					(float) from.scaleX / 65536.0f,
					(float) from.scaleY / 65536.0f);
		}
		
		if (from.hasRotate) {
			to.postSkew(
					(float) from.rotateSkew0 / 65536.0f,
					(float) from.rotateSkew1 / 65536.0f);
		}
	
		to.postTranslate(
				(float) from.translateX,
				(float) from.translateY);
	}

}