package org.xbib.io.webdav.client;

import static org.xbib.io.webdav.api.DavConstants.NAMESPACE;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xbib.io.webdav.api.Namespace;
import org.xbib.io.webdav.api.XMLizable;
import org.xbib.io.webdav.common.DavException;
import org.xbib.io.webdav.common.DomUtil;
import org.xbib.io.webdav.common.ElementIterator;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * <code>OptionsInfo</code> represents the Xml request body, that may be present
 * with a OPTIONS request.
 * <br>
 * The DAV:options element is specified to have the following form.
 *
 * <pre>
 * &lt;!ELEMENT options ANY&gt;
 * ANY value: A sequence of elements each at most once.
 * </pre>
 */
public class OptionsInfo implements XMLizable {

    /**
     * If the OPTIONS request contains a body, i must start with an DAV:options
     * element.
     *
     * @see OptionsInfo
     */
    private static final String XML_OPTIONS = "options";

    private final Set<String> entriesLocalNames = new HashSet<String>();

    /**
     * Create a new OptionsInfo with the specified entries. Each entry will
     * be converted to an empty Xml element when calling <code>toXml</code>
     *
     * @param entriesLocalNames
     */
    public OptionsInfo(String[] entriesLocalNames) {
        if (entriesLocalNames != null) {
            this.entriesLocalNames.addAll(Arrays.asList(entriesLocalNames));
        }
    }

    /**
     * Private constructor used to create an OptionsInfo from Xml.
     */
    private OptionsInfo() {
    }

    /**
     * Returns true if a child element with the given name and namespace is present.
     *
     * @param localName
     * @param namespace
     * @return true if such a child element exists in the options element.
     */
    public boolean containsElement(String localName, Namespace namespace) {
        if (NAMESPACE.equals(namespace)) {
            return entriesLocalNames.contains(localName);
        }
        return false;
    }

    /**
     * @param document
     * @see XMLizable#toXml(Document)
     */
    public Element toXml(Document document) {
        Element optionsElem = DomUtil.createElement(document, XML_OPTIONS, NAMESPACE);
        for (String localName : entriesLocalNames) {
            DomUtil.addChildElement(optionsElem, localName, NAMESPACE);
        }
        return optionsElem;
    }

    /**
     * Build an <code>OptionsInfo</code> object from the root element present
     * in the request body.
     *
     * @param optionsElement
     * @return
     * @throws DavException if the optionsElement is <code>null</code>
     *                      or not a DAV:options element.
     */
    public static OptionsInfo createFromXml(Element optionsElement) throws DavException {
        if (!DomUtil.matches(optionsElement, XML_OPTIONS, NAMESPACE)) {
            //LOG.log(Level.WARNING, "DAV:options element expected");
            throw new DavException(400);
        }
        OptionsInfo oInfo = new OptionsInfo();
        ElementIterator it = DomUtil.getChildren(optionsElement);
        while (it.hasNext()) {
            // todo: not correct since assuming its the deltaV-namespace
            oInfo.entriesLocalNames.add(it.nextElement().getLocalName());
        }
        return oInfo;
    }
}
