package org.jboss.resteasy.test.client.core;

import java.net.URI;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.jboss.resteasy.client.ClientExecutor;
import org.jboss.resteasy.client.ClientResponse;
import org.jboss.resteasy.client.ProxyFactory;
import org.jboss.resteasy.client.core.ClientErrorInterceptor;
import org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor;
import org.jboss.resteasy.spi.NoLogWebApplicationException;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.resteasy.test.BaseResourceTest;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

import static org.jboss.resteasy.test.TestPortProvider.generateBaseUrl;

public class ClientErrorInterceptorTest extends BaseResourceTest {

	public static class MyResourceImpl implements MyResource {
		public String get() {
			return "hello world";
		}

		public String error() {
			Response r = Response.status(404).type("text/plain").entity("there was an error").build();
			throw new NoLogWebApplicationException(r);
		}
      @Override
      public void update(String id, String obj)
      {
         Response r = Response.status(404).type("text/plain").entity("there was an error").build();
         throw new NoLogWebApplicationException(r);
      }
	}

	@Path("/test")
	public static interface MyResource {
		@GET
		@Produces("text/plain")
		public String get();

		@GET
		@Path("error")
		@Produces("text/plain")
		String error();

      @PUT
      @Path("{id}")
      @Consumes(MediaType.APPLICATION_XML)
      void update(@PathParam("id") String id, String obj);
	}

	@BeforeClass
	public static void setUp() throws Exception {
		addPerRequestResource(MyResourceImpl.class);
	}

	public static class MyClienteErrorInterceptor implements ClientErrorInterceptor {
		@Override
		public void handle(ClientResponse<?> response) throws RuntimeException {
			String errorMessage = response.getEntity(String.class);
			throw new MyException(errorMessage);
		}
	}

	public static class MyException extends RuntimeException {
		private static final long serialVersionUID = 1L;

		public MyException(String message) {
			super(message);
		}
	}

	@Test
	public void testStreamClosedWhenGetEntity() throws Exception {
		HttpClient httpClient = new DefaultHttpClient();
		ClientExecutor clientExecutor = new ApacheHttpClient4Executor(httpClient);

		ResteasyProviderFactory pf = ResteasyProviderFactory.getInstance();
		pf.addClientErrorInterceptor(new MyClienteErrorInterceptor());

		MyResource proxy = ProxyFactory.create(MyResource.class, new URI("http://localhost:8081"), clientExecutor, pf);

		try {
			proxy.error();
			Assert.fail();
		} catch (MyException e) {
			Assert.assertEquals("there was an error", e.getMessage());
		}
	}

   @Test
   public void testStreamClosedWhenGetEntityForVoid() throws Exception
   {
      HttpClient httpClient = new DefaultHttpClient();
      ClientExecutor clientExecutor = new ApacheHttpClient4Executor(httpClient);

      ResteasyProviderFactory pf = ResteasyProviderFactory.getInstance();
      pf.addClientErrorInterceptor(new MyClienteErrorInterceptor());

      MyResource proxy = ProxyFactory.create(MyResource.class, URI.create(generateBaseUrl()), clientExecutor, pf);

      try
      {
         proxy.update("1", "hello");
         Assert.fail();
      }
      catch (MyException e)
      {
         Assert.assertEquals("there was an error", e.getMessage());
      }
   }

}
