
package spacewar;

import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;

/**
 * The Registry keeps track of all the space objects that are floating around.
 * It basically supports register, unregister and contents type operations.
 *
 * The synchronization is done by the RegistrySynchronization aspect.
 */

class Registry {

    private Hashtable table;
    private Game      game;

    Game getGame() { return game; }

    Registry (Game theGame) {
        game = theGame;
        table = new Hashtable();
    }


    void register(SpaceObject object) {
        table.put(object, object);
    }

    void unregister(SpaceObject object) {
        table.remove(object);
    }

    /*
     * It is an invariant of the design that only two points in SpaceObject
     * should call register and unregister.  This aspect enforces that.
     *
     * Unfortunately, in the current compiler, we get a static warning when
     * there are no illegal calls that this advice has no targets.  That will
     * be fixed in a future release.  For the time being the dummy method
     * just below this fixes that.
     */
    static aspect RegistrationProtection {
        after() returning():
            (call(void Registry.register(SpaceObject)) ||
             call(void Registry.unregister(SpaceObject))) &&
            !(within(SpaceObject) && (withincode(new(..)) ||
                                      withincode(void die()))) {
            throw new IllegalAccessError(
               "This is an illegal call to " + thisJoinPoint + "\n" +
               "Only the constructor and the die() on SpaceObject\n" +
               "should call the primitive registry operations.");
        }
    }

    void dummy() {        // see comment above
        register(getObjects()[0]);
        unregister(getObjects()[0]);
    }


    SpaceObject[] getObjects() {
        SpaceObject[] allObjects = new SpaceObject[table.size()];
        Enumeration elements = table.elements();
        for(int i = 0; elements.hasMoreElements(); i++) {
            allObjects[i] = (SpaceObject)(elements.nextElement());
        }
        return allObjects;
    }

    Ship[] getShips() {
        //
        // First we have to put just the Ships into a vector, then we can put
        // them into an array of exactly the right length.
        //
        Ship[]  arrayOfShips;
        Vector vectorOfShips = new Vector();
        Enumeration elements = table.elements();
        while (elements.hasMoreElements()) {
            Object object = elements.nextElement();
            if (object instanceof Ship) {
                vectorOfShips.addElement(object);
            }
        }

        arrayOfShips = new Ship[(vectorOfShips.size())];
        vectorOfShips.copyInto(arrayOfShips);
        return arrayOfShips;
    }

    Hashtable getTable() { return table; }

    //
    // The protocol for clockTick is that it automatically cascades.
    //
    void clockTick() {
        Enumeration elements = table.elements();
        while (elements.hasMoreElements()) {
            ((SpaceObject)elements.nextElement()).clockTick();
        }
    }
}

