package net.ranides.assira.observable;

import net.ranides.assira.collection.sets.ASet;
import net.ranides.assira.events.EventListener;
import net.ranides.assira.events.EventRouter;

import java.util.Collection;
import java.util.Iterator;
import java.util.Set;

public class ObservableSet<T> extends ASet<T> {

    private final EventRouter router;

    private final Set<T> collection;

    public ObservableSet(EventRouter router, Set<T> collection) {
        this.collection = collection;
        this.router = router;
    }

    public EventRouter router() {
        return router;
    }

    public <E extends CollectionEvent<T>> void addEventListener(Class<E> event, EventListener<? super E> listener) {
        router.addEventListener(event, listener);
    }

    @Override
    public Iterator<T> iterator() {
        return new CIterator(collection.iterator());
    }

    @Override
    public int size() {
        return collection.size();
    }

    @Override
    public boolean add(T t) {
        if (collection.add(t)) {
            router.signalEvent(new CollectionEvent.Add<>(collection, t));
            return true;
        }
        return false;
    }

    @Override
    public boolean remove(Object o) {
        if (collection.remove(o)) {
            router.signalEvent(new CollectionEvent.Remove<>(collection, (T) o));
            return true;
        }
        return false;
    }

    @Override
    public boolean addAll(Collection<? extends T> c) {
        if (collection.addAll(c)) {
            router.signalEvent(new CollectionEvent.AddMany<>(collection, c));
            return true;
        }
        return false;
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        if (collection.removeAll(c)) {
            router.signalEvent(new CollectionEvent.RemoveMany<>(collection, (Collection<T>) c));
            return true;
        }
        return false;
    }

    @Override
    public void clear() {
        boolean empty = collection.isEmpty();
        collection.clear();
        if (!empty) {
            router.signalEvent(new CollectionEvent.Clear<>(collection));
        }
    }

    private class CIterator extends ObservableIterator<T> {
        public CIterator(Iterator<T> itr) {
            super(itr);
        }

        @Override
        protected void signalRemove(T value) {
            router.signalEvent(new CollectionEvent.Remove<>(ObservableSet.this, value));
        }
    }
}
