package de.sebse.fuplanner.tools.network;

import android.content.Context;
import android.support.annotation.Nullable;

import com.android.volley.AuthFailureError;
import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.TimeoutError;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.Volley;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

import de.sebse.fuplanner.tools.logging.Logger;

/**
 * Created by sebastian on 24.10.17.
 */

public class HTTPService {
    private final RequestQueue requestQueue;
    protected Logger log = new Logger(this);

    protected HTTPService(Context context) {
        this(context, false);
    }

    protected HTTPService(Context context, boolean followRedirects) {
        requestQueue = Volley.newRequestQueue(context, new BetterHurlStack(followRedirects));
    }

    protected void get(String url, @Nullable final HashMap<String, String> cookies, Response.Listener<Result> response, Response.ErrorListener error) {
        HttpRequest request = new HttpRequest(Request.Method.GET, url, response, error) {
            @Override
            public void deliverError(VolleyError error) {
                if (error == null) {
                    super.deliverError(new VolleyError(new NetworkResponse(500, null, null, true, 0)));
                } else if (error.networkResponse == null) {
                    int statusCode;
                    if (error instanceof TimeoutError)
                        statusCode = 408;
                    else
                        statusCode = 500;
                    super.deliverError(new VolleyError(new NetworkResponse(statusCode, null, null, true, error.getNetworkTimeMs())));
                } else {
                    final int status = error.networkResponse.statusCode;
                    if (status == 302) {
                        super.deliverResponse(new Result(null, error.networkResponse.headers));
                    } else {
                        super.deliverError(error);
                    }
                }
            }

            public Map<String, String> getHeaders() throws AuthFailureError {
                Map<String, String> params = super.getHeaders();
                if (cookies != null) {
                    if (params==null)
                        params = new HashMap<>();
                    else
                        params = new HashMap<>(params);
                    StringBuilder newStr = new StringBuilder();
                    for (String key : cookies.keySet())
                        newStr.append(key).append("=").append(cookies.get(key)).append(";");
                    newStr = new StringBuilder(newStr.substring(0, newStr.length() - 1));
                    params.put("Cookie", newStr.toString());
                }

                return params;
            }
        };
        requestQueue.add(request);
    }

    protected void post(String url, @Nullable final HashMap<String, String> cookies, @Nullable final HashMap<String, String> body, Response.Listener<Result> response, Response.ErrorListener error) {
        HttpRequest request = new HttpRequest(Request.Method.POST, url, response, error) {
            @Override
            public String getBodyContentType() {
                return "application/x-www-form-urlencoded";
            }

            @Override
            public byte[] getBody() {
                if (body==null) {
                    return null;
                }
                StringBuilder sb = new StringBuilder();
                for(HashMap.Entry<String, String> e: body.entrySet()){
                    if(sb.length() > 0){
                        sb.append('&');
                    }
                    try {
                        //Log.e("Superissimo", e.getKey()+"|||"+e.getValue());
                        sb.append(URLEncoder.encode(e.getKey(), "UTF-8")).append('=').append(URLEncoder.encode(e.getValue(), "UTF-8"));
                    } catch (UnsupportedEncodingException ignored) {
                    }
                }
                String requestBody = sb.toString();
                try {
                    return requestBody.getBytes("utf-8");
                } catch (UnsupportedEncodingException e) {
                    return null;
                }
            }

            @Override
            public void deliverError(VolleyError error) {
                if (error == null) {
                    super.deliverError(new VolleyError(new NetworkResponse(500, null, null, true, 0)));
                } else if (error.networkResponse == null) {
                    int statusCode;
                    if (error instanceof TimeoutError)
                        statusCode = 408;
                    else
                        statusCode = 500;
                    super.deliverError(new VolleyError(new NetworkResponse(statusCode, null, null, true, error.getNetworkTimeMs())));
                } else {
                    final int status = error.networkResponse.statusCode;
                    if (status == 302) {
                        super.deliverResponse(new Result(null, error.networkResponse.headers));
                    } else {
                        super.deliverError(error);
                    }
                }
            }

            public Map<String, String> getHeaders() throws AuthFailureError {
                Map<String, String> params = super.getHeaders();
                if (cookies != null) {
                    if (params==null)
                        params = new HashMap<>();
                    else
                        params = new HashMap<>(params);
                    StringBuilder newStr = new StringBuilder();
                    for (String key : cookies.keySet())
                        newStr.append(key).append("=").append(cookies.get(key)).append(";");
                    newStr = new StringBuilder(newStr.substring(0, newStr.length() - 1));
                    params.put("Cookie", newStr.toString());
                }

                return params;
            }
        };
        requestQueue.add(request);
    }
}
