package projectEQ2440.QRcode.info;

/**
 * <b>public class Frame extends FrameConst</b><br/>
 * Class managing the frame number codeWord in the QR code
 */
public class Frame extends FrameConst {
	
	// the frame number
	private int frameNumber;
	
	/**
	 * <b>public Frame(int frameNumber)</b><br/>
	 * Constructor for encoding
	 * 
	 * @param frameNumber : the current frame
	 */
	public Frame(int frameNumber) {
		this.frameNumber = frameNumber;
	}
	
	/**
	 * <b>public Frame(boolean[] codeWord)</b><br/>
	 * Constructor for decoding
	 * 
	 * @param codeWord : the codeWord with the frame number
	 */
	public Frame(boolean[] codeWord) {
		if (codeWord == null) frameNumber = -1;
		else if (codeWord.length != 24) frameNumber = -1;
		else frameNumber = decode(spread(codeWord));
	}
	
	/**
	 * <b>public int frame()</b><br/>
	 * Gives the frame number
	 * @return frame number
	 */
	public int frame() {
		return frameNumber;
	}
	
	/**
	 * <b>public boolean[] codeWord()</b><br/>
	 * Gives the codeword to put in the QR code
	 * 
	 * @return : the codeWord
	 */
	public boolean[] codeWord() {
		if (frameNumber < 0 || frameNumber>255) return null;
		return spread(tableFrame[frameNumber]);
	}
	
	/**
	 * <b>private boolean[] spread(boolean[] codeWord)</b><br/>
	 * Apply the spread sequence
	 * 
	 * @param codeWord : the codeWord on which apply the spread seauence
	 * @return the final codeWord
	 */
	private boolean[] spread(boolean[] codeWord) {
		boolean[] tmp = new boolean[24];
		for (int k=0; k<24; k++) tmp[k] = codeWord[k]^spreadSequence[k];
		return tmp;
	}
	
	/**
	 * <b>private static int decode(boolean[] format)</b><br/>
	 * decode the codeWord transforming directly the values and return the frame number<br/>
	 * The length of the input must be 24
	 * 
	 * @param format : boolean array representing the Frame to decode
	 * @return the best frame number
	 */
	private static int decode(boolean[] codeWord) {
		int minDist = distance(codeWord, tableFrame[0]);
		int minInd = 0;		
	    int distance, k;
		
		for (k=1; k<256; k++) {
			distance = distance(codeWord, tableFrame[k]);
			if (distance<minDist) {
				minDist = distance;
				minInd = k;
			}
			if (minDist == 0) break;
		}
		
		return minInd;
	}
	
	/**
	 * <b>private int distance(boolean[] b1, boolean[] b2)</b><br/>
	 * Function returning the distance between to boolean array<br/>
	 * The length of the input must be 24
	 * 
	 * @param b1 : First boolean Array
	 * @param b2 : Second boolean Array
	 * @return the distance between two
	 */
	private static int distance(boolean[] b1, boolean[] b2) {
		int k, distance = 0;
		
		for (k=0; k<24; k++) {
			if (b1[k]^b2[k]) distance++;
		}
		
		return distance;
	}
}
