package org.vaadin.smartgwt.server.core;
import static com.google.common.base.Preconditions.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import com.google.common.collect.Lists;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.ui.Component;
public class ComponentList<E extends Component> implements ComponentProperty, Iterable<E> {
private final Component parent;
private final List<E> components = Lists.newArrayList();
private final List<Instruction<E>> instructions = Lists.newArrayList();
private final String tagName;
public ComponentList(Component parent, String tagName) {
this.parent = parent;
this.tagName = tagName;
}
public void add(E e) {
e.setParent(parent);
components.add(e);
instructions.add(new Instruction<E>("add", e));
}
public void add(int index, E element) {
element.setParent(parent);
components.add(index, element);
instructions.add(new Instruction<E>("add", index, element));
}
public void addAll(Collection<? extends E> c) {
for (E e : c) {
e.setParent(parent);
add(e);
}
}
public void remove(E e) {
final int index = components.indexOf(e);
if (components.remove(e)) {
instructions.add(new Instruction<E>("remove", index, e));
}
}
/**
* Removes element that was removed on the client-side.
*
* @param element that was removed from the client.
*/
public void clientRemoved(E element) {
components.remove(element);
}
public E get(int index) {
return components.get(index);
}
public E set(int index, E element) {
checkPositionIndex(index, components.size());
element.setParent(parent);
final E oldElement = components.set(index, element);
instructions.add(new Instruction<E>("remove", index, oldElement));
instructions.add(new Instruction<E>("add", index, element));
return oldElement;
}
public void clear() {
for (Iterator<E> iterator = iterator(); iterator.hasNext();) {
iterator.next();
iterator.remove();
}
}
public E[] toArray(E[] a) {
return new ArrayList<E>(components).toArray(a);
}
public boolean contains(Object o) {
return components.contains(o);
}
public int indexOf(Object o) {
return components.indexOf(o);
}
@Override
public void paintContent(PaintTarget target) throws PaintException {
target.startTag(tagName);
target.addAttribute("type", "List");
for (Component component : components) {
component.paint(target);
}
if (target.isFullRepaint()) {
for (E component : components) {
new Instruction<E>("add", component).paintContent(target);
}
} else {
for (Instruction<E> instruction : instructions) {
instruction.paintContent(target);
}
}
instructions.clear();
target.endTag(tagName);
}
@Override
public Iterator<E> iterator() {
return new ComponentIterator(components.iterator());
}
private class ComponentIterator implements Iterator<E> {
private final Iterator<E> source;
private E next;
public ComponentIterator(Iterator<E> source) {
this.source = source;
}
@Override
public boolean hasNext() {
return source.hasNext();
}
@Override
public E next() {
return next = source.next();
}
@Override
public void remove() {
source.remove();
instructions.add(new Instruction<E>("remove", next));
}
}
private static class Instruction<E extends Component> {
private final E element;
private final Integer index;
private final String name;
public Instruction(String name, E element) {
this.name = name;
this.index = null;
this.element = element;
}
public Instruction(String name, int index, E element) {
this.name = name;
this.index = index;
this.element = element;
}
public void paintContent(PaintTarget target) throws PaintException {
target.startTag(name);
if (index != null) {
target.addAttribute("index", index);
}
if (element != null) {
target.addAttribute("element", element);
detachRemovedElement();
}
target.endTag(name);
}
private void detachRemovedElement() {
if ("remove".equals(name)) {
element.setParent(null);
}
}
}
}