package at.loup.filemanager.entities;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Lob;
import javax.persistence.Table;

import at.loup.commons.entities.AbstractEntityWithDefaultGenerator;
import at.loup.commons.utilities.ArgumentRuleUtilities;

@Entity
@Table(name = "binaries")
public class BinaryEntity extends AbstractEntityWithDefaultGenerator<BinaryEntity> {
	private static final long serialVersionUID = 4808540737164882902L;

	@Lob()
	@Column(length = 10000000, nullable = false)
	@Basic(fetch = FetchType.EAGER, optional = false)
	private byte[] data;

	// unique = false because different users might need control
	// of a different data element
	@Lob()
	@Column(length = 256, nullable = false, unique = false)
	@Basic(fetch = FetchType.LAZY, optional = false)
	private byte[] collisionHash;

	@Column(nullable = false)
	private Integer size;

	@Column(length = 12, nullable = false)
	private String uploaderIp;

	protected BinaryEntity() {

	}

	public byte[] getData() {
		return data;
	}

	public void setData(byte[] data) {
		ArgumentRuleUtilities.notNull("data", data);
		this.data = data;
		byte[] collisionHash = createCollisionHash(data);
		setCollisionHash(collisionHash);
		setSize(data.length);
	}

	public byte[] getCollisionHash() {
		return collisionHash;
	}

	public boolean checkCollisionHash(byte[] givenHash) {
		ArgumentRuleUtilities.notNull("givenHash", givenHash);
		boolean result = Arrays.equals(givenHash, getCollisionHash());
		return result;
	}

	public boolean checkCollisionHash(BinaryEntity otherEntity) {
		byte[] otherEntitiesCollisionHash = otherEntity.getCollisionHash();
		boolean result = checkCollisionHash(otherEntitiesCollisionHash);
		return result;
	}

	protected void setCollisionHash(byte[] collisionHash) {
		this.collisionHash = collisionHash;
	}

	public Integer getSize() {
		return size;
	}

	protected void setSize(Integer size) {
		this.size = size;
	}

	public String getUploaderIp() {
		return uploaderIp;
	}

	public void setUploaderIp(String uploaderIp) {
		this.uploaderIp = uploaderIp;
	}

	public static BinaryEntity create(byte[] data, String uploaderIp) {
		ArgumentRuleUtilities.notNull("data", data);
		BinaryEntity result = new BinaryEntity();
		result.setData(data);
		result.setUploaderIp(uploaderIp);
		return result;
	}

	public static byte[] createCollisionHash(byte[] input) {
		ArgumentRuleUtilities.notNull("input", input);
		MessageDigest messageDigestMD5;
		MessageDigest messageDigestMD2;
		try {
			messageDigestMD5 = MessageDigest.getInstance("MD5");
			messageDigestMD2 = MessageDigest.getInstance("MD2");
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(e);
		}
		// MD5 & MD2 hashes are each 128 bit long
		byte[] md5Hash = messageDigestMD5.digest(input);
		byte[] md2Hash = messageDigestMD2.digest(input);
		byte[] result = new byte[32];

		System.arraycopy(md5Hash, 0, result, 0, 16);
		System.arraycopy(md2Hash, 0, result, 16, 16);
		return result;
	}
}
