package BFTSmartBlockchain;

import java.io.ByteArrayOutputStream;
import java.io.Serializable;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Set;

import org.apache.commons.codec.binary.Hex;

public class Block implements Serializable {

	public TreeSet<Transaction> transactions;
	public byte[] prevBlockHash;
	public byte[] blockHash;
	
	public Block(TreeSet<Transaction> transactions, byte[] prevBlockHash) {
		this.transactions = transactions;
		if (prevBlockHash != null) {
			this.prevBlockHash = prevBlockHash.clone();
		} else {
			this.prevBlockHash = null;
		}
		/* 
		 * Computes the SHA1 digest using the built-in function
		 */
		try {
			MessageDigest sha = MessageDigest.getInstance("SHA");
			blockHash = sha.digest(asByteArray());
		} catch (Exception e) {}
	}
	
	public boolean Verify() {
		/*
		 * Make sure the message hash is as specified
		 */
		try {
			MessageDigest sha = MessageDigest.getInstance("SHA");
			byte[] h = sha.digest(asByteArray());
			if (!Arrays.equals(h,  blockHash)) {
				return false;
			}
		} catch (Exception e) {
			return false;
		}
		/*
		 * Verify all transactions first
		 */
		for (Transaction t : transactions) {
			if (!t.Verify()) {
				return false;
			}
		}
		return true;
	}
	
	public byte[] asByteArray() {
		try {
			/*
			 * Write all transactions
			 */
			ByteArrayOutputStream stream = new ByteArrayOutputStream();
			for (Transaction t : transactions) {
				stream.write(t.asByteArray());
			}
			/*
			 * And then add the hash of the previous block
			 */
			if (prevBlockHash != null) {
				stream.write(prevBlockHash);
			}
			return stream.toByteArray();
		} catch (Exception e) {
			return null;
		}
	}
	
	public String toString() {
		if (prevBlockHash != null) {
		return "Block \n with hash: " + Hex.encodeHexString(blockHash) + 
					"\n with: " + transactions.size() + " transactions," +
					"\n and previous Hash: "+Hex.encodeHexString(prevBlockHash);
		} else {
			return "Block \n with hash: " + Hex.encodeHexString(blockHash) + 
					"\n with: " + transactions.size() + " transactions," +
					"\n and previous Hash: null";
		}
	}
}
