package net.kencochrane.raven;

import net.kencochrane.raven.connection.AsyncConnection;
import net.kencochrane.raven.connection.Connection;
import net.kencochrane.raven.connection.HttpConnection;
import net.kencochrane.raven.connection.UdpConnection;
import net.kencochrane.raven.event.EventBuilder;
import net.kencochrane.raven.event.LoggedEvent;
import net.kencochrane.raven.marshaller.json.JsonMarshaller;

import java.nio.charset.Charset;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Raven {
    public static final String DEFAULT_CHARSET = "UTF-8";
    public static final String NAME = "Raven-Java/3.0";
    private static final Logger logger = Logger.getLogger(Raven.class.getCanonicalName());
    private Connection connection;

    public Raven() {
        this(new Dsn());
    }

    public Raven(String dsn) {
        this(new Dsn(dsn));
    }

    public Raven(Dsn dsn) {
        this(determineConnection(dsn));
    }

    public Raven(Connection connection) {
        this.connection = connection;
    }

    private static Charset determineCharset(Dsn dsn) {
        String charset = DEFAULT_CHARSET;

        if (dsn.getOptions().containsKey(Dsn.CHARSET_OPTION))
            charset = dsn.getOptions().get(Dsn.CHARSET_OPTION);

        return Charset.forName(charset);
    }

    //TODO: Replace with a factory?
    private static Connection determineConnection(Dsn dsn) {
        String protocol = dsn.getProtocol();
        Connection connection = null;
        Charset charset = determineCharset(dsn);
        JsonMarshaller marshaller = new JsonMarshaller();
        marshaller.setCompression(!dsn.getOptions().containsKey(Dsn.NOCOMPRESSION_OPTION));
        marshaller.setCharset(charset);

        if (protocol.equalsIgnoreCase("http") || protocol.equalsIgnoreCase("https")) {
            HttpConnection httpConnection = new HttpConnection(dsn);
            httpConnection.setMarshaller(marshaller);
            connection = httpConnection;
        } else if (protocol.equalsIgnoreCase("udp")) {
            UdpConnection udpConnection = new UdpConnection(dsn);
            udpConnection.setCharset(charset);
            udpConnection.setMarshaller(marshaller);
            connection = udpConnection;
        } else {
            logger.log(Level.WARNING,
                    "Couldn't figure out automatically a connection to Sentry, one should be set manually");
        }

        if (dsn.getOptions().containsKey(Dsn.ASYNC_OPTION))
            connection = new AsyncConnection(connection);

        return connection;
    }

    public UUID sendEvent(EventBuilder eventBuilder) {
        LoggedEvent event = eventBuilder.build();
        sendEvent(event);
        return event.getId();
    }

    public void sendEvent(LoggedEvent event) {
        try {
            connection.send(event);
        } catch (Exception e) {
            logger.log(Level.SEVERE, "An exception occurred while sending the event to Sentry.", e);
        }
    }

    public void setConnection(Connection connection) {
        this.connection = connection;
    }
}

@@ -342,16 +342,78 @@
 dEvent;%0A
+import net.kencochrane.raven.event.helper.EventBuilderHelper;%0A
 import n
@@ -522,16 +522,68 @@
 l.UUID;%0A
+import java.util.Collections;%0Aimport java.util.Set;%0A
 import j
@@ -900,16 +900,68 @@
 nection;
+%0A    private Set%3CEventBuilderHelper%3E builderHelpers;
 %0A%0A    pu
@@ -2928,32 +2928,237 @@
 getId();%0A    %7D%0A%0A
+    public void runBuilderHelpers(EventBuilder eventBuilder) %7B%0A        for (EventBuilderHelper builderHelper : builderHelpers) %7B%0A            builderHelper.helpBuildingEvent(eventBuilder);%0A        %7D%0A    %7D%0A%0A
     public void 
@@ -3486,11 +3486,379 @@
 n;%0A    %7D
+%0A%0A    public Set%3CEventBuilderHelper%3E getBuilderHelpers() %7B%0A        return Collections.unmodifiableSet(builderHelpers);%0A    %7D%0A%0A    public void removeBuilderHelper(EventBuilderHelper builderHelper) %7B%0A        builderHelpers.remove(builderHelper);%0A    %7D%0A%0A    public void addBuilderHelper(EventBuilderHelper builderHelper) %7B%0A        builderHelpers.add(builderHelper);%0A    %7D
 %0A%7D%0A

Add builder helpers to the Raven instance