/*
 * Copyright (c) 2004-2023, by Alex Leigh.
 * All rights reserved.
 *
 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE
 * The copyright notice above does not evidence any
 * actual or intended publication of such source code.
 */

package lc.mecha.http.server;

import lc.mecha.fabric.HandlerStatus;
import lc.mecha.fabric.MessageReceiver;
import lc.mecha.log.MechaLogger;
import lc.mecha.log.MechaLoggerFactory;

import java.util.HashSet;
import java.util.Set;

/**
 * This handler implements a <code>WebHandler</code> that will only execute
 * if the requested path starts with the associated prefix path. More than one path can be associated
 * with the handler.
 * <p>
 * Note: It is not particularly well performing to use a lot of these; in the case where you need
 * more than 20 or 30 in a single <code>WebServer</code> it may be better to implement
 * some sort of multi-handler which works on a Map-based association instead.
 *
 * @author Alex Leigh
 */
public abstract class PrefixedHandler implements MessageReceiver<HttpTransaction> {
    private static final MechaLogger logger = MechaLoggerFactory.getLogger(PrefixedHandler.class);
    private final Set<String> pathPrefix = new HashSet<>();

    public PrefixedHandler(final Set<String> pathPrefixes) {
        logger.debug("PrefixHandler(): Creating new handler. [prefix: {}] [obj: {}]", pathPrefixes, this);
        this.pathPrefix.addAll(pathPrefixes);
    }

    public Set<String> getPathPrefix() {
        return pathPrefix;
    }

    @Override
    public HandlerStatus receive(final HttpTransaction request) throws Throwable {
        if (request.request.isHandled()) {
            logger.trace("Request already served. Bypassing.");
            return HandlerStatus.CONTINUE;
        }

        for (String prefix : pathPrefix) {
            logger.trace("Matching: {} to {}", prefix, request.httpServletRequest.getPathInfo());
            if (request.httpServletRequest.getPathInfo().startsWith(prefix)) {
                request.setPrefix(prefix);
                final HandlerStatus status = handlePrefixedWebRequest(request);
                if (status == HandlerStatus.BREAK)
                    request.request.setHandled(true);
                return status;
            }
        }

        logger.debug("Paths did not match, returning. [pathPrefix: {}] [pathInfo: {}]", pathPrefix,
                request.httpServletRequest.getPathInfo());

        return HandlerStatus.CONTINUE;
    }

    /**
     * Implement this method to handle the provided request. If any sort of error returns,
     * throw an exception and an error response will automatically be generated.
     *
     * @param request
     * @return
     * @throws Throwable
     */
    public abstract HandlerStatus handlePrefixedWebRequest(HttpTransaction request) throws Throwable;
}
