package org.xbib.io.webdav.common;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xbib.io.webdav.api.EventBundle;
import org.xbib.io.webdav.api.Namespace;
import org.xbib.io.webdav.api.Subscription;
import org.xbib.io.webdav.api.XMLizable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * <code>EventDiscovery</code> represents the request body of a successful
 * POLL request. It reveals all events that occurred since the last POLL. The
 * definition what events that particular subscription is interested in was
 * specified with the initial SUBSCRIPTION that started the event listening.
 */
public class EventDiscovery implements XMLizable {

    private static final Namespace DCR_NAMESPACE = Namespace.getNamespace("dcr", "http://www.day.com/jcr/webdav/1.0");

    private final List<EventBundle> bundles = new ArrayList<>();

    /**
     * Add the Xml representation of an single 'eventBundle' listing the
     * events that resulted from a change in the server, filtered by the
     * restrictions present in the corresponding subscription.
     *
     * @param eventBundle
     * @see Subscription
     */
    public void addEventBundle(EventBundle eventBundle) {
        if (eventBundle != null) {
            bundles.add(eventBundle);
        }
    }

    /**
     * Returns an iterator over the {@link EventBundle event bundles} currently
     * present on this discovery.
     *
     * @return iterator over event bundles present.
     */
    public Iterator<EventBundle> getEventBundles() {
        return bundles.iterator();
    }

    /**
     * Returns true, if this event discovery does not report any events (thus
     * {@link #getEventBundles()} would return an empty iterator.
     *
     * @return true if {@link #getEventBundles()} would return an empty iterator,
     * false otherwise.
     */
    public boolean isEmpty() {
        return bundles.isEmpty();
    }

    /**
     * Returns the XML representation of this <code>EventDiscovery</code> as
     * being present in the POLL response body.
     *
     * @param document
     * @return Xml representation
     * @see XMLizable#toXml(Document)
     */
    @Override
    public Element toXml(Document document) {
        Element ed = DomUtil.createElement(document, "eventdiscovery", DCR_NAMESPACE);
        for (EventBundle bundle : bundles) {
            ed.appendChild(bundle.toXml(document));
        }
        return ed;
    }

    /**
     * Build a <code>EventDiscovery</code> from the specified xml element.
     *
     * @param eventDiscoveryElement
     * @return new <code>EventDiscovery</code> instance.
     * @throws IllegalArgumentException if the given document is <code>null</code>
     *                                  or does not provide the required element.
     */
    public static EventDiscovery createFromXml(Element eventDiscoveryElement) {
        if (!DomUtil.matches(eventDiscoveryElement, "eventdiscovery", DCR_NAMESPACE)) {
            throw new IllegalArgumentException(
                    "{" + DCR_NAMESPACE + "}" + "eventdiscovery" + " element expected, but got: {"
                            + eventDiscoveryElement.getNamespaceURI() + "}" + eventDiscoveryElement.getLocalName());
        }
        EventDiscovery eventDiscovery = new EventDiscovery();
        ElementIterator it = DomUtil.getChildren(eventDiscoveryElement, "eventbundle", DCR_NAMESPACE);
        while (it.hasNext()) {
            final Element ebElement = it.nextElement();
            EventBundle eb = new EventBundle() {
                public Element toXml(Document document) {
                    return (Element) document.importNode(ebElement, true);
                }
            };
            eventDiscovery.addEventBundle(eb);
        }
        return eventDiscovery;
    }
}
