package projectEQ2440.QRcode.ReedSolomon.GaloisField;

/**
 * <b>public class Galois</b><br/>
 * Galois Field
 */
public class Galois extends GaloisConst {
	
	// The equivalent value
	private byte equivalent_value;
	
	/**
	 * <b>public Galois(byte equi)</b><br/>
	 * Constructor gives the Galois number based on an byte
	 * 
	 * @param equi : Byte on which is based this Galois number 
	 */
	public Galois(byte equi) {
		equivalent_value = equi;
	}

	/**
	 * <b>public Galois clone()</b><br/>
	 * Clone the Galois number
	 *  
	 * @return A copy of this Galois Number
	 */
	public Galois clone() {
		return new Galois(equivalent_value);
	}
	
	/**
	 * <b>public String toString()</b><br/>
	 * Return a string representation of the equivalent byte
	 * 
	 * @return The string representation 
	 */
	public String toString() {
		return ("" + (equivalent_value & 0xFF));
	}
	
	/**
	 * <b>public byte toByte()</b><br/>
	 * Return the equivalent value as byte
	 * 
	 * @return The equivalent byte 
	 */
	public byte toByte() {
		return equivalent_value;
	}
	
	/**
	 * <b></b><br/>
	 * Test if the Galois number is null (equivalent to zero)
	 *  
	 * @return A boolean if it's null or not
	 */
	public boolean isNull() {
		return (equivalent_value == 0x00);
	}

	/**
	 * <b>public int log()</b><br/>
	 * Return the logarithm value of the galois number
	 * 
	 * @return The logarithm as integer
	 */
	public int log() {
		return table_log[(int) (equivalent_value & 0xFF)];
	}

	/**
	 * <b>public boolean inv()</b><br/>
	 * Invert the actual Galois number (equivalent to put it at power 254)
	 * Doesn't work if the actual Galois number is null
	 * 
	 * @return A boolean if it worked
	 */
	public boolean inv() {
		if (isNull()) {
			return false;
		} else {
			equivalent_value = table_pow[(255-log())%255];
		}
		return true;
	}

	/**
	 * <b>public boolean add(Galois g)</b><br/>
	 * Add a Galois number to the actual galois number
	 * 
	 * @param g : the Galois number to add
	 * @return a boolean if it worked
	 */
	public boolean add(Galois g) {
		equivalent_value = (byte) (equivalent_value ^ g.toByte());
		return true;
	}
	
	/**
	 * <b>public boolean prod(Galois g)</b><br/>
	 * Multiply a Galois number to the actual galois number
	 * 
	 * @param g : the Galois number to multiply
	 * @return a boolean if it worked
	 */
	public boolean prod(Galois g) {
		if (isNull()) {
			return true;
		} else if (g.isNull()) {
			equivalent_value = 0;
		} else {
			equivalent_value = table_pow[(log()+g.log())%255];
		}
		return true;
	}
	
	/**
	 * <b>public boolean div(Galois g)</b><br/>
	 * Dived a Galois number to the actual galois number
	 * Doesn't worked if the the Galois number is null
	 * 
	 * @param g : the Galois number to dived
	 * @return a boolean if it worked
	 */
	public boolean div(Galois g) {
		if (isNull()) {
			return true;
		} else if (g.isNull()) {
			return false;
		} else {
			equivalent_value = table_pow[(log()+255-g.log())%255];
		}
		return true;
	}
	
	/**
	 * <b>public static Galois inv(Galois g)</b><br/>
	 * Return the invert of a given Galois number
	 * 
	 * @param g : Galois number to invert
	 * @return The invert of the Galois number
	 */
	public static Galois inv(Galois g) {
		Galois h = g.clone();
		if (h.inv()) return h;
		else return null;
	}
	
	/**
	 * <b>public static Galois pow(int power)</b><br/>
	 * Return the Galois number link to the power of the primitive : 2^power
	 * 
	 * @param power : power to apply
	 * @return The Galois number link to the power 
	 */
	public static Galois pow(int power) {
		while (power<0) power += 255; 
		return new Galois(table_pow[power%255]);
	}
	
	/**
	 * <b>public static Galois add(Galois g1, Galois g2)</b><br/>
	 * Add two Galois number
	 * 
	 * @param g1 : First Galois number
	 * @param g2 : Second Galois number
	 * @return The Galois number which is the addition of the two
	 */
	public static Galois add(Galois g1, Galois g2) {
		return new Galois( (byte) (g1.toByte() ^ g2.toByte()) );
	}
	
	/**
	 * <b>public static Galois prod(Galois g1, Galois g2)</b><br/>
	 * Multiply two Galois number
	 * 
	 * @param g1 : first Galois number
	 * @param g2 : second Galois number
	 * @return The product of the two Galois number
	 */
	public static Galois prod(Galois g1, Galois g2) {
		Galois g3 = g1.clone();
		if (g3.prod(g2)) return g3;
		else return null; 
	}

	/**
	 * <b>public static Galois div(Galois g1, Galois g2)</b><br/>
	 * Divide 2 Galois number
	 * 
	 * @param g1 : dividend 
	 * @param g2 : divisor
	 * @return The division of the two
	 */
	public static Galois div(Galois g1, Galois g2) {
		Galois g3 = g1.clone();
		if (g3.div(g2)) return g3;
		else return null; 
	}
	
	/* 
	 * Supplementary functions
	 */
	
	/**
	 * <b>public Galois prodiv(int log1, int log2)</b><br/>
	 * return the actual Galois number multiply by a^log1 and divide by b^log2
	 * 
	 * @param log1 : the log of the multiplication factor
	 * @param log2 : the log of the division factor
	 * @return The result
	 */
	public Galois prodiv(int log1, int log2) {
		if (isNull()) return new Galois((byte) 0x00);
		int n = log() + log1 + 255 - log2;
		return pow(n);
	}
}
