package org.jboss.resteasy.experiment;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.HashSet;
import java.util.Set;

import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Payload;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.client.Client;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

public class Test2795 {

   private static UndertowJaxrsServer server;
   private static Client client; 

   @Path("")
   public static class TestResource {

      @Path("test")
      @GET
      @TestConstraint(message="testMessage", value="testValue")
      public String m1() {
         System.out.println("entering get()");
         return "test";
      }
      
      @GET
      @Path("throw")
      @TestConstraint(message="throwMessage", value="throwValue")
      public String m2() {
         System.out.println("entering throw()");
         Set<? extends ConstraintViolation<?>> set = new HashSet<ConstraintViolation<String>>();
         throw new TestException("throw", set);
      }
   }

   @Constraint(validatedBy = TestValidator.class)
   @Target({TYPE,METHOD})
   @Retention(RUNTIME)
   public @interface TestConstraint
   {
      String message() default "custom";
      Class<?>[] groups() default {};
      Class<? extends Payload>[] payload() default {};
      String value();
   }

   public static class TestValidator implements ConstraintValidator<TestConstraint, String>
   {
      public void initialize(TestConstraint constraintAnnotation) { }
      public boolean isValid(String value, ConstraintValidatorContext context) {
         return false;
      }
   }

   public static class TestException extends ConstraintViolationException {
      private static final long serialVersionUID = 1L;

      public TestException(Set<? extends ConstraintViolation<?>> constraintViolations)
      {
         super(constraintViolations);
      }

      public TestException(String message, Set<? extends ConstraintViolation<?>> constraintViolations) {
         super(message, constraintViolations);
      }
   }

   @Provider
   public static class ConstraintViolationExceptionMapper implements ExceptionMapper<ConstraintViolationException> {

      @Override
      public Response toResponse(ConstraintViolationException exception) {
         return Response
               .status(Status.BAD_REQUEST)
               .type("text/plain")
               .entity(exception.getMessage())
               .build();
      }
   }

   @ApplicationPath("")
   public static class MyApp extends Application {
      @Override
      public Set<Class<?>> getClasses() {
         HashSet<Class<?>> classes = new HashSet<Class<?>>();
         classes.add(TestResource.class);
         classes.add(ConstraintViolationExceptionMapper.class);
         return classes;
      }
   }

   @BeforeClass
   public static void init() throws Exception {
      server = new UndertowJaxrsServer().start();
      server.deploy(MyApp.class);
      client = (ResteasyClient) ResteasyClientBuilder.newClient();
   }

   @AfterClass
   public static void stop() throws Exception {
      server.stop();
   }

   @Test
   public void testInvalid() throws Exception {
      Response response = client.target("http://localhost:8081/test").request().get();
      String s = response.readEntity(String.class);
      System.out.println("s: " + s);
   }
   
   @Test
   public void testThrow() throws Exception {
      Response response = client.target("http://localhost:8081/throw").request().get();
      String s = response.readEntity(String.class);
      System.out.println("s: " + s);
   }
}
