//
//  ========================================================================
//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
//  ------------------------------------------------------------------------
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//

package org.eclipse.jetty.hazelcast.session;


import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.session.DefaultSessionCache;
import org.eclipse.jetty.server.session.SessionContext;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;

import static org.junit.jupiter.api.Assertions.*;

public class TestHazelcastSessions
{
    public static class TestServlet
        extends HttpServlet
    {

        @Override
        protected void doGet( HttpServletRequest req, HttpServletResponse resp )
            throws ServletException, IOException
        {
            String arg = req.getParameter( "action" );
            if ( arg == null )
            {
                return;
            }
            HttpSession s = null;
            if ( "set".equals( arg ) )
            {
                s = req.getSession( true );
                assertNotNull( s );
                s.setAttribute( "val", req.getParameter( "value" ) );
            }
            else if ( "get".equals( arg ) )
            {
                s = req.getSession( false );
                System.err.println( "GET: s=" + s + ",id=" + (s != null ? s.getId() : "" ) );
            }
            else if ( "del".equals( arg ) )
            {
                s = req.getSession();
                assertNotNull( s );
                s.invalidate();
                s = null;
            }

            resp.setContentType( "text/html" );
            PrintWriter w = resp.getWriter();
            if ( s == null )
            {
                w.write( "No session" );
            }
            else
            {
                w.write( (String) s.getAttribute( "val" ) );
            }
        }

    }

    private HazelcastSessionDataStore hazelcastSessionDataStore;
    private HazelcastSessionDataStoreFactory hazelcastSessionDataStoreFactory;

    private Server server;

    private ServerConnector serverConnector;

    String contextPath = "/";

    @BeforeEach
    public void initialize()
        throws Exception
    {

        server = new Server();
        serverConnector = new ServerConnector( server, new HttpConnectionFactory() );
        server.addConnector( serverConnector );

        ServletContextHandler context = new ServletContextHandler( ServletContextHandler.SESSIONS );
        context.setContextPath( contextPath );
        context.setResourceBase( System.getProperty( "java.io.tmpdir" ) );
        server.setHandler( context );

        SessionContext sessionContext = new SessionContext( "foo", null );

        hazelcastSessionDataStoreFactory = new HazelcastSessionDataStoreFactory();
        hazelcastSessionDataStore = (HazelcastSessionDataStore) hazelcastSessionDataStoreFactory.getSessionDataStore(
            context.getSessionHandler() );
        hazelcastSessionDataStore.initialize( sessionContext );

        DefaultSessionCache defaultSessionCache = new DefaultSessionCache( context.getSessionHandler() );
        defaultSessionCache.setSessionDataStore( hazelcastSessionDataStore );
        context.getSessionHandler().setSessionCache( defaultSessionCache );
        // Add a test servlet
        context.addServlet( new ServletHolder( new TestServlet() ), contextPath );

        server.start();
    }

    @AfterEach
    public void shutdown()
        throws Exception
    {
        hazelcastSessionDataStoreFactory.getHazelcastInstance().shutdown();
        server.stop();
    }

    @Test
    public void testHazelcast()
        throws Exception
    {

        int port = serverConnector.getLocalPort();
        HttpClient client = new HttpClient();
        client.start();
        try
        {
            int value = 42;
            ContentResponse response =
                client.GET( "http://localhost:" + port + contextPath + "?action=set&value=" + value );
            assertEquals( HttpServletResponse.SC_OK, response.getStatus() );
            String sessionCookie = response.getHeaders().get( "Set-Cookie" );
            assertTrue( sessionCookie != null );
            // Mangle the cookie, replacing Path with $Path, etc.
            sessionCookie = sessionCookie.replaceFirst( "(\\W)(P|p)ath=", "$1\\$Path=" );

            String resp = response.getContentAsString();
            assertEquals( resp.trim(), String.valueOf( value ) );

            // Be sure the session value is still there
            Request request = client.newRequest( "http://localhost:" + port + contextPath + "?action=get" );
            request.header( "Cookie", sessionCookie );
            response = request.send();
            assertEquals( HttpServletResponse.SC_OK, response.getStatus() );

            resp = response.getContentAsString();
            assertEquals( String.valueOf( value ), resp.trim() );

            //Delete the session
            request = client.newRequest( "http://localhost:" + port + contextPath + "?action=del" );
            request.header( "Cookie", sessionCookie );
            response = request.send();
            assertEquals( HttpServletResponse.SC_OK, response.getStatus() );

            //Check that the session is gone
            request = client.newRequest( "http://localhost:" + port + contextPath + "?action=get" );
            request.header( "Cookie", sessionCookie );
            response = request.send();
            assertEquals( HttpServletResponse.SC_OK, response.getStatus() );
            resp = response.getContentAsString();
            assertEquals( "No session", resp.trim() );



        }
        finally
        {
            client.stop();
        }

    }

}
