package org.jboss.resteasy.test;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.*;
import org.jboss.resteasy.plugins.server.netty.NettyJaxrsServer;
import org.jboss.resteasy.spi.ResteasyDeployment;
import org.jboss.resteasy.util.HttpHeaderNames;
import org.junit.*;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.net.MalformedURLException;
import java.net.URL;

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

public class RESTEASY1325Test
{
   static String BASE_URI = generateURL("");

   static final int IDLE_TIMEOUT = 10;

   @BeforeClass
   public static void setupSuite() throws Exception
   {
   }

   @AfterClass
   public static void tearDownSuite() throws Exception
   {
   }

   @Before
   public void setupTest() throws Exception
   {
   }

   @After
   public void tearDownTest() throws Exception
   {
   }

   @Test(timeout= IDLE_TIMEOUT * 1000 + 1000)
   public void testIdleCloseConnection() throws Exception
   {
      NettyJaxrsServer netty = new NettyJaxrsServer();
      ResteasyDeployment deployment = new ResteasyDeployment();
      netty.setDeployment(deployment);
      netty.setPort(TestPortProvider.getPort());
      netty.setRootResourcePath("");
      netty.setSecurityDomain(null);
      netty.setIdleTimeout(IDLE_TIMEOUT);
      netty.start();
      deployment.getRegistry().addSingletonResource(new Resource());
      callAndIdle();
      netty.stop();

   }

    /**
     * Test case
     * @throws InterruptedException
     * @throws MalformedURLException
     */
   private void callAndIdle() throws InterruptedException, MalformedURLException {

         EventLoopGroup group = new NioEventLoopGroup();
         try {
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<Channel>() {
                       @Override
                       protected void initChannel(Channel ch) throws Exception {
                          ch.pipeline().addLast(new HttpClientCodec());
                          ch.pipeline().addLast(new HttpObjectAggregator(4096));
                          ch.pipeline().addLast(new SimpleChannelInboundHandler<FullHttpResponse>() {
                             @Override
                             protected void channelRead0(ChannelHandlerContext ctx, FullHttpResponse msg) {
                                System.out.println("HTTP response from resteasy: "+msg);
                                 Assert.assertEquals(HttpResponseStatus.OK, msg.getStatus());
                             }
                          });
                       }
                    });

            // first request;
            URL url = new URL(BASE_URI+"/test");
            // Make the connection attempt.
            final Channel ch = b.connect(url.getHost(), url.getPort()).sync().channel();

            // Prepare the HTTP request.
            HttpRequest request = new DefaultFullHttpRequest(
                    HttpVersion.HTTP_1_1, HttpMethod.GET, url.getFile());
            request.headers().set(HttpHeaderNames.HOST, url.getHost());
            request.headers().set(HttpHeaderNames.CONNECTION, "keep-alive");
            // Send the HTTP request.
            ch.writeAndFlush(request);

            // waiting for server close connection after idle.
            ch.closeFuture().await();
         } finally {
            // Shut down executor threads to exit.
            group.shutdownGracefully();
         }
   }

    @Path("/")
    public static class Resource {
        @GET
        @Path("/test")
        @Produces(MediaType.TEXT_PLAIN)
        public String get() {
            return "hello world";
        }
    }
}
