package org.jboss.seam.wicket.mock;

import java.io.File;
import java.net.URISyntaxException;
import java.net.URL;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletResponse;

import org.apache.wicket.protocol.http.HttpSessionStore;
import org.apache.wicket.protocol.http.WebRequestCycle;
import org.apache.wicket.protocol.http.WebResponse;
import org.apache.wicket.session.ISessionStore;
import org.apache.wicket.util.tester.BaseWicketTester;
import org.apache.wicket.util.tester.DummyHomePage;
import org.apache.wicket.util.tester.WicketTester;
import org.jboss.seam.Seam;
import org.jboss.seam.contexts.Lifecycle;
import org.jboss.seam.contexts.ServletLifecycle;
import org.jboss.seam.core.Init;
import org.jboss.seam.init.Initialization;
import org.jboss.seam.wicket.SeamWebApplication;


/**
 * A subclass of WicketTester that enforces the use of a SeamWebApplication.  This ensures that
 * ensures that seam contexts are are set up and torn down correctly in testing.   Each SeamWebApplication
 * gets a complete application context, so seam application teardown/restart happens if you create
 * a new SeamWicketTester without propogating any existing SeamWebApplication through the constructor.
 */
public class SeamWicketTester extends WicketTester
{

   public SeamWicketTester()
   {
      this(DummyHomePage.class);
   }
   
   public SeamWicketTester(Class homePage) 
   {
      this(homePage,null);
   }
   
   public SeamWicketTester(Class homePage, Class loginPage) 
   {
      this(createApplication(homePage, loginPage));
   }
   
   public SeamWicketTester(final SeamWebApplication application)
   {
      this(application,null);
   }
   
   public SeamWicketTester(final SeamWebApplication application, final String path)
   {
      super(application,path);
      
      /*
       * When in tests, we want the contexts destroyed lazily, i.e. 
       * don't destroy the contexts after a request, but rather before the 
       * next request, so that we can inspect the values of wicket components and
       * their models 
       */
      Lifecycle.beginCall();
      ((SeamWebApplication)getApplication()).setDestroyContextsLazily(true);
      Lifecycle.endCall();
   }

   /**
    * Create a SeamWebApplication suitable for testing, a la WicketTester's DummyApplication
    * @param homePage The WebPage class to start on
    * @param loginPage The WebPage class to use for any Seam Authentication redirects
    */
   private static SeamWebApplication createApplication(final Class homePage, final Class loginPage)
   {
      return new SeamWebApplication()
      {
         @Override
         public Class getHomePage()
         {
            return homePage;
         }
         
         @Override
         protected Class getLoginPage()
         {
            return loginPage;
         }

         @Override
         protected ISessionStore newSessionStore()
         {
            // Don't use a filestore, or we spawn lots of threads, which
            // makes things slow.
            return new HttpSessionStore(this);
         }

         @Override
         protected WebResponse newWebResponse(final HttpServletResponse servletResponse)
         {
            // Don't use a buffered response in testing 
            return new WebResponse(servletResponse);
         }

         @Override
         protected void outputDevelopmentModeWarning()
         {
            // Do nothing.
         }
      };
   }
   
   /**
    * For each new servletContext, i.e. each new SeamWebApplication instance, we create a new seam
    * initialization.
    */
   @Override
   public ServletContext newServletContext(String path) 
   { 
      if (ServletLifecycle.getServletContext() != null)
      {
         ServletLifecycle.endApplication();
      }
      if (path == null) 
      {
         URL webxml = getClass().getResource("/WEB-INF/web.xml");
         if (webxml != null)
         {
            try
            {
               path = new File(webxml.toURI()).getParentFile().getParentFile().getAbsolutePath();
            }
            catch (URISyntaxException e)
            {
               throw new RuntimeException(e);
            }
         }
      }
      ServletContext context = super.newServletContext(path);
      //startJbossEmbeddedIfNecessary();
      ServletLifecycle.beginApplication(context);
      new Initialization(context).create().init();
      ((Init) context.getAttribute(Seam.getComponentName(Init.class))).setDebug(false);
      return context;
   }

   @Override
   public WebRequestCycle setupRequestAndResponse(boolean isAjax) { 
      WebRequestCycle cycle = super.setupRequestAndResponse(isAjax);
      /**
       * FormTester wants to walk the form tree and call getValue() on components
       * without having started the request cycle.  This fails when wicket components have
       * seam injections.  So force a call here 
       */
      BaseWicketTester.callOnBeginRequest(cycle);
      return cycle;
   }
   
   private static boolean started;

//   protected void startJbossEmbeddedIfNecessary() 
//   {
//      try 
//      {
//         if (!started && embeddedJBossAvailable())
//         {
//            new EmbeddedBootstrap().startAndDeployResources();
//         }
//         started = true;
//      }
//      catch (Exception exception)
//      {
//         throw new RuntimeException("Failure starting up Embedded Jboss",exception);
//      }
//   }
//
//   private boolean embeddedJBossAvailable()
//   {
//      try
//      {
//         Class.forName("org.jboss.embedded.Bootstrap");
//         return true;
//      }
//      catch (ClassNotFoundException e)
//      {
//         return false;
//      }
//   }

}
