/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.qpid.proton.engine;

import org.apache.qpid.proton.reactor.Reactor;
import org.apache.qpid.proton.reactor.Selectable;
import org.apache.qpid.proton.reactor.Task;


/**
 * Event
 *
 */

public interface Event extends Extendable
{
    /**
     * Event types built into the library.
     */
    public enum Type implements EventType {
        REACTOR_INIT,
        REACTOR_QUIESCED,
        REACTOR_FINAL,

        TIMER_TASK,

        CONNECTION_INIT,
        CONNECTION_BOUND,
        CONNECTION_UNBOUND,
        CONNECTION_LOCAL_OPEN,
        CONNECTION_REMOTE_OPEN,
        CONNECTION_LOCAL_CLOSE,
        CONNECTION_REMOTE_CLOSE,
        CONNECTION_FINAL,

        SESSION_INIT,
        SESSION_LOCAL_OPEN,
        SESSION_REMOTE_OPEN,
        SESSION_LOCAL_CLOSE,
        SESSION_REMOTE_CLOSE,
        SESSION_FINAL,

        LINK_INIT,
        LINK_LOCAL_OPEN,
        LINK_REMOTE_OPEN,
        LINK_LOCAL_DETACH,
        LINK_REMOTE_DETACH,
        LINK_LOCAL_CLOSE,
        LINK_REMOTE_CLOSE,
        LINK_FLOW,
        LINK_FINAL,

        DELIVERY,

        TRANSPORT,
        TRANSPORT_ERROR,
        TRANSPORT_HEAD_CLOSED,
        TRANSPORT_TAIL_CLOSED,
        TRANSPORT_CLOSED,

        SELECTABLE_INIT,
        SELECTABLE_UPDATED,
        SELECTABLE_READABLE,
        SELECTABLE_WRITABLE,
        SELECTABLE_EXPIRED,
        SELECTABLE_ERROR,
        SELECTABLE_FINAL,
        
        /**
         * This value must never be used to generate an event, it's only used as
         * a guard when casting custom EventTypes to core {@link Type} via
         * {@link Event#getType()}.
         */
        NON_CORE_EVENT {
            @Override
            public boolean isValid() { return false; }
        };

        @Override
        public boolean isValid() {
            return true;
        }
    }

    /**
     * @return type of the event. The event type can be defined outside of the
     *         proton library.
     */
    EventType getEventType();

    /**
     * A concrete event type of core events.
     * 
     * @return type of the event for core events. For events generated by
     *         extensions a {@link Type#NON_CORE_EVENT} will be returned
     */
    Type getType();

    Object getContext();

    /**
     * The {@link Handler} at the root of the handler tree.
     * <p>
     * Set by the {@link Reactor} before dispatching the event.
     * <p>
     * @see #redispatch(EventType, Handler)
     * @return The root handler
     */
    Handler getRootHandler();

    void dispatch(Handler handler) throws HandlerException;

    /**
     * Synchronously redispatch the current event as a new {@link EventType} on the provided handler and it's children.
     * <p>
     * Note: the <code>redispatch()</code> will complete before children of the current handler have had the current event dispatched, see {@link #delegate()}.
     *
     *
     * @param as_type Type of event to dispatch
     * @param handler The handler where to start the dispatch. Use {@link #getRootHandler()} to redispatch the new event to all handlers in the tree.
     * @throws HandlerException A wrapper exception of any unhandled exception thrown by <code>handler</code>
     */
    void redispatch(EventType as_type, Handler handler) throws HandlerException;

    /**
     * dispatch the event to all children of the handler. A handler can call
     * this method explicitly to be able to do more processing after all child
     * handlers have already processed the event. If handler does not invoke
     * this method it is invoked implicitly by {@link #dispatch(Handler)}
     *
     * @throws HandlerException
     */
    void delegate() throws HandlerException;

    Connection getConnection();

    Session getSession();

    Link getLink();

    Sender getSender();

    Receiver getReceiver();

    Delivery getDelivery();

    Transport getTransport();

    Reactor getReactor();

    Selectable getSelectable();

    Task getTask();

    Event copy();

}
