package com.docusign.esign.client.auth;

import com.migcomponents.migbase64.Base64;
import java.util.Map;

import javax.ws.rs.core.Response.Status.Family;
import org.apache.oltu.oauth2.client.HttpClient;
import org.apache.oltu.oauth2.client.response.OAuthClientResponse;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest;
import org.apache.oltu.oauth2.client.response.OAuthClientResponseFactory;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest.AuthenticationRequestBuilder;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest.TokenRequestBuilder;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.types.GrantType;
import com.sun.jersey.api.client.WebResource.Builder;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;

public class OAuthJerseyClient implements HttpClient {

	private Client client;

	public OAuthJerseyClient() {
		this.client = new Client(null, null);
	}

	public OAuthJerseyClient(Client client) {
		this.client = client;
	}

	public <T extends OAuthClientResponse> T execute(OAuthClientRequest request, Map<String, String> headers,
			String requestMethod, Class<T> responseClass) throws OAuthSystemException, OAuthProblemException {
		String contentType = headers.get("Content-Type");
		String url = request.getLocationUri();
		String body = request.getBody();
		Builder builder = this.client.resource(url).getRequestBuilder();

		for (String key : headers.keySet()) {
			builder = builder.header(key, headers.get(key));
		}
		
		String grantType = null, code = null, clientId = null, clientSecret = null;
		for (String entry : body.split("&")) {
			String key = entry.split("=")[0];
			String value = entry.split("=")[1];
			if ("grant_type".equals(key)) {
				grantType = value;
			} else if ("code".equals(key)) {
				code = value;
			} else if ("client_id".equals(key)) {
				clientId = value;
			} else if ("client_secret".equals(key)) {
				clientSecret = value;
			}
		}

		if (grantType == null) {
			throw new OAuthSystemException("Missing grant_type");
		}
		if (!grantType.equals(GrantType.REFRESH_TOKEN.toString()) && code == null) {
			throw new OAuthSystemException("Missing code for grant_type="+grantType);
		}

		if (code == null) {
			body = "grant_type=" + grantType;
		} else {
			body = "grant_type=" + grantType + "&code=" + code;
		}

		if (clientId == null || clientSecret == null) {
			throw new OAuthSystemException("Missing clientId/secret");
		} else {
			byte[] bytes = (clientId + ":" + clientSecret).getBytes();
			builder.header("Authorization", "Basic " + Base64.encodeToString(bytes, false));
		}

		ClientResponse response = null;

		if ("GET".equals(requestMethod)) {
			response = (ClientResponse) builder.get(ClientResponse.class);
		} else if ("POST".equals(requestMethod)) {
			response = builder.type(contentType).post(ClientResponse.class, body);
		} else if ("PUT".equals(requestMethod)) {
			response = builder.type(contentType).put(ClientResponse.class, body);
		} else if ("DELETE".equals(requestMethod)) {
			response = builder.type(contentType).delete(ClientResponse.class, body);
		}

		if(response.getStatusInfo() == ClientResponse.Status.NO_CONTENT) {
	      return null;
	    } else if (response.getStatusInfo().getFamily() == Family.SUCCESSFUL) {
	      if (responseClass == null)
	        return null;
	      else {
	    	String respBody = response.getEntity(String.class);
	        return OAuthClientResponseFactory.createCustomResponse(
	        		respBody,
                    contentType,
                    response.getStatus(),
                    response.getHeaders(),
                    responseClass
            );
	      }
	    } else {
	      String message = "error";
	      String respBody = null;
	      if (response.hasEntity()) {
	        try {
	          respBody = response.getEntity(String.class);
	          message = respBody;
	          System.err.println(message);
	        } catch (RuntimeException e) {
	          e.printStackTrace();
	        }
	      }
	    }
		return null;
	}

	public void shutdown() {
		// Nothing to do here
	}
}

@@ -1729,16 +1729,37 @@
 Secret =
+ null, refreshToken =
  null;%0A%09
@@ -2116,24 +2116,95 @@
 et = value;%0A
+%09%09%09%7D else if (%22refresh_token%22.equals(key)) %7B%0A%09%09%09%09refreshToken = value;%0A
 %09%09%09%7D%0A%09%09%7D%0A%0A%09%09
@@ -2453,42 +2453,155 @@
 %09%09%7D%0A
-%0A
 %09%09if (
-code == null) %7B%0A%09%09%09body = %22
+grantType.equals(GrantType.REFRESH_TOKEN.toString()) && refreshToken == null) %7B%0A%09%09%09throw new OAuthSystemException(%22Missing refresh_token for 
 gran
@@ -2600,35 +2600,33 @@
 for grant_type=%22
- + 
++
 grantType;%0A%09%09%7D e
@@ -2618,30 +2618,24 @@
 rantType
+)
 ;%0A%09%09%7D
- else %7B%0A%09
+%0A%0A
 %09%09body =
@@ -2664,26 +2664,149 @@
 Type
- + %22&code=%22 + code
+;%0A%09%09if (code != null) %7B%0A%09%09%09body = body + %22&code=%22 + code;%0A%09%09%7D%0A%09%09if (refreshToken != null) %7B%0A%09%09%09body = body + %22&refresh_token=%22 + refreshToken
 ;%0A%09%09

check and set refresh_token in body of request