/*
 * Copyright (C) 2005-2008 Jive Software. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jivesoftware.openfire.multiplex;

import org.dom4j.Element;
import org.jivesoftware.openfire.StreamID;
import org.jivesoftware.openfire.spi.BasicStreamIDFactory;
import org.xmpp.packet.Packet;

import java.util.Iterator;
import java.util.List;

/**
 * Route packets identify target sessions by their stream ID and contain a single
 * wrapped stanza that should be processed by the target session.
 *
 * @author Gaston Dombiak
 */
public class Route extends Packet {

    /**
     * Constructs a new Route.
     *
     * @param streamID the stream ID that identifies the connection that is actually sending
     *                 the wrapped stanza.
     */
    public Route(StreamID streamID) {
        this.element = docFactory.createDocument().addElement("route");
        // Set the stream ID that identifies the target session
        element.addAttribute("streamid", streamID.getID());
    }

     /**
     * Constructs a new Route using an existing Element. This is useful
     * for parsing incoming route Elements into Route objects.
     *
     * @param element the route Element.
     */
    public Route(Element element) {
        super(element, true);
    }

    public Route(Route route) {
        Element elementCopy = route.element.createCopy();
        docFactory.createDocument().add(elementCopy);
        this.element = elementCopy;
        // Copy cached JIDs (for performance reasons)
        this.toJID = route.toJID;
        this.fromJID = route.fromJID;
    }

    /**
     * Returns the wrapped stanza that is being routed. Route packets must have
     * a single wrapped stanza. This is a convenience method to avoid manipulating
     * the underlying packet's Element instance directly.
     *
     * @return the wrapped stanza.
     */
    public Element getChildElement() {
        List elements = element.elements();
        if (elements.isEmpty()) {
            return null;
        }
        else {
            // Return the first child element
            return (Element) elements.get(0);
        }
    }

    /**
     * Sets the wrapped stanza by this Route packet. ClientRoute packets may have a single child
     * element. This is a convenience method to avoid manipulating this underlying packet's
     * Element instance directly.
     *
     * @param childElement the child element.
     */
    public void setChildElement(Element childElement) {
        for (Iterator i=element.elementIterator(); i.hasNext(); ) {
            element.remove((Element)i.next());
        }
        element.add(childElement);
    }

    /**
     * Return the stream ID that identifies the connection that is actually sending
     * the wrapped stanza.
     *
     * @return the stream ID that identifies the connection that is actually sending
     *         the wrapped stanza.
     */
    public StreamID getStreamID() {
        final String value = element.attributeValue( "streamid" );
        if (value == null) {
            return null;
        }
        return BasicStreamIDFactory.createStreamID( value );
    }

    /**
     * Returns a deep copy of this route packet.
     *
     * @return a deep copy of this route packet.
     */
    @Override
	public Route createCopy() {
        return new Route(this);
    }
}
