package etomica.server;

import com.fasterxml.jackson.databind.module.SimpleModule;
import com.google.inject.AbstractModule;
import com.google.inject.Injector;
import com.google.inject.Provides;
import etomica.meta.ComponentIndex;
import etomica.meta.SimulationModel;
import etomica.meta.properties.Property;
import etomica.meta.wrappers.Wrapper;
import etomica.server.health.BasicHealthCheck;
import etomica.server.resources.*;
import etomica.server.serializers.PropertySerializer;
import etomica.server.serializers.SimulationModelSerializer;
import etomica.server.serializers.WrapperSerializer;
import etomica.simulation.Simulation;
import io.dropwizard.Application;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
import io.dropwizard.websockets.WebsocketBundle;
import ru.vyarus.dropwizard.guice.GuiceBundle;

import javax.inject.Inject;
import javax.inject.Singleton;
import javax.websocket.server.ServerEndpointConfig;
import java.util.Map;
import java.util.Timer;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

public class EtomicaServer extends Application<EtomicaServerConfig> {
    private final Map<UUID, SimulationModel> simStore = new ConcurrentHashMap<>();
    private final Timer timer = new Timer();

    @Override
    public String getName() {
        return "EtomicaServer";
    }

    @Override
    public void initialize(Bootstrap<EtomicaServerConfig> bootstrap) {

        bootstrap.addBundle(GuiceBundle.builder()
                .enableAutoConfig(getClass().getPackage().getName())
                .modules(new WebSocketModule(), new EtomicaServerModule())
                .build()
        );

        SimpleModule mod = new SimpleModule("Etomica Module");
        mod.addSerializer(new PropertySerializer(Property.class));
        mod.addSerializer(new WrapperSerializer(Wrapper.class));
        mod.addSerializer(new SimulationModelSerializer(SimulationModel.class));

        bootstrap.getObjectMapper().registerModule(mod);

        final ServerEndpointConfig wsConfig = ServerEndpointConfig.Builder
                .create(ConfigurationStreamResource.class, "/simulations/{id}/configuration")
                .build();

        wsConfig.getUserProperties().put("simStore", simStore);
        wsConfig.getUserProperties().put("timer", timer);

        WebsocketBundle wsBundle = new WebsocketBundle(new WSConfigurator());
        wsBundle.addEndpoint(EchoServer.class);
        wsBundle.addEndpoint(ConfigurationStreamResource.class);

        bootstrap.addBundle(wsBundle);

        super.initialize(bootstrap);
    }

    @Override
    public void run(EtomicaServerConfig configuration, Environment environment) throws Exception {
        environment.healthChecks().register("basic", new BasicHealthCheck());

//        environment.jersey().register(new SimulationsIndexResource(new ComponentIndex<>(Simulation.class)));
//        environment.jersey().register(new SimulationResource(simStore));
//        environment.jersey().register(new ControlResource(simStore));

    }

    public static void main(String[] args) throws Exception {
        new EtomicaServer().run(args);
    }

    private static class WSConfigurator extends ServerEndpointConfig.Configurator {
        @Inject
        private static Injector injector;

        @Override
        public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException {
            return injector.getInstance(endpointClass);
        }
    }

    private static class WebSocketModule extends AbstractModule {

        @Override
        protected void configure() {
            requestStaticInjection(WSConfigurator.class);
        }
    }

    private static class EtomicaServerModule extends AbstractModule {

        @Override
        protected void configure() {
        }

        @Provides @Singleton
        ComponentIndex<Simulation> provideSimulationIndex() {
            return new ComponentIndex<>(Simulation.class);
        }
    }
}

@@ -785,24 +785,77 @@
 cketBundle;%0A
+import org.eclipse.jetty.servlets.CrossOriginFilter;%0A
 import ru.vy
@@ -945,24 +945,102 @@
 .Singleton;%0A
+import javax.servlet.DispatcherType;%0Aimport javax.servlet.FilterRegistration;%0A
 import javax
@@ -1079,16 +1079,42 @@
 Config;%0A
+import java.util.EnumSet;%0A
 import j
@@ -2941,16 +2941,52 @@
 heck());
+%0A        configureCors(environment);
 %0A%0A//    
@@ -3345,32 +3345,720 @@
 n(args);%0A    %7D%0A%0A
+    private static void configureCors(Environment env) %7B%0A        final FilterRegistration.Dynamic cors = env.servlets().addFilter(%22CORS%22, CrossOriginFilter.class);%0A%0A        cors.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, %22*%22);%0A        cors.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, %22X-Requested-With,Content-Type,Accept,Origin,Authorization%22);%0A        cors.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, %22OPTIONS,GET,PUT,POST,DELETE,HEAD%22);%0A        cors.setInitParameter(CrossOriginFilter.ALLOW_CREDENTIALS_PARAM, %22true%22);%0A%0A        // Add URL mapping%0A        cors.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, %22/*%22);%0A    %7D%0A%0A
     private stat

Add CORS headers filter to server