// Path: portfolio-service/src/main/generated/io/vertx/workshop/portfolio/reactivex/PortfolioService.java
// @io.vertx.lang.reactivex.RxGen(io.vertx.workshop.portfolio.PortfolioService.class)
// public class PortfolioService {
// 
//   public static final io.vertx.lang.reactivex.TypeArg<PortfolioService> __TYPE_ARG = new io.vertx.lang.reactivex.TypeArg<>(
//     obj -> new PortfolioService((io.vertx.workshop.portfolio.PortfolioService) obj),
//     PortfolioService::getDelegate
//   );
// 
//   private final io.vertx.workshop.portfolio.PortfolioService delegate;
//   
//   public PortfolioService(io.vertx.workshop.portfolio.PortfolioService delegate) {
//     this.delegate = delegate;
//   }
// 
//   public io.vertx.workshop.portfolio.PortfolioService getDelegate() {
//     return delegate;
//   }
// 
//   /**
//    * Gets the portfolio.
//    * @param resultHandler the result handler called when the portfolio has been retrieved. The async result indicates whether the call was successful or not.
//    */
//   public void getPortfolio(Handler<AsyncResult<Portfolio>> resultHandler) { 
//     delegate.getPortfolio(resultHandler);
//   }
// 
//   /**
//    * Gets the portfolio.
//    * @return 
//    */
//   public Single<Portfolio> rxGetPortfolio() { 
//     return new io.vertx.reactivex.core.impl.AsyncResultSingle<Portfolio>(handler -> {
//       getPortfolio(handler);
//     });
//   }
// 
//   /**
//    * Buy `amount` shares of the given shares (quote).
//    * @param amount the amount
//    * @param quote the last quote
//    * @param resultHandler the result handler with the updated portfolio. If the action cannot be executed, the async result is market as a failure (not enough money, not enough shares available...)
//    */
//   public void buy(int amount, JsonObject quote, Handler<AsyncResult<Portfolio>> resultHandler) { 
//     delegate.buy(amount, quote, resultHandler);
//   }
// 
//   /**
//    * Buy `amount` shares of the given shares (quote).
//    * @param amount the amount
//    * @param quote the last quote
//    * @return 
//    */
//   public Single<Portfolio> rxBuy(int amount, JsonObject quote) { 
//     return new io.vertx.reactivex.core.impl.AsyncResultSingle<Portfolio>(handler -> {
//       buy(amount, quote, handler);
//     });
//   }
// 
//   /**
//    * Sell `amount` shares of the given shares (quote).
//    * @param amount the amount
//    * @param quote the last quote
//    * @param resultHandler the result handler with the updated portfolio. If the action cannot be executed, the async result is market as a failure (not enough share...)
//    */
//   public void sell(int amount, JsonObject quote, Handler<AsyncResult<Portfolio>> resultHandler) { 
//     delegate.sell(amount, quote, resultHandler);
//   }
// 
//   /**
//    * Sell `amount` shares of the given shares (quote).
//    * @param amount the amount
//    * @param quote the last quote
//    * @return 
//    */
//   public Single<Portfolio> rxSell(int amount, JsonObject quote) { 
//     return new io.vertx.reactivex.core.impl.AsyncResultSingle<Portfolio>(handler -> {
//       sell(amount, quote, handler);
//     });
//   }
// 
//   /**
//    * Evaluates the current value of the portfolio.
//    * @param resultHandler the result handler with the valuation
//    */
//   public void evaluate(Handler<AsyncResult<Double>> resultHandler) { 
//     delegate.evaluate(resultHandler);
//   }
// 
//   /**
//    * Evaluates the current value of the portfolio.
//    * @return 
//    */
//   public Single<Double> rxEvaluate() { 
//     return new io.vertx.reactivex.core.impl.AsyncResultSingle<Double>(handler -> {
//       evaluate(handler);
//     });
//   }
// 
// 
//   public static  PortfolioService newInstance(io.vertx.workshop.portfolio.PortfolioService arg) {
//     return arg != null ? new PortfolioService(arg) : null;
//   }
// }
// 
// Path: currency-service/src/main/solution/io/vertx/workshop/currency/Helpers.java
// public static SingleObserver<JsonObject> toObserver(Future<JsonObject> future) {
//     return new SingleObserver<JsonObject>() {
//         public void onSubscribe(@NonNull Disposable d) {
//         }
// 
//         public void onSuccess(@NonNull JsonObject item) {
//             future.tryComplete(item);
//         }
// 
//         public void onError(Throwable error) {
//             future.tryFail(error);
//         }
//     };
// }


