//   Copyright 2012 Georg-August-Universität Göttingen, Germany
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

package de.ugoe.cs.autoquest.httpmonitor;

import javax.servlet.Servlet;

import de.ugoe.cs.util.console.Console;

/**
 * <p>
 * The HTTP monitor starts a web server ({@link HttpMonitorServer}) that receives exchanges
 * of the HTTP proxy. In addition, it provides via get a unique ordering id for requests and
 * responses that can be used by the proxies when creating the exchanges. The exchanges are
 * logged using the {@link HttpMonitorLogManager}. The class assures that on shutdown e.g. caused
 * by CTRL-C the server and the log manager are stopped correctly.
 * </p>
 * 
 * @author Patrick Harms
 */
public class HttpMonitor implements HttpMonitorComponent {

    /**
     * the port on which the webserver shall listen. Defaults to 8090.
     */
    private int port = 8090;
    
    /**
     * the web server receiving the exchanges
     */
    private HttpMonitorServer server;
    
    /**
     * the directory into which the log files shall be written
     */
    private String logFileBaseDir;

    /**
     * the log manager being responsible for performing the logging
     */
    private HttpMonitorLogManager logManager;

    /**
     * the id generator used for getting new unique ids
     */
    private IdGenerator idGenerator;

    /**
     * the thread needed to handle CTRL-C events
     */
    private Thread shutdownHook;

    /**
     * <p>
     * initializes the monitor with the command line arguments. Those may be the log directory
     * as first argument and the port to listen on as second
     * </p>
     *
     * @param commandLineArguments the command line arguments when starting the monitor using
     *                             the {@link Runner}
     */
    public HttpMonitor(String[] commandLineArguments) {
        if (commandLineArguments.length > 0) {
            this.logFileBaseDir = commandLineArguments[0];
            Console.println("putting logs into directory " + this.logFileBaseDir);
        }
        
        if (commandLineArguments.length > 1) {
            try {
                this.port = Integer.parseInt(commandLineArguments[1]);
            }
            catch (NumberFormatException e) {
                Console.println("ignoring invalid port specification " + commandLineArguments[1]);
            }
            Console.println("listening on port " + this.port);
        }
    }

    /* (non-Javadoc)
     * @see de.ugoe.cs.autoquest.htmlmonitor.HttpMonitorComponent#init()
     */
    @Override
    public synchronized void init() throws HttpMonitorException {
        if (server != null) {
            throw new IllegalStateException("already initialized.");
        }
        
        try {
            idGenerator = new SimpleIdGenerator();
            idGenerator.init();

            logManager = new HttpMonitorLogManager(logFileBaseDir);
            logManager.init();
        
            Servlet servlet = new HttpMonitorServlet(logManager, idGenerator);
            server = new HttpMonitorServer(port, servlet);
            server.init();
        
            shutdownHook = new Thread(new ShutdownHook(server, logManager));
        }
        catch (HttpMonitorException e) {
            Console.printerrln("could not initialize HTTP monitor: " + e);
            Console.logException(e);
        }
    }

    /* (non-Javadoc)
     * @see de.ugoe.cs.autoquest.htmlmonitor.HttpMonitorComponent#start()
     */
    @Override
    public synchronized void start() {
        if (server == null) {
            throw new IllegalStateException("not initialized.");
        }
        
        try {
            Runtime.getRuntime().addShutdownHook(shutdownHook);
            idGenerator.start();
            logManager.start();
            server.start();
        }
        catch (HttpMonitorException e) {
            Console.printerrln("could not start HTTP monitor: " + e);
            Console.logException(e);
        }
    }

    /* (non-Javadoc)
     * @see de.ugoe.cs.autoquest.htmlmonitor.HttpMonitorComponent#stop()
     */
    @Override
    public synchronized void stop() {
        if (server == null) {
            throw new IllegalStateException("not initialized.");
        }
        
        Runtime.getRuntime().removeShutdownHook(shutdownHook);
        server.stop();
        logManager.stop();
        idGenerator.stop();
        
        server = null;
        logManager = null;
        idGenerator = null;
    }

}
