package ro.pub.cs.vmchecker.client.service;

import java.util.HashMap;
import java.util.Iterator;

import ro.pub.cs.vmchecker.client.event.AuthenticationEvent;
import ro.pub.cs.vmchecker.client.event.ErrorDisplayEvent;
import ro.pub.cs.vmchecker.client.model.ErrorResponse;
import ro.pub.cs.vmchecker.client.service.json.ErrorResponseDecoder;
import ro.pub.cs.vmchecker.client.service.json.JSONDecoder;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.http.client.URL; 

public class Delegate<T> {
	
	private HandlerManager eventBus; 
	private RequestBuilder rb; 
	private boolean isGet;
	private String url; 
	
	public Delegate(HandlerManager eventBus, String url, boolean isGet) {
		this.eventBus = eventBus;
		this.isGet = isGet;
		this.url = url; 
		if (isGet) {
			rb = new RequestBuilder(RequestBuilder.GET, url);
		} else {
			rb = new RequestBuilder(RequestBuilder.POST, url);
		}
		rb.setHeader("Content-Type", "application/x-www-form-urlencoded"); 
	}
	
	private String packParameters(HashMap<String, String> params) {
		StringBuffer result = new StringBuffer();  
		for (Iterator<String> it = params.keySet().iterator(); it.hasNext(); ) {
			String key = it.next(); 
			result.append(URL.encodeComponent(key, true) + "=" + URL.encodeComponent(params.get(key), true));
			if (it.hasNext()) {
				result.append('&'); 
			}
		}
		return result.toString();  		
	}

	public void parseError(AsyncCallback<T> callback, String text) {
		try {
			ErrorResponseDecoder decoder = new ErrorResponseDecoder(); 
			ErrorResponse serviceError = decoder.decode(text);
			if (serviceError.isAuthError()) {
				eventBus.fireEvent(new AuthenticationEvent(AuthenticationEvent.EventType.ERROR));  
			} else {
				eventBus.fireEvent(new ErrorDisplayEvent("[Service Error]" + serviceError.message, serviceError.trace)); 
			}
		} catch (Exception e) { 
			GWT.log("[parseError()]", e);
			/* unexpected format */
			eventBus.fireEvent(new ErrorDisplayEvent("[Service Error] Unknown format in response", 
					"<b>Service URL</b>: " + url + "<br/><b>Content</b>:<br/>" + text)); 
		}
	}
		
	public void sendRequest(final AsyncCallback<T> callback, final JSONDecoder<T> decoder, HashMap<String, String> params) {
		if (params != null) {
			if (isGet) {
				rb = new RequestBuilder(RequestBuilder.GET, url + "?" + packParameters(params)); 
			} else {
				rb.setRequestData(packParameters(params));
			}
		}
		rb.setCallback(new RequestCallback() {
			
			public void onError(Request request, Throwable exception) {
				callback.onFailure(exception); 
			}

			public void onResponseReceived(Request request, Response response) {
				try {
					T result = decoder.decode(response.getText());
					if (result != null) {
						callback.onSuccess(result);
					} else {
						GWT.log("Null result from Decoder: ", new NullPointerException());
						parseError(callback, response.getText());
					}
				} catch (Exception e) {
					GWT.log("Decoder did not parsed correctly", e);
					parseError(callback, response.getText()); 
				}
			}			
		}); 
		try {
			rb.send(); 
		} catch (RequestException e) {
			callback.onFailure(e);  
		}
	}
	
	
}

@@ -1307,17 +1307,45 @@
 coded%22);
- 
+%0A%09%09rb.setTimeoutMillis(2000);
 %0A%09%7D%0A%09%0A%09p

Enable timeout reporting for HTTP requests