package org.apache.axis.message;

import org.apache.axis.encoding.DeserializationContext;
import org.w3c.dom.Element;
import org.xml.sax.Attributes;

import javax.xml.soap.Name;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeaderElement;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class SOAPHeader extends MessageElement implements javax.xml.soap.SOAPHeader {

    /** No-arg constructor for building messages?
     */
    public SOAPHeader() {
        super();
    }

    SOAPHeader(String namespace, String localPart) {
        super(namespace, localPart);
    }

    SOAPHeader(String namespace, String localPart, Object value) {
        super(namespace, localPart, value);
    }

    SOAPHeader(Element elem) {
        super(elem);
    }

    public SOAPHeader(String namespace, String localPart, String qName,
                      Attributes attributes, DeserializationContext context) {
        super(namespace, localPart, qName, attributes, context);
    }

    /**
     * Creates a new <CODE>SOAPHeaderElement</CODE> object
     * initialized with the specified name and adds it to this
     * <CODE>SOAPHeader</CODE> object.
     * @param   name a <CODE>Name</CODE> object with
     *     the name of the new <CODE>SOAPHeaderElement</CODE>
     *     object
     * @return the new <CODE>SOAPHeaderElement</CODE> object that
     *     was inserted into this <CODE>SOAPHeader</CODE>
     *     object
     * @throws  SOAPException if a SOAP error occurs
     */
    public SOAPHeaderElement addHeaderElement(Name name)
            throws SOAPException {
        //how to set prefix???
        org.apache.axis.message.SOAPHeaderElement she = new org.apache.axis.message.SOAPHeaderElement(
                name.getURI(), name.getLocalName());
        she.setPrefix(name.getPrefix());
        this.addChildElement(she);
        return (she);
    }

    /**
     * Returns a list of all the <CODE>SOAPHeaderElement</CODE>
     * objects in this <CODE>SOAPHeader</CODE> object that have the
     * the specified actor. An actor is a global attribute that
     * indicates the intermediate parties to whom the message should
     * be sent. An actor receives the message and then sends it to
     * the next actor. The default actor is the ultimate intended
     * recipient for the message, so if no actor attribute is
     * included in a <CODE>SOAPHeader</CODE> object, the message is
     * sent to its ultimate destination.
     * @param   actor  a <CODE>String</CODE> giving the
     *     URI of the actor for which to search
     * @return an <CODE>Iterator</CODE> object over all the <CODE>
     *     SOAPHeaderElement</CODE> objects that contain the
     *     specified actor
     * @see #extractHeaderElements(java.lang.String) extractHeaderElements(java.lang.String)
     */
    public Iterator examineHeaderElements(String actor) {
        this.getHeaderElements(actor, false);
    }

    /**
     * Returns a list of all the <CODE>SOAPHeaderElement</CODE>
     *   objects in this <CODE>SOAPHeader</CODE> object that have
     *   the the specified actor and detaches them from this <CODE>
     *   SOAPHeader</CODE> object.
     *
     *   <P>This method allows an actor to process only the parts of
     *   the <CODE>SOAPHeader</CODE> object that apply to it and to
     *   remove them before passing the message on to the next
     *   actor.
     * @param   actor  a <CODE>String</CODE> giving the
     *     URI of the actor for which to search
     * @return an <CODE>Iterator</CODE> object over all the <CODE>
     *     SOAPHeaderElement</CODE> objects that contain the
     *     specified actor
     * @see #examineHeaderElements(java.lang.String) examineHeaderElements(java.lang.String)
     */
    public Iterator extractHeaderElements(String actor) {
        this.getHeaderElements(actor, true);
    }

    /**
     * @param actor    when this param is null, headers without actor will be returned
     *
     * @param detach   if true, the matching header elements will be removed from this header.
     *
     * @return Iterator     the matching header elements.
     */
    private Iterator getHeaderElements(String actor, boolean detach) {
        Iterator i = this.getChildElements();
        List l = new ArrayList();

        if (actor == null) {
            while (i.hasNext()) {
                Object o = i.next();
                if (o instanceof SOAPHeaderElement) {
                    SOAPHeaderElement e = (SOAPHeaderElement) o;
                    String myActor = e.getActor();

                    if (myActor == null) {
                        l.add(e);
                    }
                }
            }
        } else {
            while (i.hasNext()) {
                Object o = i.next();
                if (o instanceof SOAPHeaderElement) {
                    SOAPHeaderElement e = (SOAPHeaderElement) o;
                    String myActor = e.getActor();

                    if (actor.equals(myActor)) {
                        l.add(e);
                    }
                }
            }
        }

        //detach only when 'detach' is true
        if (detach) {
            for (int j = 0; j < l.size(); j++) {
                SOAPHeaderElement e2 = (SOAPHeaderElement) l.get(j);
                e2.detachNode();
            }
        }
        return l.iterator();
    }
}
