package com.kryptnostic.rhizome.core;

import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.ServletContainerInitializer;
import javax.servlet.annotation.HandlesTypes;


import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.annotations.ClassInheritanceHandler;
import org.eclipse.jetty.annotations.ContainerInitializerAnnotationHandler;
import org.eclipse.jetty.annotations.ServletContainerInitializersStarter;
import org.eclipse.jetty.plus.annotation.ContainerInitializer;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.webapp.WebAppContext;

/**
 * This class contains an exact replica of the annotation configuration class, with the exception that it registers a
 * {@code RhizomeWebApplicationInitializer} for discovery during class path scanning.
 * 
 * @author Matthew Tamayo-Rios
 */
public class JettyAnnotationConfigurationHack extends AnnotationConfiguration {
    private static final Logger       LOG                    = Log.getLogger( JettyAnnotationConfigurationHack.class );
    private static final List<String> additionalInitializers = Lists.newArrayList();

    static {
        additionalInitializers.add( Rhizome.class.getCanonicalName() );
    }

    @Override
    public void createServletContainerInitializerAnnotationHandlers(
            WebAppContext context,
            List<ServletContainerInitializer> scis ) {
        if ( scis == null || scis.isEmpty() ) return; // nothing to do

        final List<ContainerInitializer> initializers = new ArrayList<>();
        context.setAttribute( CONTAINER_INITIALIZERS, initializers );

        for ( ServletContainerInitializer service : scis ) {
            HandlesTypes annotation = service.getClass().getAnnotation( HandlesTypes.class );
            ContainerInitializer initializer = null;
            if ( annotation != null ) {
                // There is a HandlesTypes annotation on the on the ServletContainerInitializer
                Class<?>[] classes = annotation.value();
                if ( classes != null ) {
                    initializer = new ContainerInitializer( service, classes );
                    /*
                     * Add custom initializer as a work around for https://bugs.eclipse.org/bugs/show_bug.cgi?id=404176
                     */
                    for ( String t : additionalInitializers ) {
                        initializer.addApplicableTypeName( t );
                    }
                    // If we haven't already done so, we need to register a handler that will
                    // process the whole class hierarchy to satisfy the ServletContainerInitializer
                    if ( context.getAttribute( CLASS_INHERITANCE_MAP ) == null ) {
                        // MultiMap<String> map = new MultiMap<>();
                        ConcurrentHashMap<String, Set<String>> map = new ClassInheritanceMap();
                        context.setAttribute( CLASS_INHERITANCE_MAP, map );
                        _classInheritanceHandler = new ClassInheritanceHandler( map );
                    }

                    for ( Class<?> c : classes ) {
                        // The value of one of the HandlesTypes classes is actually an Annotation itself so
                        // register a handler for it
                        if ( c.isAnnotation() ) {
                            if ( LOG.isDebugEnabled() )
                                LOG.debug( "Registering annotation handler for " + c.getName() );
                            _containerInitializerAnnotationHandlers.add( new ContainerInitializerAnnotationHandler(
                                    initializer,
                                    c ) );
                        }
                    }
                } else {
                    initializer = new ContainerInitializer( service, null );
                    if ( LOG.isDebugEnabled() )
                        LOG.debug( "No classes in HandlesTypes on initializer " + service.getClass() );
                }
            } else {
                initializer = new ContainerInitializer( service, null );
                if ( LOG.isDebugEnabled() ) LOG.debug( "No annotation on initializer " + service.getClass() );
            }

            initializers.add( initializer );
        }

        // add a bean to the context which will call the servletcontainerinitializers when appropriate
        ServletContainerInitializersStarter starter = (ServletContainerInitializersStarter) context
                .getAttribute( CONTAINER_INITIALIZER_STARTER );
        if ( starter != null ) throw new IllegalStateException( "ServletContainerInitializersStarter already exists" );
        starter = new ServletContainerInitializersStarter( context );
        context.setAttribute( CONTAINER_INITIALIZER_STARTER, starter );
        context.addBean( starter, true );
    }

    public static void registerInitializer( String className ) {
        additionalInitializers.add( className );
    }

