package org.jboss.weld.integration.deployer.env.helpers;

import javax.servlet.ServletContext;

import org.jboss.weld.bootstrap.api.Bootstrap;
import org.jboss.weld.bootstrap.api.Environments;
import org.jboss.weld.bootstrap.api.Service;
import org.jboss.weld.bootstrap.spi.BeanDeploymentArchive;
import org.jboss.weld.context.api.BeanStore;
import org.jboss.weld.ejb.spi.EjbServices;
import org.jboss.weld.injection.spi.EjbInjectionServices;
import org.jboss.weld.injection.spi.JpaInjectionServices;
import org.jboss.weld.injection.spi.ResourceInjectionServices;
import org.jboss.weld.integration.deployer.env.FlatDeployment;
import org.jboss.weld.security.spi.SecurityServices;
import org.jboss.weld.servlet.api.ServletServices;
import org.jboss.weld.transaction.spi.TransactionServices;
import org.jboss.weld.validation.spi.ValidationServices;

/**
 * A bean version of bootstrap that delegates to the underlying bootstrap impl
 *
 * @author Pete Muir
 *
 */
public class BootstrapBean
{

   static class JBossServletServices implements ServletServices
   {

      // For now, JBoss is using a totally flat deployment structure
      private final BeanDeploymentArchive beanDeploymentArchive;

      public JBossServletServices(BeanDeploymentArchive beanDeploymentArchive)
      {
         this.beanDeploymentArchive = beanDeploymentArchive;
      }


      public BeanDeploymentArchive getBeanDeploymentArchive(ServletContext ctx)
      {
         return beanDeploymentArchive;
      }

      public void cleanup() {}

   }

   private final Bootstrap bootstrap;
   private final FlatDeployment deployment;
   private BeanStore applicationBeanStore;

   public BootstrapBean(Bootstrap bootstrap, FlatDeployment flatDeployment)
   {
      this.bootstrap = bootstrap;
      this.deployment = flatDeployment;
   }

   public void setEjbServices(EjbServices ejbServices)
   {
      addDeploymentService(EjbServices.class, ejbServices);
   }

   public void setEjbInjectionServices(EjbInjectionServices service)
   {
      addBeanDeploymentArchiveService(EjbInjectionServices.class, service);
   }

   public void setJpaServices(JpaInjectionServices jpaServices)
   {
      addBeanDeploymentArchiveService(JpaInjectionServices.class, jpaServices);
   }

   public void setResourceServices(ResourceInjectionServices resourceServices)
   {
      addBeanDeploymentArchiveService(ResourceInjectionServices.class, resourceServices);
   }

   public FlatDeployment getDeployment()
   {
      return deployment;
   }

   public void setTransactionServices(TransactionServices transactionServices)
   {
      addDeploymentService(TransactionServices.class, transactionServices);
   }

   public void setApplicationContext(BeanStore applicationContext)
   {
      this.applicationBeanStore = applicationContext;
   }

   public void setValidationServices(ValidationServices validationServices)
   {
      addDeploymentService(ValidationServices.class, validationServices);
   }

   public void setSecurityServices(SecurityServices securityServices)
   {
      addDeploymentService(SecurityServices.class, securityServices);
   }

   private <S extends Service> void addDeploymentService(Class<S> type, S service)
   {
      getDeployment().getServices().add(type, service);
   }

   private <S extends Service> void addBeanDeploymentArchiveService(Class<S> type, S service)
   {
      if (getDeployment().getFlatBeanDeploymentArchive() == null)
      {
         throw new IllegalStateException("Must add BeanDeploymentArchive to FlatDeployment first!");
      }
      getDeployment().getFlatBeanDeploymentArchive().getServices().add(type, service);
   }

   public void boot()
   {
      bootstrap.startInitialization().deployBeans().validateBeans().endInitialization();
   }

   /**
    * @return the bootstrap
    */
   public Bootstrap getBootstrap()
   {
      return bootstrap;
   }

   public void initialize()
   {
      // Create the JBoss Servlet Services
      addDeploymentService(ServletServices.class, new JBossServletServices(deployment.getFlatBeanDeploymentArchive()));
      bootstrap.startContainer(Environments.EE_INJECT, deployment, applicationBeanStore);
   }

   public void shutdown()
   {
      bootstrap.shutdown();
   }

}