/*
 * 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 javax.servlet.http;

import java.util.Set;

/**
 * Builds a push request based on the {@link HttpServletRequest} from which this
 * builder was obtained. The push request will be constructed on the following
 * basis:
 * <ul>
 * <li>The request method is set to <code>GET</code>.</li>
 * <li>The path will not be set. This must be set explicitly via a call to
 *     {@link #path(String)}.</li>
 * <li>Conditional, range, expectation, authorization and referer headers will
 *     be removed.</li>
 * <li>Cookies added to the associated response will be added to the push
 *     request unless maxAge &lt;= 0 in which case any request cookie with the
 *     same name will be removed.</li>
 * <li>The referer header will be set to
 *     {@link HttpServletRequest#getRequestURL()} plus, if present, the query
 *     string from {@link HttpServletRequest#getQueryString()}.
 * </ul>
 *
 * @since Servlet 4.0
 */
public interface PushBuilder {

    /**
     * Specify the HTTP method to use for the push request.
     *
     * @param method The method to use for the push request
     *
     * @return This builder instance
     *
     * @throws IllegalArgumentException if an HTTP method is specified that is
     *         known not to be <a
     *         href="https://tools.ietf.org/html/rfc7540#section-8.2">cacheable
     *         and safe</a>. POST, PUT, DELETE, CONNECT, OPTIONS and TRACE will
     *         trigger the exception.
     */
    PushBuilder method(String method);

    /**
     * Specifies the query string to use in subsequent push requests generated
     * by a call to {@link #push()}. This will be appended to any query string
     * specified in the call to {@link #path(String)}.
     *
     * @param queryString The query string to use to generate push requests
     *
     * @return This builder instance
     */
    PushBuilder queryString(String queryString);

    /**
     * Specifies the session ID to use in subsequent push requests generated
     * by a call to {@link #push()}. The session ID will be presented the same
     * way as it is on the original request (cookie or URL parameter). The
     * default is determined in the following order:
     * <ul>
     * <li>the requested session ID for the originating request</li>
     * <li>the session ID generated in the originated request</li>
     * <li>{@code null}</li>
     * </ul>
     *
     * @param sessionId The session ID to use to generate push requests
     *
     * @return This builder instance
     */
    PushBuilder sessionId(String sessionId);

    /**
     * Sets an HTTP header on the request. Any existing headers of the same name
     * are first remove.
     *
     * @param name  The name of the header to set
     * @param value The value of the header to set
     *
     * @return This builder instance
     */
    PushBuilder setHeader(String name, String value);

    /**
     * Adds an HTTP header to the request.
     *
     * @param name  The name of the header to add
     * @param value The value of the header to add
     *
     * @return This builder instance
     */
    PushBuilder addHeader(String name, String value);

    /**
     * Removes an HTTP header from the request.
     *
     * @param name  The name of the header to remove
     *
     * @return This builder instance
     */
    PushBuilder removeHeader(String name);

    /**
     * Sets the URI path to be used for the push request. This must be called
     * before every call to {@link #push()}. If the path includes a query
     * string, the query string will be appended to the existing query string
     * (if any) and no de-duplication will occur.
     *
     * @param path Paths beginning with '/' are treated as absolute paths. All
     *             other paths are treated as relative to the context path of
     *             the request used to create this builder instance. The path
     *             may include a query string.
     *
     * @return This builder instance
     */
    PushBuilder path(String path);

    /**
     * Generates the push request and sends it to the client unless pushes are
     * not available for some reason. After calling this method the following
     * fields are set to {@code null}:
     * <ul>
     * <li>{@code path}</li>
     * <li>conditional request headers ({@code if-none-match} and
     *     {@code if-modified-since})</li>
     * </ul>
     *
     * @throws IllegalStateException If this method is called when {@code path}
     *         is {@code null}
     * @throws IllegalArgumentException If the request to push requires a body
     */
    void push();

    /**
     * Obtain the name of the HTTP method that will be used for push requests
     * generated by future calls to {@code push()}.
     *
     * @return The HTTP method to be used for future push requests
     */
    String getMethod();

    /**
     * Obtain the query string that will be used for push requests generated by
     * future calls to {@code push()}.
     *
     * @return The query string that will be appended to push requests.
     */
    String getQueryString();

    /**
     * Obtain the session ID that will be used for push requests generated by
     * future calls to {@code push()}.
     *
     * @return The session that will be used for push requests.
     */
    String getSessionId();

    /**
     * @return The current set of names of HTTP headers to be used the next time
     *         {@code push()} is called.
     */
    Set<String> getHeaderNames();

    /**
     * Obtain a value for the given HTTP header.
     * TODO Servlet 4.0
     * Clarify the behaviour of this method
     *
     * @param name  The name of the header whose value is to be returned
     *
     * @return The value of the given header. If multiple values are defined
     *         then any may be returned
     */
    String getHeader(String name);

    /**
     * Obtain the path that will be used for the push request that will be
     * generated by the next call to {@code push()}.
     *
     * @return The path value that will be associated with the next push request
     */
    String getPath();
}
