/*
 * 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 jakarta.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();

    /**
     * Returns the set of names of HTTP headers that will be used the next time {@code push()} is called.
     *
     * @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. If the push builder has not had this header set, the return value is
     * <code>null</code>. If the push builder has had this header set multiple times, the value returned is
     * implementation-specific.
     *
     * @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();
}
