package at.ac.univie.isc.asio;

import com.jayway.restassured.builder.RequestSpecBuilder;
import com.jayway.restassured.specification.RequestSpecification;

import java.net.URI;

import static java.util.Objects.requireNonNull;

/**
 * Deployment specific configuration for rest-assured integration tests.
 */
public abstract class AsioSpec {
  /**
   * Authorization is applied by including the permission in the request URI.
   *
   * @param address base service address
   * @return uri based asio spec
   */
  public static AsioSpec withUriAuthorization(final URI address) {
    return new UriBased(address);
  }

  /**
   * Authorization is skipped.
   *
   * @param address base service address
   * @return asio spec without authorization
   */
  public static AsioSpec withoutAuthorization(final URI address) {
    return new NoAuth(address);
  }

  private final URI root;

  private AsioSpec(final URI root) {
    this.root = requireNonNull(root);
  }

  protected URI getRoot() {
    return root;
  }

  /**
   * Create rest-assured request to the service root with given permission.
   *
   * @param permission required for the test request
   * @return initialized request specification
   */
  public RequestSpecification requestWith(final String permission) {
    requireNonNull(permission);
    final RequestSpecBuilder request = new RequestSpecBuilder().setBaseUri(root);
    final RequestSpecBuilder authorized = authorize(request, permission);
    return authorized.build();
  }

  protected abstract RequestSpecBuilder authorize(final RequestSpecBuilder spec, final String permission);

  public abstract URI authorizedAddress(final String permission);

  public abstract boolean isAuthorizing();

  /**
   * Use the URI based authorization mechanism
   */
  private static class UriBased extends AsioSpec {
    private UriBased(final URI root) {
      super(root);
    }

    @Override
    protected RequestSpecBuilder authorize(final RequestSpecBuilder spec, final String permission) {
      return spec.setBaseUri(authorizedAddress(permission));
    }

    @Override
    public URI authorizedAddress(final String permission) {
      return this.getRoot().resolve(permission + "/");
    }

    @Override
    public boolean isAuthorizing() {
      return true;
    }
  }


  /**
   * Do not modify requests, no authorization is applied
   */
  private static class NoAuth extends AsioSpec {
    private NoAuth(final URI root) {
      super(root);
    }

    @Override
    protected RequestSpecBuilder authorize(final RequestSpecBuilder spec, final String ignored) {
      return spec;
    }

    @Override
    public URI authorizedAddress(final String permission) {
      return this.getRoot();
    }

    @Override
    public boolean isAuthorizing() {
      return false;
    }
  }
}

@@ -25,16 +25,88 @@
 .asio;%0A%0A
+import com.jayway.restassured.authentication.PreemptiveBasicAuthScheme;%0A
 import c
@@ -155,16 +155,16 @@
 uilder;%0A
-
 import c
@@ -407,16 +407,382 @@
 oSpec %7B%0A
+  /**%0A   * Authorization is applied by sending the permission in the request headers.%0A   *%0A   * @param address base service address%0A   * @param header name of the auth bearing header%0A   * @return header based asio spec%0A   */%0A  public static AsioSpec withHeaderAuthorization(final URI address, final String header) %7B%0A    return new HeaderBased(address, header);%0A  %7D%0A%0A
   /**%0A  
@@ -2096,32 +2096,32 @@
 g permission);%0A%0A
-
   public abstrac
@@ -2148,16 +2148,914 @@
 ing();%0A%0A
+  /**%0A   * Send permission as http header and force basic auth.%0A   */%0A  private static class HeaderBased extends AsioSpec %7B%0A    private final String headerName;%0A    private final PreemptiveBasicAuthScheme defaultAuth;%0A%0A    private HeaderBased(final URI root, final String headerName) %7B%0A      super(root);%0A      this.headerName = requireNonNull(headerName, %22header name%22);%0A      defaultAuth = new PreemptiveBasicAuthScheme();%0A      defaultAuth.setUserName(%22anonymous%22);%0A      defaultAuth.setPassword(%22%22);%0A    %7D%0A%0A    @Override%0A    protected RequestSpecBuilder authorize(final RequestSpecBuilder spec, final String permission) %7B%0A      return spec.setAuth(defaultAuth).addHeader(headerName, permission);%0A    %7D%0A%0A    @Override%0A    public URI authorizedAddress(final String permission) %7B%0A      return this.getRoot();%0A    %7D%0A%0A    @Override%0A    public boolean isAuthorizing() %7B%0A      return true;%0A    %7D%0A  %7D%0A%0A
   /**%0A  

support for header permissions in AsioSpec