package net.suaree.eventbrite;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import net.suaree.eventbrite.exception.RequestErrorException;
import net.suaree.eventbrite.exception.RequestException;
import net.suaree.eventbrite.model.EventData;
import net.suaree.eventbrite.operations.*;
import net.suaree.eventbrite.serialization.EventSearchDataDeserializer;
import net.suaree.eventbrite.serialization.LowercaseEnumTypeAdapterFactory;
import net.suaree.eventbrite.serialization.ResultBaseDeserializer;
import net.suaree.eventbrite.serialization.TimeZoneDeserializer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.TimeZone;

/**
 * A client for the Eventbrite APIs.
 *
 * @author roger
 */
public class EventbriteClient {
    private static final Log log = LogFactory.getLog(EventbriteClient.class);

    /**
     * Holds the credentials for accessing the Eventbrite APIs.
     */
    private final Credentials credentials;

    /**
     * Holds the HttpClient to use with this instance.
     */
    private final HttpClient httpClient;

    /**
     * Holds the Gson JSON serializer/deserializer to use with this instance.
     */
    private final Gson gson;

    /**
     * Initializes a new instance of EventbriteClient using the given Credentials.
     *
     * @param credentials The Credentials to use when calling the Eventbrite APIs.
     */
    public EventbriteClient(Credentials credentials) {
        this(credentials, new DefaultHttpClient());
    }

    /**
     * Initializes a new instance of EventbriteClient using the given Credentials.
     *
     * @param credentials The Credentials to use when calling the Eventbrite APIs.
     * @param httpClient  The HttpClient to use when invoking the Eventbrite APIs.
     */
    public EventbriteClient(Credentials credentials, HttpClient httpClient) {
        if (null == credentials) {
            throw new IllegalArgumentException("credentials");
        }

        if (null == httpClient) {
            throw new IllegalArgumentException("httpClient");
        }

        this.credentials = credentials;
        this.httpClient = httpClient;

        this.gson = new GsonBuilder()
                .registerTypeAdapter(ResultBase.class, new ResultBaseDeserializer())
                .registerTypeAdapter(EventData.class, new EventSearchDataDeserializer())
                .registerTypeAdapter(TimeZone.class, new TimeZoneDeserializer())
                .registerTypeAdapterFactory(new LowercaseEnumTypeAdapterFactory())
                .create();
    }

    /**
     * Searches for events using the Eventbrite event_search API.
     *
     * @param request The parameters for the search request.
     * @return An instance of EventsResult that describes the result of the event_search API call.
     * @throws RequestException
     */
    public EventsResult search(SearchRequest request) throws RequestException {
        ResultBase result = sendRequest(request);

        return (EventsResult) result;
    }

    /**
     * Gets the event described by the GetEventRequest using the Eventbrite event_get API.
     *
     * @param request The parameters for the get request.
     * @return An instance of EventResult that describes the result of the event_get API call.
     * @throws RequestException
     */
    public EventResult get(GetEventRequest request) throws RequestException {
        ResultBase result = sendRequest(request);

        return (EventResult) result;
    }

    /**
     * Gets the venue described by the GetVenueRequest using the Eventbrite venue_get API.
     *
     * @param request The parameters for the get request.
     * @return An instance of VenueResult that describes the result of the venue_get API call.
     * @throws RequestException
     */
    public VenueResult get(GetVenueRequest request) throws RequestException {
        ResultBase result = sendRequest(request);

        return (VenueResult) result;
    }

    /**
     * Sends the given request to the service and returns the resulting HttpResponse.
     *
     * @param request The RequestBase that describes the request to send to the service.
     * @return An instance of ResultBase that represents the response from the service.
     * @throws RequestException
     */
    private ResultBase sendRequest(RequestBase request) throws RequestException {
        assert null != request;

        HttpGet get = null;

        try {
            URI requestUri = request.getUri(credentials);
            get = new HttpGet(requestUri);

            if (log.isDebugEnabled()) {
                log.debug(String.format("GET %s", get.getURI()));
            }

            HttpResponse response = httpClient.execute(get);
            InputStream in = response.getEntity().getContent();
            Reader reader;

            if (log.isDebugEnabled()) {
                log.debug("Response Headers:");

                for (Header header : response.getAllHeaders()) {
                    log.debug(String.format("%s: %s", header.getName(), header.getValue()));
                }
            }

            reader = new InputStreamReader(in);

            if (log.isTraceEnabled()) {
                // If tracing is enabled for this class, wrap the InputStreamReader in a LoggingInputStreamReader so we
                // can log the request body.
                reader = new LoggingInputStreamReader(new BufferedReader(reader));
            }

            ResultBase result = gson.fromJson(reader, ResultBase.class);

            if (result instanceof ErrorResult) {
                throw new RequestErrorException(((ErrorResult) result).getError());
            }

            return result;
        } catch (URISyntaxException ex) {
            log.error("URISyntaxException:", ex);

            throw new RequestException(ex);
        } catch (ClientProtocolException ex) {
            log.error("ClientProtocolException:", ex);

            throw new RequestException(ex);
        } catch (IOException ex) {
            log.error("IOException:", ex);

            throw new RequestException(ex);
        } finally {
            if (null != get) {
                get.releaseConnection();
            }
        }
    }
}

@@ -690,24 +690,59 @@
 ttp.Header;%0A
+import org.apache.http.HttpEntity;%0A
 import org.a
@@ -766,16 +766,16 @@
 sponse;%0A
-
 import o
@@ -2955,32 +2955,122 @@
 reate();%0A    %7D%0A%0A
+    public void shutdown() %7B%0A        httpClient.getConnectionManager().shutdown();%0A    %7D%0A%0A
     /**%0A     * S
@@ -4914,16 +4914,47 @@
  = null;
+%0A        InputStream in = null;
 %0A%0A      
@@ -5257,30 +5257,33 @@
         
-InputStream in
+HttpEntity entity
  = respo
@@ -5297,16 +5297,170 @@
 Entity()
+;%0A%0A            if (null == entity) %7B%0A                throw  new RequestException(%22No entity present in response.%22);%0A            %7D%0A%0A            in = entity
 .getCont
@@ -6774,32 +6774,32 @@
 tException(ex);%0A
-
         %7D finall
@@ -6798,24 +6798,235 @@
 %7D finally %7B%0A
+            if (null != in) %7B%0A                try %7B%0A                    in.close();%0A                %7D catch (IOException ex) %7B%0A                    log.error(%22IOException:%22, ex);%0A                %7D%0A            %7D%0A%0A
             

Add the shutdown method to the EventbriteClient to shut down the HttpClient ConnectionManager.