Entry.java

package org.microspace.table;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.List;

import org.microspace.exception.IllegalOperationException;
import org.microspace.table.column.Accessor;
import org.microspace.table.column.GetSetPair;
import org.microspace.table.column.Getter;
import org.microspace.table.column.Setter;

/**
 * A tracker object used by Tables.
 * 
 * @author Gaspar Sinai - {@literal gaspar.sinai@microspace.org}
 * @version 2016-06-26
 * @param <T> is the type of the Table.
 */

public class Entry<T> implements Comparable<Entry<T>> {
	
	T spaceEntry;
	Object key;
	final Accessor<T> accessor;
	
	BigInteger updateCount;
	boolean removed;
	Object[] fields;
	byte[] bytes;
	
	public Entry (T entry, Accessor<T> accessor) {
		this(entry, accessor, null);
	}
	
	public Entry (T entry, Accessor<T> accessor, BigInteger updateCount) {
		this.spaceEntry = entry;
		this.accessor = accessor;
        this.updateCount = updateCount;
        this.removed = false;
        this.fields = new Object[accessor.getGetSetPairs().size()];
        this.bytes = null;
        List<GetSetPair<T>> getters = accessor.getGetSetPairs();
		for (int i=0; i<getters.size(); i++) {
			Getter<T> getter = getters.get(i);
			Object o = getter.get (spaceEntry);
			fields[i] = o;
		}
		this.key = accessor.getPrimaryKeyGetSetPair().get(spaceEntry);
	}
	
	public Object getPrimaryKey () {
		return this.key;
	}
	/**
	 * Make a shallow copy of fields and entry.
	 * @param entry the entry to copy from
	 */
	public Entry (Entry<T> entry) {
		this.spaceEntry = entry.spaceEntry;
		this.accessor = entry.accessor;
		this.updateCount = entry.updateCount;
		this.removed = entry.removed;
		this.bytes = entry.bytes;
		this.fields = new Object [entry.fields.length];
		for (int i=0; i<fields.length; i++) {
			fields[i] = entry.fields[i];
		}
		this.key = entry.key;
		this.spaceEntry = accessor.getBlankObject();
		List<GetSetPair<T>> getSet = accessor.getGetSetPairs();
		if (getSet.size() != fields.length) {
			throw new IllegalOperationException ("Field size mismatch");
		}
		// The fields array is the correct representation of the object
		for (int i=0; i<getSet.size(); i++) {
			getSet.get(i).set (spaceEntry, entry.fields[i]);
		}
	}
	
	public void serialize () throws IOException {
		List<GetSetPair<T>> pairs = accessor.getGetSetPairs();
		Object fields[] = new Object[pairs.size()];
		for (int i=0; i<pairs.size(); i++) {
			fields[i] = pairs.get(i).get(spaceEntry);
		}
		ByteArrayOutputStream os = new ByteArrayOutputStream ();
		ObjectOutputStream oos = new ObjectOutputStream (os);
		oos.writeObject (fields);
		oos.close ();
		bytes = os.toByteArray();
	}
	
	public Object getField (int index) {
		return this.fields[index];
	}
	
	public Object[] getFields () {
		return Arrays.copyOf(fields, fields.length);
	}
	
	public void setRemoved (boolean removed) {
		this.removed = removed;
	}
	
	public boolean isRemoved () {
		return removed;
	}

	public T getSpaceEntry () {
		return spaceEntry;
	}
	
	public T getEntryCopy () {
		T ret = accessor.getBlankObject();
		List<GetSetPair<T>> getSet = accessor.getGetSetPairs();
		if (getSet.size() != fields.length) {
			throw new IllegalOperationException ("Field size mismatch");
		}
		// The fields array is the correct representation of the object
		for (int i=0; i<getSet.size(); i++) {
			Setter<T> setter = getSet.get(i);
			setter.set (ret, fields[i]);
		}
		return ret;
	}
	
	public BigInteger getUpdateCount() {
		return updateCount;
	}
	
	public void setUpdateCount(BigInteger updateCount) {
		this.updateCount = updateCount;
	}
	@Override
	public int compareTo (Entry<T> o) {
		return updateCount.compareTo (o.updateCount);
	}
	
	@Override
	public boolean equals (Object o) {
		if (! (o instanceof Entry)) return false;
		@SuppressWarnings("unchecked")
		Entry<T> oa = (Entry<T>) o;
		return compareTo(oa) == 0;
	}
	@Override
	public int hashCode () {
		return updateCount.intValue();
	}
	public Accessor<T> getAccessor() {
		return accessor;
	}
	
}