//   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.proxy;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.logging.Level;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.client.util.OutputStreamContentProvider;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpVersion;

import de.ugoe.cs.autoquest.httpmonitor.HttpMonitor;
import de.ugoe.cs.autoquest.httpmonitor.HttpMonitorExchangeHandler;
import de.ugoe.cs.autoquest.plugin.http.logdata.HttpExchange;
import de.ugoe.cs.autoquest.plugin.http.logdata.ObjectFactory;
import de.ugoe.cs.util.console.Console;

/**
 * <p>
 * If the exchanges recorded by the proxy are to be transmitted to a central {@link HttpMonitor},
 * this exchanges handler is used. It is called by the exchange listener on completion of a proxied
 * request/response. It then creates an HTTP request to the central monitor and sends it there.
 * It is initialized with the name of the server and the port on which the central monitor runs.
 * If the exchanges cannot be forwarded to the central server, they are discarded.
 * </p>
 * 
 * @author Patrick Harms
 */
public class HttpMonitorRemoteExchangeHandler
    extends HttpMonitorRemoteConnection
    implements HttpMonitorExchangeHandler
{
    
    /**
     * <p>
     * initializes the exchange handler with the host and port of the central server
     * </p>
     *
     * @param httpMonitorServer the host name of the central server
     * @param httpMonitorPort   the port of the central server
     */
    public HttpMonitorRemoteExchangeHandler(String httpMonitorServer, int httpMonitorPort) {
        super(httpMonitorServer, httpMonitorPort);
    }

    /* (non-Javadoc)
     * @see de.ugoe.cs.autoquest.httpmonitor.HttpMonitorExchangeHandler#handleHttpExchange()
     */
    @Override
    public synchronized void handleHttpExchange(HttpExchange httpExchange) {
        // send the exchange to the server and wait for completion
        Request httpMonitorRequest = super.newRequest();
        httpMonitorRequest.method(HttpMethod.POST);
        httpMonitorRequest.version(HttpVersion.HTTP_1_1);

        OutputStreamContentProvider out = new OutputStreamContentProvider();
        httpMonitorRequest.content(out);
        
        super.sendRequest(httpMonitorRequest);

        try {
            JAXBContext jaxbContext =
                JAXBContext.newInstance(HttpExchange.class.getPackage().getName());
            Marshaller marshaller = jaxbContext.createMarshaller();

            OutputStreamWriter writer = new OutputStreamWriter(out.getOutputStream(), "UTF-8");
            marshaller.marshal(new ObjectFactory().createHttpExchange(httpExchange), writer);

            out.getOutputStream().close();
        }
        catch (JAXBException e) {
            Console.printerrln("could not convert request and response to XML string: " + e);
            Console.logException(e);
        }
        catch (IOException e) {
            Console.printerrln
                ("could not close the stream for sending data to the HTML monitor: " + e);
            Console.logException(e);
        }
        
        // wait to ensure that the request was received
        Result result = super.getResult(httpMonitorRequest);
        
        if (result.isFailed()) {
            Console.traceln
                (Level.WARNING, "could not log exchange correctly: " + result.getFailure());
            Console.logException((Exception) result.getFailure());
        }
    }
}
