package com.guidewire.pl.system.servlet;

import com.guidewire.commons.profiler.Profiler;
import com.guidewire.commons.system.DeploymentEnvironment;
import com.guidewire.pl.system.database.DatabaseDependencies;
import com.guidewire.pl.system.database.connection.ConnectionPool;
import com.guidewire.pl.system.database.connection.DriverSupport;
import com.guidewire.pl.system.logging.PLLoggerCategory;
import com.guidewire.pl.system.server.InitTab;
import com.guidewire.pl.system.server.Version;
import com.guidewire.testharness.mock.GosuUtil;
import gw.api.profiler.ProfilerFrame;
import gw.api.profiler.ProfilerTag;
import gw.api.system.server.Runlevel;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.Properties;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class GuidewireStartupServlet extends HttpServlet {
   public static final String JAVA_HEADLESS_PARAM = "java.awt.headless";
   private static GuidewireStartupServlet _instance = null;

   public static GuidewireStartupServlet getInstance() {
      return _instance;
   }

   public GuidewireStartupServlet() {
      _instance = this;
   }

   public void init() {
      ProfilerFrame profilerFrame = Profiler.push(ProfilerTag.SERVER_INITIALIZATION);

      try {
         ServletContext servletContext = this.getServletContext();
         ServletUtilities.initServletEnvironment(servletContext);
         this.setSystemProps(servletContext);
         DeploymentEnvironment deploymentEnvironment = DeploymentEnvironment.getInstance();
         PLLoggerCategory.SERVER.debug("JRE Version       = " + deploymentEnvironment.getJreVersion());
         PLLoggerCategory.SERVER.debug("JRE Vendor        = " + deploymentEnvironment.getJreVendor());
         PLLoggerCategory.SERVER.debug("Classpath         = " + deploymentEnvironment.getClasspath());
         PLLoggerCategory.SERVER.debug("OS Name           = " + deploymentEnvironment.getOsName());
         PLLoggerCategory.SERVER.debug("OS Arch           = " + deploymentEnvironment.getOsArch());
         PLLoggerCategory.SERVER.debug("OS Version        = " + deploymentEnvironment.getOsVersion());
         PLLoggerCategory.SERVER.debug("Servlet Container = " + deploymentEnvironment.getServletContainer());

         try {
            InitTab.getInstance().setRunLevel(InitTab.getStartingRunlevel());
            String msg = "***** " + Version.getAppName() + " ready *****";
            PLLoggerCategory.SERVER_RUNLEVEL.info(msg);
         } catch (Throwable e) {
            PLLoggerCategory.SERVER_RUNLEVEL.error("***** " + Version.getAppName() + " unable to start *****", e);
         }
      } finally {
         Profiler.pop(profilerFrame);
      }
   }

   protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      resp.setContentType("text/plain; charset=UTF8");

      try (PrintWriter out = resp.getWriter()) {
         out.print(InitTab.getInstance().getRunLevelNoLock().name());
      }
   }

   public void destroy() {
      ProfilerFrame profilerFrame = Profiler.push(ProfilerTag.SERVER_SHUTDOWN);

      try {
         try {
            PLLoggerCategory.SERVER_RUNLEVEL.info("***** " + Version.getAppName() + " shutting down *****");
            if (InitTab.getInstance().getRunLevel().isLater(Runlevel.SHUTDOWN)) {
               InitTab.getInstance().setRunLevel(Runlevel.SHUTDOWN);
               if (DatabaseDependencies.getDatabase() != null && DatabaseDependencies.getDatabase().getDBSupport() != null) {
                  DatabaseDependencies.getDatabase().getDBSupport().ensureDatabaseClosed();
                  ConnectionPool connectionPool = DatabaseDependencies.getDatabase().getConnectionPool();
                  if (!connectionPool.isExternallyManaged()) {
                     connectionPool.close();
                  }
               }

               DriverSupport.unregisterJdbcDriversLoadedByClassLoader(this.getClass().getClassLoader());
            }

            InitTab.getInstance().setRunLevel(Runlevel.NONE);
         } catch (Exception e) {
            PLLoggerCategory.SERVER_RUNLEVEL.error("***** " + Version.getAppName() + " unable to shut down *****", e);
         }

         if (!Boolean.getBoolean("gw.disable.aggressive.jar.cleanup")) {
            GosuUtil.maybeCloseOpenJarFiles();
         }

         PLLoggerCategory.SERVER_RUNLEVEL.info("***** " + Version.getAppName() + " successfully shut down *****");
      } finally {
         Profiler.pop(profilerFrame);
      }
   }

   public String getServletInfo() {
      return this.getServletName();
   }

   public String getServletName() {
      return "Guidewire Servlet Startup";
   }

   private void setSystemProps(ServletContext servletContext) {
      Properties systemProps = System.getProperties();
      Enumeration e = servletContext.getInitParameterNames();

      while (e.hasMoreElements()) {
         String name = (String)e.nextElement();
         String value = servletContext.getInitParameter(name);
         String oldValue = System.getProperty(name);
         if (oldValue != null && oldValue.length() > 0) {
            PLLoggerCategory.SERVER_RUNLEVEL.debug("Retaining system property: \"" + name + "=" + oldValue + "\"");
         } else {
            PLLoggerCategory.SERVER_RUNLEVEL.debug("Setting system property: \"" + name + "=" + value + "\"");
            systemProps.setProperty(name, value);
         }
      }
   }
}
