/**
 * 
 */
package mathsquared.resultswizard2;

import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;

/**
 * Handles communication between client and server, including slide selection.
 * 
 * @author MathSquared
 * 
 */
public class ProtocolSelector implements Selector {
    private int width;
    private int height;

    private LinkedHashMap<String, Slide[]> slides; // stores the slides to display
    private String currentTag; // the current key in the map where to find the current slide
    private int currentIndex; // the index in the array given by currentTag

    public ProtocolSelector (int width, int height) {
        this.width = width;
        this.height = height;

        slides = new LinkedHashMap<String, Slide[]>();
    }

    public Slide getCurrent () {
        if (currentTag == null) {
            return null;
        }
        if (!slides.containsKey(currentTag)) {
            return null;
        }
        if (slides.size() == 0) {
            return null; // this also checks that locateNextString won't IOOBE due to no entries in the key set
        }

        // Create duplicate field values to mess with (to canonicalize what we return)
        String tag = currentTag;
        int idx = currentIndex;

        // Ensure idx is in bounds
        if (idx < 0) {
            idx = 0;
        }
        if (idx > slides.get(tag).length) {
            // Move to the next tag; continue while there are no slides in the current one
            String origTag = tag; // ensure we don't wrap around the keySet
            do {
                tag = locateNextString(tag);
            } while (slides.get(tag).length == 0 && origTag != tag);
            idx = 0;
        }

        return slides.get(tag)[idx];
    }

    private String locateNextString (String current) {
        LinkedList<String> keys = new LinkedList<String>();
        keys.addAll(slides.keySet());
        Iterator<String> iter = keys.iterator();

        // Iterate while we have entries until we skip over an entry equal to current
        while (iter.hasNext() && !iter.next().equals(current));

        // If we're out of entries, return the first one
        if (!iter.hasNext()) {
            return keys.get(0);
        }

        // Return the next string
        return iter.next();
    }
}

@@ -129,16 +129,38 @@
 kedList;
+%0Aimport java.util.Map;
 %0A%0A/**%0A *
@@ -410,18 +410,20 @@
 g, Slide
-%5B%5D
+List
 %3E slides
@@ -791,10 +791,12 @@
 lide
-%5B%5D
+List
 %3E();
@@ -1420,22 +1420,22 @@
 et(tag).
-length
+size()
 ) %7B%0A    
@@ -1700,14 +1700,14 @@
 ag).
-length
+size()
  == 
@@ -1794,13 +1794,1987 @@
 tag)
-%5Bidx%5D
+.get(idx);%0A    %7D%0A%0A    public Command processMessage (Command msg) %7B%0A        switch (msg.getType()) %7B%0A        case POISON:%0A        case XMIT_ERROR_RESTART:%0A            currentTag = null;%0A            break;%0A        case ADD:%0A            slides.putAll(msg.getStringSlideListPayload());%0A            break;%0A        case REMOVE:%0A            slides.remove(msg.getStringPayload());%0A            break;%0A        case RETR_SLIDES:%0A            return new Command() %7B%0A                // Carry the slides along with the command%0A                private LinkedHashMap%3CString, SlideList%3E carriedSlides = new LinkedHashMap%3CString, SlideList%3E(slides);%0A%0A                public Message getType () %7B%0A                    return Message.RESP_SLIDES;%0A                %7D%0A%0A                public String getStringPayload () %7B%0A                    throw new UnsupportedOperationException(%22RESP_SLIDES does not carry a String payload%22);%0A                %7D%0A%0A                public Map%3CString, SlideList%3E getStringSlideListPayload () %7B%0A                    return new LinkedHashMap%3CString, SlideList%3E(carriedSlides);%0A                %7D%0A            %7D;%0A            // break; (unreachable)%0A        case TICKER:%0A            // TODO ticker not supported%0A            break;%0A        case RETR_TICKER:%0A            return new Command() %7B%0A                public Message getType () %7B%0A                    return Message.RESP_TICKER;%0A                %7D%0A%0A                public String getStringPayload () %7B%0A                    return %22%22;%0A                %7D%0A%0A                public Map%3CString, SlideList%3E getStringSlideListPayload () %7B%0A                    throw new UnsupportedOperationException(%22RESP_TICKER does not carry a Map%3CString, SlideList%3E payload%22);%0A                %7D%0A            %7D;%0A            // break; (unreachable)%0A        case RESP_SLIDES: // we don't expect these cases%0A        case RESP_TICKER:%0A            break;%0A        %7D%0A%0A        // if we haven't already returned, nothing to send to the client%0A        return null
 ;%0A  

Add processMessage