package scratchlib.objects;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;


/**
 * Maps instances of {@link ScratchObject} to reference IDs, offering insertion,
 * lookup and iteration methods.
 */
public class ScratchReferenceTable implements Iterable<ScratchObject>
{
    private final List<ScratchObject> references = new ArrayList<>();

    /**
     * Performs a reference lookup for the given {@link ScratchObject}.
     * 
     * @param object The object to look up.
     * @return The object's reference ID, or -1 if not found.
     */
    public int lookup(ScratchObject object)
    {
        int index = references.indexOf(object);
        return index == -1 ? index : index + 1;
    }

    /**
     * Performs an object lookup for the given reference ID.
     * 
     * @param referenceID The ID to look up.
     * @return The referenced object, or null if not found.
     */
    public ScratchObject lookup(int referenceID)
    {
        return references.get(referenceID - 1);
    }

    /**
     * Inserts the given {@link ScratchObject} into this reference table. The ID
     * is determined automatically.
     * 
     * @param object The object to insert.
     */
    public void insert(ScratchObject object)
    {
        if (references.stream().anyMatch(r -> r == object)) {
            throw new IllegalArgumentException("object already referenced");
        }
        references.add(object);
    }

    /**
     * @return The number of references stored.
     */
    public int size()
    {
        return references.size();
    }

    @Override
    public Iterator<ScratchObject> iterator()
    {
        return references.iterator();
    }
}

@@ -22,16 +22,44 @@
 jects;%0A%0A
+import java.io.IOException;%0A
 import j
@@ -129,16 +129,105 @@
 .List;%0A%0A
+import scratchlib.project.ScratchProject;%0Aimport scratchlib.writer.ScratchOutputStream;%0A%0A
 %0A/**%0A * 
@@ -1804,11 +1804,839 @@
 );%0A    %7D
+%0A%0A    /**%0A     * Convenience method. If the object is inline, it is written out directly%0A     * via its %7B@code writeTo(...)%7D method; otherwise, the reference stored for%0A     * it in this table is written instead.%0A     * %0A     * %3Cp%3E%0A     * This is useful for fields of other objects.%0A     * %0A     * @param o The object to write.%0A     * @param out The stream to write to.%0A     * @param project The project the object is part of.%0A     * @throws IOException%0A     */%0A    public void writeField(ScratchObject o, ScratchOutputStream out,%0A            ScratchProject project) throws IOException%0A    %7B%0A        int ref = lookup(o);%0A%0A        if (!(o instanceof IScratchReferenceType) %7C%7C ref %3C 1) %7B%0A            o.writeTo(out, this, project);%0A            return;%0A        %7D%0A%0A        out.write(99);%0A        out.write24bitUnsignedInt(ref);%0A    %7D
 %0A%7D%0A

Add ScratchReferenceTable.writeField()