package ru.yandex.webmaster.common.health;

import java.util.Map;

import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.health.HealthCheckRegistry;
import com.codahale.metrics.servlets.AdminServletContextListener;
import com.codahale.metrics.servlets.HealthCheckServlet;
import com.codahale.metrics.servlets.MetricsServlet;
import com.codahale.metrics.servlets.ThreadDumpServlet;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * @author aherman
 */
public class MonitoringServletRegistrar implements ApplicationContextAware {
    private static final Logger log = LoggerFactory.getLogger(MonitoringServletRegistrar.class);

    private HealthCheckRegistry healthCheckRegistry;
    private MetricRegistry metricRegistry;
    private ApplicationContext applicationContext;

    public AbstractHandler createMonitoringHandler() {
        ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
        servletContextHandler.setContextPath("/monitoring");

        servletContextHandler.addEventListener(new AdminServletContextListener() {
            @Override
            protected MetricRegistry getMetricRegistry() {
                return metricRegistry;
            }

            @Override
            protected HealthCheckRegistry getHealthCheckRegistry() {
                return healthCheckRegistry;
            }
        });
//
        servletContextHandler.addServlet(HealthCheckServlet.class, "/health-check");
        servletContextHandler.addServlet(MetricsServlet.class, "/metrics");
        servletContextHandler.addServlet(ThreadDumpServlet.class, "/thread-dump");
        servletContextHandler.addServlet(PingServantlet.class, "/ping");

        Map<String, MonitoringServlet> monitoringServlets = applicationContext.getBeansOfType(MonitoringServlet.class);
        for (MonitoringServlet monitoringServlet : monitoringServlets.values()) {
            String path = monitoringServlet.getPath();
            if (path.charAt(0) != '/') {
                path = "/" + path;
            }
            if (path.length() > 1) {
                servletContextHandler.addServlet(new ServletHolder(monitoringServlet), path);
            } else {
                log.error("Unable to add monitoring servlet[{}], path too short: {}",
                        monitoringServlet.getClass().getCanonicalName(), path);
            }
        }

        return servletContextHandler;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Required
    public void setHealthCheckRegistry(HealthCheckRegistry healthCheckRegistry) {
        this.healthCheckRegistry = healthCheckRegistry;
    }

    @Required
    public void setMetricRegistry(MetricRegistry metricRegistry) {
        this.metricRegistry = metricRegistry;
    }
}
