package jp.sourceforge.nicoro.swf;

import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;

import jp.sourceforge.nicoro.BinUtil;
import jp.sourceforge.nicoro.FailAnalyzeSwfException;
import jp.sourceforge.nicoro.Util;

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;

public class RECT {
	public byte nbits;		// UB[5]
	public int xmin;		// SB[Nbits] 最長31bit
	public int xmax;		// SB[Nbits] 最長31bit
	public int ymin;		// SB[Nbits] 最長31bit
	public int ymax;		// SB[Nbits] 最長31bit
	
    public int read(byte[] bufferArray, int offset) {
    	RECT rect = this;
    	
		if (DEBUG_LOGD) {
			Log.d(LOG_TAG, Log.buf().append("readRECT: offset=")
					.append(offset).toString());
		}
    	rect.nbits = (byte) ((bufferArray[offset] >> 3) & 0x1f);
    	if (DEBUG_LOGD) {
    		Log.d(LOG_TAG, Log.buf().append("Nbits=")
    				.append(rect.nbits).toString());
    	}
    	byte[] binary = BinUtil.toBinaryFromBytes(bufferArray, offset * 8 + 5, rect.nbits * 4);
    	rect.xmin = BinUtil.toSIntFromBinary(binary,
    			rect.nbits * 0, rect.nbits);
    	rect.xmax = BinUtil.toSIntFromBinary(binary,
    			rect.nbits * 1, rect.nbits);
    	rect.ymin = BinUtil.toSIntFromBinary(binary,
    			rect.nbits * 2, rect.nbits);
    	rect.ymax = BinUtil.toSIntFromBinary(binary,
    			rect.nbits * 3, rect.nbits);
    	if (DEBUG_LOGD) {
    		Log.d(LOG_TAG, Log.buf().append("Xmin=").append(rect.xmin)
    				.append(" Xmax=").append(rect.xmax)
    				.append(" Ymin=").append(rect.ymin)
    				.append(" Ymax=").append(rect.ymax).toString());
    	}
    	return offset + (5 + rect.nbits * 4 + 7) / 8;
    }
    
    public void read(InputStream inSwf) throws IOException, FailAnalyzeSwfException {
    	RECT rect = this;
    	
		if (DEBUG_LOGD) {
			Log.d(LOG_TAG, "readRECT");
		}
    	int size = inSwf.read();
    	if (size < 0) {
    		throw new FailAnalyzeSwfException("RECT read failed: " + size);
    	}
    	rect.nbits = (byte) ((size >> 3) & 0x1f);
    	if (DEBUG_LOGD) {
    		Log.d(LOG_TAG, Log.buf().append("Nbits=")
    				.append(rect.nbits).toString());
    	}
    	int rectSize = (5 + (rect.nbits * 4) + 7) / 8;
    	byte[] rectBufferArray = new byte[rectSize];
    	rectBufferArray[0] = (byte) size;
    	int readSize = Util.readComplete(inSwf, rectBufferArray, 1, rectSize - 1);
    	if (readSize != rectSize - 1) {
    		throw new FailAnalyzeSwfException("RECT read failed: " + readSize);
    	}
    	byte[] binary = BinUtil.toBinaryFromBytes(rectBufferArray, 5, rect.nbits * 4);
//    	if (DEBUG_LOGD) {
//    		StringBuilder log = new StringBuilder(binary.length);
//    		for (int i = 0; i < binary.length; ++i) {
//    			log.append((char) (binary[i] + '0'));
//    		}
//    		Log.d(LOG_TAG, "binary=" + log.toString());
//    	}
    	rect.xmin = BinUtil.toSIntFromBinary(binary,
    			rect.nbits * 0, rect.nbits);
    	rect.xmax = BinUtil.toSIntFromBinary(binary,
    			rect.nbits * 1, rect.nbits);
    	rect.ymin = BinUtil.toSIntFromBinary(binary,
    			rect.nbits * 2, rect.nbits);
    	rect.ymax = BinUtil.toSIntFromBinary(binary,
    			rect.nbits * 3, rect.nbits);
    	if (DEBUG_LOGD) {
    		Log.d(LOG_TAG, Log.buf().append("Xmin=").append(rect.xmin)
    				.append(" Xmax=").append(rect.xmax)
    				.append(" Ymin=").append(rect.ymin)
    				.append(" Ymax=").append(rect.ymax).toString());
    	}
    }

    public void read(RandomAccessFile inSwf) throws IOException, FailAnalyzeSwfException {
    	RECT rect = this;
    	
		if (DEBUG_LOGD) {
			Log.d(LOG_TAG, "readRECT");
		}
    	int size = inSwf.read();
    	if (size < 0) {
    		throw new FailAnalyzeSwfException("RECT read failed: " + size);
    	}
    	rect.nbits = (byte) ((size >> 3) & 0x1f);
    	if (DEBUG_LOGD) {
    		Log.d(LOG_TAG, Log.buf().append("Nbits=")
    				.append(rect.nbits).toString());
    	}
    	int rectSize = (5 + (rect.nbits * 4) + 7) / 8;
    	byte[] rectBufferArray = new byte[rectSize];
    	rectBufferArray[0] = (byte) size;
    	int readSize = Util.readComplete(inSwf, rectBufferArray, 1, rectSize - 1);
    	if (readSize != rectSize - 1) {
    		throw new FailAnalyzeSwfException("RECT read failed: " + readSize);
    	}
    	byte[] binary = BinUtil.toBinaryFromBytes(rectBufferArray, 5, rect.nbits * 4);
//    	if (DEBUG_LOGD) {
//    		StringBuilder log = new StringBuilder(binary.length);
//    		for (int i = 0; i < binary.length; ++i) {
//    			log.append((char) (binary[i] + '0'));
//    		}
//    		Log.d(LOG_TAG, "binary=" + log.toString());
//    	}
    	rect.xmin = BinUtil.toSIntFromBinary(binary,
    			rect.nbits * 0, rect.nbits);
    	rect.xmax = BinUtil.toSIntFromBinary(binary,
    			rect.nbits * 1, rect.nbits);
    	rect.ymin = BinUtil.toSIntFromBinary(binary,
    			rect.nbits * 2, rect.nbits);
    	rect.ymax = BinUtil.toSIntFromBinary(binary,
    			rect.nbits * 3, rect.nbits);
    	if (DEBUG_LOGD) {
    		Log.d(LOG_TAG, Log.buf().append("Xmin=").append(rect.xmin)
    				.append(" Xmax=").append(rect.xmax)
    				.append(" Ymin=").append(rect.ymin)
    				.append(" Ymax=").append(rect.ymax).toString());
    	}
    }
}
