package pp.iloc.eval;

import java.util.Arrays;

/** Simulated memory. */
public class Memory {
	/** The default size of the memory, in number of bytes. */
	public final static int DEFAULT_SIZE = 10000;
	/** The memory array. */
	private byte[] mem = new byte[DEFAULT_SIZE];

	/** Reinitialises the memory to a certain size. */
	public void setSize(int size) {
		this.mem = new byte[size];
	}

	/** Sets a location in memory to a given value. */
	public void set(int loc, byte value) {
		this.mem[loc] = value;
	}

	/**
	 * Returns the value at a given memory location. The value is 0 if the
	 * location was never accessed before.
	 */
	public byte get(int loc) {
		return this.mem[loc];
	}

	/** Returns the size of the used memory. */
	public int size() {
		return this.mem.length;
	}

	/** Removes all values from the memory. */
	public void clear() {
		Arrays.fill(this.mem, (byte) 0);
	}

	/**
	 * Returns the heap area of this memory for a given machine using memlib.
	 * 
	 * @param m
	 *            the machine to which this memory belongs
	 * @return the heap space of this memory
	 */
	public String toString(Machine m) {
		StringBuilder result = new StringBuilder();
		int loc = 4;

		System.err.flush();

		while (loc != 0 && loc < m.getReg("brk")) {
			int size = m.load(loc + 4);
			int nloc = m.load(loc);

			if (!(size == 0 && nloc == 0)) {
				result.append(String.format("0x%05x  ", loc + 8));

				if ((nloc >= m.load(0) && nloc > loc) || nloc == 0)
					result.append("   free");
				else
					result.append(String.format("% 2d ref ", m.load(loc)));

				for (int i = 0; i < size && i < 40; i += 4) {
					if (m.load(loc + 8 + i) == 0)
						result.append("........");
					else
						result.append(String.format("%8x", m.load(loc + 8 + i)).replace(" ", "."));
					result.append(" ");
				}
				result.append(size > 40 ? "...\n" : "\n");
			}
			loc += size + 8;
		}

		return result.toString();
	}

	@Override
	public String toString() {
		StringBuilder result = new StringBuilder();
		int lineLength = 4 * 8;

		for (int base = 0; base < this.mem.length; base += lineLength) {
			result.append(String.format("0x%08x ", base));
			for (int offset = 0; offset < lineLength && base + offset < this.mem.length; offset++) {
				if (offset % 4 == 0 && offset > 0)
					result.append(" ");

				result.append(String.format("%02x", this.mem[base + offset]));
			}
			result.append("\n");
		}
		return result.toString();
	}
}
