package org.iri_research.renkan.coweb;

import java.util.HashMap;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.servlet.ServletContext;

import org.cometd.annotation.ServerAnnotationProcessor;
import org.cometd.bayeux.server.BayeuxServer;
import org.cometd.server.BayeuxServerImpl;
import org.cometd.websocket.server.WebSocketTransport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.web.context.ServletContextAware;

//@Component
//@Scope("prototype")
public class SpringConfigurer implements DestructionAwareBeanPostProcessor, ServletContextAware, ApplicationContextAware
{
	
    private BayeuxServer bayeuxServer;
    private ServerAnnotationProcessor processor;
    private final Logger logger = LoggerFactory.getLogger(SpringConfigurer.class);
    private ApplicationContext context;
    
    private static volatile SpringConfigurer instance = null;
        
    private SpringConfigurer() 
    {
    	this.logger.debug("Buiding SpringCond=figurer");    	
    }
    
    public static SpringConfigurer getInstance() {
    	if (instance == null) {
    		synchronized (SpringConfigurer.class) {
				if(instance == null) {
					instance = new SpringConfigurer();
				}
			}
    	}
    	return instance;
    }

    @Inject
    private void setBayeuxServer(BayeuxServer bayeuxServer)
    {
        this.bayeuxServer = bayeuxServer;
    }

    @PostConstruct
    private void init()
    {
        this.processor = new ServerAnnotationProcessor(bayeuxServer);
    }

    public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException
    {
        processor.processDependencies(bean);
        processor.processConfigurations(bean);
        processor.processCallbacks(bean);
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String name) throws BeansException
    {
        return bean;
    }

    public void postProcessBeforeDestruction(Object bean, String name) throws BeansException
    {
        processor.deprocessCallbacks(bean);
    }

    @Bean(initMethod = "start", destroyMethod = "stop")
    public BayeuxServer bayeuxServer()
    {
        BayeuxServerImpl bean = new BayeuxServerImpl();
        bean.addTransport(new WebSocketTransport(bean));
        Map<String, Object> options = new HashMap<String, Object>();
        options.put(BayeuxServerImpl.LOG_LEVEL, "1");
        options.put("timeout", "1500");
        bean.setOptions(options);
        return bean;
    }

    public void setServletContext(ServletContext servletContext)
    {
        servletContext.setAttribute(BayeuxServer.ATTRIBUTE, bayeuxServer);
    }

	@Override
	@Inject
	public void setApplicationContext(ApplicationContext context)
			throws BeansException {
		this.context = context;
	}
	
	public ApplicationContext getApplicationContext() {
		return this.context;
	}
}