//
// Triple Play - utilities for use in PlayN-based games
// Copyright (c) 2011, Three Rings Design, Inc. - All rights reserved.
// http://github.com/threerings/tripleplay/blob/master/LICENSE

package tripleplay.ui;

import react.Slot;
import react.Value;
import react.ValueView;

/**
 * Maintains a single selected item among the children of <code>Elements</code>.<p>
 *
 * A click on a child that implements <code>Clickable</code> makes it the selected item, or
 * <code>setSelected</code> can be used to manually control the selected item.
 */
public class Selector
{
    /** The selected item. May be updated to set the selection manually. */
    public final Value<Element<?>> selected = Value.create(null);

    /** Create a selector with a null initial selection. */
    public Selector () {
        selected.connect(new ValueView.Listener<Element<?>> () {
            @Override public void onChange (Element<?> selected, Element<?> deselected) {
                if (deselected != null) {
                    deselected.set(Element.Flag.SELECTED, false);
                    deselected.invalidate();
                }
                if (selected != null) {
                    selected.set(Element.Flag.SELECTED, true);
                    selected.invalidate();
                }
            }
        });
    }

    /** Creates a selector containing the children of elements with initialSelection selected. */
    public Selector (Elements<?> elements, Element<?> initialSelection) {
        this();
        add(elements);
        selected.update(initialSelection);
    }

    /**
     * Tracks the children of <code>elements</code> for setting the selection.
     */
    public Selector add (Elements<?> elements) {
        for (Element<?> child : elements) {
            _childAddSlot.onEmit(child);
        }
        elements.childAdded().connect(_childAddSlot);
        elements.childRemoved().connect(_childRemoveSlot);
        return this;
    }

    /**
     * Stops tracking the children of <code>elements</code> for setting the selection.
    */
    public Selector remove (Elements<?> elements) {
        for (Element<?> child : elements) {
            _childRemoveSlot.onEmit(child);
        }
        elements.childAdded().disconnect(_childAddSlot);
        elements.childRemoved().disconnect(_childRemoveSlot);
        return this;
    }

    protected final Slot<Element<?>> _childAddSlot = new Slot<Element<?>>() {
        @Override public void onEmit (Element<?> child) {
            if (child instanceof Clickable<?>) {
                ((Clickable<?>)child).clicked().connect(_clickSlot);
            }
        }
    };

    protected final Slot<Element<?>> _childRemoveSlot = new Slot<Element<?>>() {
        @Override public void onEmit (Element<?> removed) {
            if (removed instanceof Clickable<?>) {
                ((Clickable<?>)removed).clicked().disconnect(_clickSlot);
            }
            if (selected.get() == removed) selected.update(null);
        }
    };

    protected final Slot<Element<?>> _clickSlot = new Slot<Element<?>>() {
        @Override public void onEmit (Element<?> clicked) {
            selected.update(clicked);
        }
    };

}

@@ -473,11 +473,8 @@
 e%3Ese
-tSe
 lect
@@ -1012,95 +1012,33 @@
    d
-es
+oS
 elect
-ed.set(Element.Flag.SELECTED, false);%0A                    deselected.invalidate(
+(deselected, false
 );%0A 
@@ -1118,91 +1118,31 @@
     
-s
+doS
 elect
-ed.set(Element.Flag.SELECTED, true);%0A                    selected.invalidate(
+(selected, true
 );%0A 
@@ -2227,24 +2227,413 @@
 his;%0A    %7D%0A%0A
+    protected void doSelect (Element%3C?%3E elem, boolean state) %7B%0A        // TODO: do we need a Selectable interface to better abstract this kind of signal?%0A        if (elem instanceof TogglableTextWidget) %7B%0A            ((TogglableTextWidget%3C?%3E)elem).selected.update(state);%0A        %7D else %7B%0A            elem.set(Element.Flag.SELECTED, state);%0A            elem.invalidate();%0A        %7D%0A    %7D%0A%0A
     protecte

Handle toggle widgets specially