package tech.greenfield.vertx.irked;

import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.impl.RoutingContextDecorator;
import tech.greenfield.vertx.irked.status.OK;

/**
 * Request handling wrapper which adds some useful routines for
 * API writers.
 * 
 * Can serve as a basis for local context parsers that API writers
 * can use to expose path arguments from parent prefixes
 * 
 * @author odeda
 */
public class Request extends RoutingContextDecorator {

	private RoutingContext outerContext;

	public Request(RoutingContext outerContext) {
		super(outerContext.currentRoute(), outerContext);
		this.outerContext = outerContext;
	}

	@Override
	public void fail(int statusCode) { 
		// we're overriding the fail handlers, which for some reason the decorator 
		// feels should be moved to another thread. Instead, use the outer implementation
		// and let it do what's right
		this.outerContext.fail(statusCode);
	}

	@Override
	public void fail(Throwable throwable) {
		// we're overriding the fail handlers, which for some reason the decorator 
		// feels should be moved to another thread. Instead, use the outer implementation
		// and let it do what's right
		this.outerContext.fail(throwable);
	}
	
	/**
	 * Helper method to terminate request processing with a success (200 OK) response 
	 * containing a JSON body.
	 * @param json {@link JsonObject} containing the output to encode
	 */
	public void sendJSON(JsonObject json) {
		sendJSON(json, new OK());
	}
	
	/**
	 * Helper method to terminate request processing with a success (200 OK) response 
	 * containing a JSON body.
	 * @param json {@link JsonArray} containing the output to encode
	 */
	public void sendJSON(JsonArray json) {
		sendJSON(json, new OK());
	}
	
	/**
	 * Helper method to terminate request processing with a custom response 
	 * containing a JSON body and the specified status line.
	 * @param json {@link JsonObject} containing the output to encode
	 * @param status HTTP status to send
	 */
	public void sendJSON(JsonObject json, HttpError status) {
		sendContent(json.encode(), status);
	}
	
	/**
	 * Helper method to terminate request processing with a custom response 
	 * containing a JSON body and the specified status line.
	 * @param json {@link JsonArray} containing the output to encode
	 * @param status HTTP status to send
	 */
	public void sendJSON(JsonArray json, HttpError status) {
		sendContent(json.encode(), status);
	}
	
	/**
	 * Helper method to terminate request processing with a custom response
	 * containing some text and the specifeid status line.
	 * @param content
	 * @param status
	 */
	public void sendContent(String content, HttpError status) {
		response(status)
		.putHeader("Content-Type", "application/json")
		.putHeader("Content-Length", String.valueOf(content.length()))
		.end(content);
	}
	
	/**
	 * Helper method to terminate request processing with an HTTP error (non-200 OK) response.
	 * The resulting HTTP response will have the correct status line and an application/json content
	 * with a JSON encoded object containing the fields "status" set to "false" and "message" set
	 * to the {@link HttpError}'s message.
	 * @param err
	 */
	public void sendError(HttpError err) {
		sendJSON(new JsonObject().put("status", false).put("message", err.getMessage()), err);
	}

	/**
	 * Helper method to generate response with the specified HTTP status
	 * @param status HTTP status code and text to set on the response
	 * @return HTTP response created using {@link RoutingContext#response()}
	 */
	public HttpServerResponse response(HttpError status) {
		return response().setStatusCode(status.getStatusCode()).setStatusMessage(status.getStatusText());
	}

}

@@ -31,16 +31,43 @@
 irked;%0A%0A
+import java.util.Objects;%0A%0A
 import i
@@ -1360,32 +1360,1338 @@
 ble);%0A%09%7D%0A%09%0A%09/**%0A
+%09 * Helper failure handler for CompletableFuture users.%0A%09 * Use at the end of an async chain to succinctly propagate exceptions, as%0A%09 * thus: %3Ccode%3E.exceptionally(req::handleFailure)%3C/code%3E.%0A%09 * This method will call %7B@link #fail(Throwable)%7D after unwrapping%0A%09 * %7B@link RuntimeException%7Ds as needed.%0A%09 * @param throwable A %7B@link Throwable%7D error to fail on%0A%09 * @return null%0A%09 */%0A%09public Void handleFailure(Throwable throwable) %7B%0A%09%09fail(HttpError.unwrap(throwable));%0A%09%09return null;%0A%09%7D%0A%09%0A%09/**%0A%09 * Helper failure handler for CompletableFuture users.%0A%09 * Use in the middle an async chain to succinctly propagate exceptions, or%0A%09 * success values as thus: %3Ccode%3E.whenComplete(req::handlePossibleFailure)%3C/code%3E.%0A%09 * This method will call %7B@link Request#fail(Throwable)%7D if a failure occured,%0A%09 * after unwrapping %7B@link RuntimeException%7Ds as needed. It will also pass on%0A%09 * the success value (or null if there was a failure) for the next async%0A%09 * element. Subsequent code can check whether a failure was propagated%0A%09 * by calling %7B@link #failed()%7D%0A%09 * @param throwable A %7B@link Throwable%7D error to fail on%0A%09 * @return null%0A%09 */%0A%09public %3CV%3E V handlePossibleFailure(V successValue, Throwable throwable) %7B%0A%09%09if (Objects.nonNull(throwable))%0A%09%09%09fail(HttpError.unwrap(throwable));%0A%09%09return successValue;%0A%09%7D%0A%09%0A%09/**%0A
 %09 * Helper metho

add helper methods to propagate failures from CompletableFuture chains