import io.vertx.circuitbreaker.CircuitBreakerOptions;
import io.vertx.core.json.JsonObject;
import io.vertx.reactivex.circuitbreaker.CircuitBreaker;
import io.vertx.reactivex.core.AbstractVerticle;
import io.vertx.reactivex.core.buffer.Buffer;
import io.vertx.reactivex.ext.web.Router;
import io.vertx.reactivex.ext.web.RoutingContext;
import io.vertx.reactivex.ext.web.client.HttpResponse;
import io.vertx.reactivex.ext.web.handler.BodyHandler;
import io.vertx.reactivex.servicediscovery.ServiceDiscovery;
import io.vertx.reactivex.servicediscovery.types.EventBusService;
import io.vertx.reactivex.servicediscovery.types.HttpEndpoint;
import io.vertx.workshop.portfolio.reactivex.PortfolioService;
import static io.vertx.workshop.currency.Helpers.toObserver;
                    err -> new JsonObject()
                        .put("amount", rc.getBodyAsJson().getDouble("amount"))
                        .put("currency", "USD")))

            // ----
            .map(JsonObject::toBuffer)
            .map(Buffer::new)

            .subscribe(toObserver(rc));
    }

    /**
     * Example of method not using a circuit breaker.
     *
     * @param rc the routing context
     */
    private void delegate(RoutingContext rc) {
        HttpEndpoint.rxGetWebClient(discovery, svc -> svc.getName().equals("currency-3rdparty-service"))
            .flatMap(client -> client.post("/").rxSendJsonObject(rc.getBodyAsJson()))
            .map(HttpResponse::bodyAsBuffer)
            .subscribe(toObserver(rc));
    }


    /**
     * Method to check the proxy requesting to convert the current portfolio to EUR.
     *
     * @param rc the routing context
     */
    private void convertPortfolioToEuro(RoutingContext rc) {
// Path: portfolio-service/src/main/generated/io/vertx/workshop/portfolio/reactivex/PortfolioService.java
// @io.vertx.lang.reactivex.RxGen(io.vertx.workshop.portfolio.PortfolioService.class)
// public class PortfolioService {
// 
//   public static final io.vertx.lang.reactivex.TypeArg<PortfolioService> __TYPE_ARG = new io.vertx.lang.reactivex.TypeArg<>(
//     obj -> new PortfolioService((io.vertx.workshop.portfolio.PortfolioService) obj),
//     PortfolioService::getDelegate
//   );
// 
//   private final io.vertx.workshop.portfolio.PortfolioService delegate;
//   
//   public PortfolioService(io.vertx.workshop.portfolio.PortfolioService delegate) {
//     this.delegate = delegate;
//   }
// 
//   public io.vertx.workshop.portfolio.PortfolioService getDelegate() {
//     return delegate;
//   }
// 
//   /**
//    * Gets the portfolio.
//    * @param resultHandler the result handler called when the portfolio has been retrieved. The async result indicates whether the call was successful or not.
//    */
//   public void getPortfolio(Handler<AsyncResult<Portfolio>> resultHandler) { 
//     delegate.getPortfolio(resultHandler);
//   }
// 
//   /**
//    * Gets the portfolio.
//    * @return 
//    */
//   public Single<Portfolio> rxGetPortfolio() { 
//     return new io.vertx.reactivex.core.impl.AsyncResultSingle<Portfolio>(handler -> {
//       getPortfolio(handler);
//     });
//   }
// 
//   /**
//    * Buy `amount` shares of the given shares (quote).
//    * @param amount the amount
//    * @param quote the last quote
//    * @param resultHandler the result handler with the updated portfolio. If the action cannot be executed, the async result is market as a failure (not enough money, not enough shares available...)
//    */
//   public void buy(int amount, JsonObject quote, Handler<AsyncResult<Portfolio>> resultHandler) { 
//     delegate.buy(amount, quote, resultHandler);
//   }
// 
//   /**
//    * Buy `amount` shares of the given shares (quote).
//    * @param amount the amount
//    * @param quote the last quote
//    * @return 
//    */
//   public Single<Portfolio> rxBuy(int amount, JsonObject quote) { 
//     return new io.vertx.reactivex.core.impl.AsyncResultSingle<Portfolio>(handler -> {
//       buy(amount, quote, handler);
//     });
//   }
// 
//   /**
//    * Sell `amount` shares of the given shares (quote).
//    * @param amount the amount
//    * @param quote the last quote
//    * @param resultHandler the result handler with the updated portfolio. If the action cannot be executed, the async result is market as a failure (not enough share...)
//    */
//   public void sell(int amount, JsonObject quote, Handler<AsyncResult<Portfolio>> resultHandler) { 
//     delegate.sell(amount, quote, resultHandler);
//   }
// 
//   /**
//    * Sell `amount` shares of the given shares (quote).
//    * @param amount the amount
//    * @param quote the last quote
//    * @return 
//    */
//   public Single<Portfolio> rxSell(int amount, JsonObject quote) { 
//     return new io.vertx.reactivex.core.impl.AsyncResultSingle<Portfolio>(handler -> {
//       sell(amount, quote, handler);
//     });
//   }
// 
//   /**
//    * Evaluates the current value of the portfolio.
//    * @param resultHandler the result handler with the valuation
//    */
//   public void evaluate(Handler<AsyncResult<Double>> resultHandler) { 
//     delegate.evaluate(resultHandler);
//   }
// 
//   /**
//    * Evaluates the current value of the portfolio.
//    * @return 
//    */
//   public Single<Double> rxEvaluate() { 
//     return new io.vertx.reactivex.core.impl.AsyncResultSingle<Double>(handler -> {
//       evaluate(handler);
//     });
//   }
// 
// 
//   public static  PortfolioService newInstance(io.vertx.workshop.portfolio.PortfolioService arg) {
//     return arg != null ? new PortfolioService(arg) : null;
//   }
// }
// 
// Path: currency-service/src/main/solution/io/vertx/workshop/currency/Helpers.java
// public static SingleObserver<JsonObject> toObserver(Future<JsonObject> future) {
//     return new SingleObserver<JsonObject>() {
//         public void onSubscribe(@NonNull Disposable d) {
//         }
// 
//         public void onSuccess(@NonNull JsonObject item) {
//             future.tryComplete(item);
//         }
// 
//         public void onError(Throwable error) {
//             future.tryFail(error);
//         }
//     };
// }


// Path: currency-service/src/main/solution/io/vertx/workshop/currency/CurrencyServiceProxy.java
import io.vertx.circuitbreaker.CircuitBreakerOptions;
import io.vertx.core.json.JsonObject;
import io.vertx.reactivex.circuitbreaker.CircuitBreaker;
import io.vertx.reactivex.core.AbstractVerticle;
import io.vertx.reactivex.core.buffer.Buffer;
import io.vertx.reactivex.ext.web.Router;
import io.vertx.reactivex.ext.web.RoutingContext;
import io.vertx.reactivex.ext.web.client.HttpResponse;
import io.vertx.reactivex.ext.web.handler.BodyHandler;
import io.vertx.reactivex.servicediscovery.ServiceDiscovery;
import io.vertx.reactivex.servicediscovery.types.EventBusService;
import io.vertx.reactivex.servicediscovery.types.HttpEndpoint;
import io.vertx.workshop.portfolio.reactivex.PortfolioService;
import static io.vertx.workshop.currency.Helpers.toObserver;

                    err -> new JsonObject()
                        .put("amount", rc.getBodyAsJson().getDouble("amount"))
                        .put("currency", "USD")))

            // ----
            .map(JsonObject::toBuffer)
            .map(Buffer::new)

            .subscribe(toObserver(rc));
    }

    /**
     * Example of method not using a circuit breaker.
     *
     * @param rc the routing context
     */
    private void delegate(RoutingContext rc) {
        HttpEndpoint.rxGetWebClient(discovery, svc -> svc.getName().equals("currency-3rdparty-service"))
            .flatMap(client -> client.post("/").rxSendJsonObject(rc.getBodyAsJson()))
            .map(HttpResponse::bodyAsBuffer)
            .subscribe(toObserver(rc));
    }


    /**
     * Method to check the proxy requesting to convert the current portfolio to EUR.
     *
     * @param rc the routing context
     */
    private void convertPortfolioToEuro(RoutingContext rc) {
        EventBusService.getServiceProxy(discovery, svc -> svc.getName().equals("portfolio"), PortfolioService.class,