    public static void removeInitializer( String className ) {
        additionalInitializers.remove( className );
    }
}
@@ -1567,339 +1567,47 @@
     
-if ( scis == null %7C%7C scis.isEmpty() ) return; // nothing to do%0A%0A        final List%3CContainerInitializer%3E initializers = new ArrayList%3C%3E();%0A        context.setAttribute( CONTAINER_INITIALIZERS, initializers );%0A%0A        for ( ServletContainerInitializer service : scis ) %7B%0A            HandlesTypes annotation = service.getClass().get
+super.createServletContainerInitializer
 Anno
@@ -1616,934 +1616,119 @@
 tion
-( 
 Handle
-sTypes.class );%0A            ContainerInitializer initializer = null;%0A            if ( annotation != null ) %7B%0A                // There is a HandlesTypes annotation on the on the ServletContainerInitializer%0A                Class%3C?%3E%5B%5D classes = annotation.value();%0A                if ( classes != null ) %7B%0A                    initializer = new ContainerInitializer( service, classes );%0A                    /*%0A                     * Add custom initializer as a work around for https://bugs.eclipse.org/bugs/show_bug.cgi?id=404176%0A                     */%0A                    for ( String t : additionalInitializers ) %7B%0A                        initializer.addApplicableTypeName( t );%0A                    %7D%0A                    // If we haven't already done so, we need to register a handler that will%0A                    // process the whole class hierarchy to satisfy the ServletContainerInitializer%0A                    if (
+rs( context, scis );%0A        final List%3CContainerInitializer%3E initializers = (List%3CContainerInitializer%3E)
  con
@@ -1751,1568 +1751,109 @@
 e( C
-LASS_
+ONTA
 IN
-H
 ER
-ITANCE_MAP ) == null ) %7B%0A                        // MultiMap%3CString%3E map = new MultiMap%3C%3E();%0A                        ConcurrentHashMap%3CString, Set%3CString%3E%3E map = new ClassInheritanceMap();%0A                        context.setAttribute( CLASS_INHERITANCE_MAP, map );%0A                        _classInheritanceHandler = new ClassInheritanceHandler( map );%0A                    %7D%0A%0A                    for ( Class%3C?%3E c : classes ) %7B%0A                        // The value of one of the HandlesTypes classes is actually an Annotation itself so%0A                        // register a handler for it%0A                        if ( c.isAnnotation() ) %7B%0A                            if ( LOG.isDebugEnabled() )%0A                                LOG.debug( %22Registering annotation handler for %22 + c.getName() );%0A                            _containerInitializerAnnotationHandlers.add( new ContainerInitializerAnnotationHandler(%0A                                    initializer,%0A                                    c ) );%0A                        %7D%0A                    %7D%0A                %7D else %7B%0A                    initializer = new ContainerInitializer( service, null );%0A                    if ( LOG.isDebugEnabled() )%0A                        LOG.debug( %22No classes in HandlesTypes on initializer %22 + service.getClass() );%0A                %7D%0A            %7D else %7B%0A                initializer = new ContainerInitializer( service, null );%0A                if ( LOG.isDebugEnabled() ) LOG.debug( %22No annotation on initializer %22 + service.getClass() );%0A            %7D%0A%0A           
+_INITIALIZERS );%0A        initializers.forEach( initializer -%3E additionalInitializers.forEach(
  ini
@@ -1864,608 +1864,33 @@
 izer
-s.add( initializer );%0A        %7D%0A%0A        // add a bean to the context which will call the servletcontainerinitializers when appropriate%0A        ServletContainerInitializersStarter starter = (ServletContainerInitializersStarter) context%0A                .getAttribute( CONTAINER_INITIALIZER_STARTER );%0A        if ( starter != null ) throw new IllegalStateException( %22ServletContainerInitializersStarter already exists%22 );%0A        starter = new ServletContainerInitializersStarter( context );%0A        context.setAttribute( CONTAINER_INITIALIZER_STARTER, starter );%0A        context.addBean( starter, true
+::addApplicableTypeName )
  );%0A

Make it a little less hacky.