package com.gh.gamecenter.volley.extended;

import android.text.TextUtils;

import com.android.volley.AuthFailureError;
import com.android.volley.DefaultRetryPolicy;
import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.toolbox.HttpHeaderParser;
import com.gh.common.util.GzipUtils;
import com.gh.common.util.Utils;

import org.apache.http.HttpStatus;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

/**
 * 
 * @author 温冠超
 * @email 294299195@qq.com
 * @date 2015-7-31
 * @param <T>
 */
public abstract class ExtendedRequest<T> extends Request<T> {

	private static final String HEADER_ENCODING = "Content-Encoding";
	private static final String HEADER_USER_AGENT = "User-Agent";
	private static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding";
	private static final String ENCODING_GZIP = "gzip";
	private static final int TIMEOUT = 5 * 1000;

	protected Map<String, String> mParams;
	protected Map<String, String> mHeaders;

	private String mUserAgent;
	private boolean mGzipEnabled = true;

	protected final Response.Listener<T> mSuccessListener;

	public ExtendedRequest(int method,
						   String url,
						   Response.Listener<T> successListener,
						   Response.ErrorListener errorListener) {
		super(method, url, errorListener);
		setTimeout(TIMEOUT);
		mSuccessListener = successListener;
	}

	@Override
	protected void deliverResponse(T response) {
		if (mSuccessListener != null) {
			mSuccessListener.onResponse(response);
		}
	}

	@Override
	abstract protected Response<T> parseNetworkResponse(NetworkResponse response);

	protected String getResponseString(NetworkResponse response) throws UnsupportedEncodingException {
		String responseString = null;
		String charset = HttpHeaderParser.parseCharset(response.headers);

		if (HttpStatus.SC_NOT_MODIFIED == response.statusCode
				|| (mGzipEnabled && isGzipped(response.headers))
				|| HttpStatus.SC_OK == response.statusCode) {
			try {
				byte[] data = GzipUtils.decompressBytes(response.data);
				responseString = new String(data, charset);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		if (responseString == null) {
			responseString = new String(response.data, charset);
		}

		return responseString;
	}

	private boolean isGzipped(Map<String, String> headers) {
		return headers != null
				&& !headers.isEmpty()
				&& headers.containsKey(HEADER_ENCODING)
				&& headers.get(HEADER_ENCODING).equalsIgnoreCase(ENCODING_GZIP);
	}

	/**
	 * Sets parameters map
	 * 
	 * @param params Parameters map
	 */
	public void setParams(Map<String, String> params) {
		mParams = params;
	}

	/**
	 * Adds POST parameter
	 * 
	 * @param key Parameter name
	 * @param value Parameter value
	 */
	public void addParam(String key, String value) {
		if (mParams == null) {
			mParams = new HashMap<String, String>();
		}
		mParams.put(key, value);
	}
	
	public void addHeader(String key, String value) {
		if (mHeaders == null) {
			mHeaders = new HashMap<String, String>();
		}
		mHeaders.put(key, value);
	}

	@Override
	protected Map<String, String> getParams() throws AuthFailureError {
		return mParams;
	}

	@Override
	public Map<String, String> getHeaders() throws AuthFailureError {
		if (mHeaders == null) {
			mHeaders = new HashMap<String, String>();
		}

		// add user agent header
		if (TextUtils.isEmpty(mUserAgent)) {
			mHeaders.put(HEADER_USER_AGENT, mUserAgent);
		}

		// add gzip header
		if (mGzipEnabled) {
			mHeaders.put(HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
			Utils.log(ExtendedRequest.class.getSimpleName(),
					"using gzip-------------------");
		} else {
			Utils.log(ExtendedRequest.class.getSimpleName(),
					"not use gzip-------------------");
		}

		return mHeaders;
	}

	/**
	 * Sets user agent to specify in request header
	 * 
	 * @param userAgent
	 *            User agent string
	 */
	public void setUserAgent(String userAgent) {
		mUserAgent = userAgent;
	}

	/** Disables GZIP compressing (enabled by default) */
	public void disableGzip() {
		mGzipEnabled = false;
	}

	public boolean isSetGzip() {
		return mGzipEnabled;
	}

	/**
	 * Sets request timeout
	 * 
	 * @param timeout Timeout in seconds
	 */
	public void setTimeout(int timeout) {
		setRetryPolicy(new DefaultRetryPolicy(timeout,
				DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
				DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
	}
}