package com.orgsync.api;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Map;

import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.ning.http.client.AsyncCompletionHandler;
import com.ning.http.client.AsyncHttpClient;
import com.ning.http.client.FluentStringsMap;
import com.ning.http.client.ListenableFuture;
import com.ning.http.client.Request;
import com.ning.http.client.RequestBuilder;
import com.ning.http.client.Response;
import com.orgsync.api.messages.ApiError;

public class ApiClientImpl implements ApiClient {

	public static final String HOST = "https://api.orgsync.com/api/";

	public static final Version DEFAULT_VERSION = Version.V2;

	private static final AsyncHttpClient DEFAULT_CLIENT = new AsyncHttpClient();

	private static final Gson DEFAULT_GSON = new GsonBuilder()
			.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
			.create();

	private final String apiKey;

	private final Version version;

	private AsyncHttpClient client;

	private final Gson gson;

	public ApiClientImpl(final String apiKey, final Version version) {
		this.apiKey = apiKey;
		this.version = version;
		setHttpClient(DEFAULT_CLIENT);
		this.gson = DEFAULT_GSON;
	}

	@Override
	public void destroy() {
		getHttpClient().close();
	}

	@Override
	public <T> T getModule(final Module<T> module) {
		return module.get(this);
	}

	// /* package */<T> ApiResponse<T> getResponse(final String method,
	// final String endpoint, final Type type) {
	// RequestBuilder result = makeCall(endpoint);
	// String body = null;
	// try {
	// body = result.getResponseBody();
	// } catch (IOException e) {
	// // TODO Auto-generated catch block
	// e.printStackTrace();
	// }
	//
	// if (result.getStatusCode() == 200 && body != null) {
	// return ApiResponse.success(gson.fromJson(body, type));
	// } else {
	// return ApiResponse.error(gson.fromJson(body, ApiError.class));
	// }
	// }
	//
	// private Response makeCall(final String endpoint) {
	//
	// try {
	// String url = toURL(endpoint);
	// System.out.println("Sending request to: " + url);
	// return getHttpClient().prepareGet(url).execute().get();
	// } catch (InterruptedException e) {
	// // TODO Auto-generated catch block
	// e.printStackTrace();
	// } catch (ExecutionException e) {
	// // TODO Auto-generated catch block
	// e.printStackTrace();
	// } catch (IOException e) {
	// // TODO Auto-generated catch block
	// e.printStackTrace();
	// }
	//
	// return null;
	// }

	public AsyncHttpClient getHttpClient() {
		return client;
	}

	public ApiClientImpl setHttpClient(final AsyncHttpClient client) {
		this.client = client;
		return this;
	}

	public String getApiKey() {
		return apiKey;
	}

	/* package */<T> ListenableFuture<ApiResponse<T>> getResponse(
			final RequestParams requestParams, final Type type) {
		Request request = buildRequest(requestParams);
		try {
			return client.executeRequest(request,
					new ResponseCompletionHandler<ApiResponse<T>>(type));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		// TODO obviously not good
		return null;
	}

	private Request buildRequest(final RequestParams requestParams) {
		return new RequestBuilder(requestParams.method)
				.setUrl(toURL(requestParams.endpoint))
				.setQueryParameters(mergeParams(requestParams.queryParams))
				.build();
	}

	private FluentStringsMap mergeParams(
			final Map<String, Collection<String>> queryParams) {
		return new FluentStringsMap(queryParams).add("key", apiKey);
	}

	// TODO gots to go...
	private String toURL(final String endpoint) {
		return new StringBuilder().append(HOST).append(version.getPath())
				.append(endpoint).toString();
	}

	private class ResponseCompletionHandler<T> extends
			AsyncCompletionHandler<T> {

		private final Type type;

		public ResponseCompletionHandler(final Type type) {
			this.type = type;
		}

		@Override
		@SuppressWarnings("unchecked")
		public T onCompleted(final Response response) throws Exception {
			String body = response.getResponseBody();

			if (response.getStatusCode() == 200) {
				return (T) ApiResponse.success(gson.fromJson(body, type));
			}

			return (T) ApiResponse.error(gson.fromJson(body, ApiError.class));
		}

	}

}

@@ -1464,1107 +1464,8 @@
 %09%7D%0A%0A
-%09// /* package */%3CT%3E ApiResponse%3CT%3E getResponse(final String method,%0A%09// final String endpoint, final Type type) %7B%0A%09// RequestBuilder result = makeCall(endpoint);%0A%09// String body = null;%0A%09// try %7B%0A%09// body = result.getResponseBody();%0A%09// %7D catch (IOException e) %7B%0A%09// // TODO Auto-generated catch block%0A%09// e.printStackTrace();%0A%09// %7D%0A%09//%0A%09// if (result.getStatusCode() == 200 && body != null) %7B%0A%09// return ApiResponse.success(gson.fromJson(body, type));%0A%09// %7D else %7B%0A%09// return ApiResponse.error(gson.fromJson(body, ApiError.class));%0A%09// %7D%0A%09// %7D%0A%09//%0A%09// private Response makeCall(final String endpoint) %7B%0A%09//%0A%09// try %7B%0A%09// String url = toURL(endpoint);%0A%09// System.out.println(%22Sending request to: %22 + url);%0A%09// return getHttpClient().prepareGet(url).execute().get();%0A%09// %7D catch (InterruptedException e) %7B%0A%09// // TODO Auto-generated catch block%0A%09// e.printStackTrace();%0A%09// %7D catch (ExecutionException e) %7B%0A%09// // TODO Auto-generated catch block%0A%09// e.printStackTrace();%0A%09// %7D catch (IOException e) %7B%0A%09// // TODO Auto-generated catch block%0A%09// e.printStackTrace();%0A%09// %7D%0A%09//%0A%09// return null;%0A%09// %7D%0A%0A
 %09pub
@@ -2513,31 +2513,8 @@
 %09%7D%0A%0A
-%09// TODO gots to go...%0A
 %09pri

Remove old comments and commented out methods.