package me.nithanim.gw2api.v2.util.rest;

import com.google.gson.JsonSyntaxException;
import java.lang.reflect.Type;
import javax.ws.rs.ProcessingException;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import me.nithanim.gw2api.v2.GuildWars2Api;
import me.nithanim.gw2api.v2.exceptions.GuildWars2ApiIOException;
import me.nithanim.gw2api.v2.exceptions.GuildWars2ApiMappingException;
import me.nithanim.gw2api.v2.exceptions.GuildWars2ApiRequestException;

public class RequestHelperImpl implements RequestHelper {
    private static final MediaType[] DEFAULT_MEDIA_TYPES = new MediaType[] {MediaType.APPLICATION_JSON_TYPE};

    @Override
    public <T> T getRequest(WebTarget wr, Type type) {
        try {
            String json = wr
                .request(DEFAULT_MEDIA_TYPES)
                .header("Cache-Control", "max-age=0")
                .get(String.class);
            return jsonToObject(json, type);
        } catch (ProcessingException | WebApplicationException ex) {
            throw genWebApplicationException(ex);
        }
    }

    @Override
    public <T> T getRequest(WebTarget wr, String apiKey, Class<T> clazz) {
        try {
            String json = wr
                .request(DEFAULT_MEDIA_TYPES)
                .header("Cache-Control", "max-age=0")
                .header("Authorization", "Bearer " + apiKey)
                .get(String.class);
            return jsonToObject(json, clazz);
        } catch (ProcessingException | WebApplicationException ex) {
            throw genWebApplicationException(ex);
        }
    }

    @Override
    public <T> PaginationResult<T> getRequestExtended(WebTarget wr, String apiKey, Class<T> clazz) {
        try {
            Response response = wr
                .request(DEFAULT_MEDIA_TYPES)
                .header("Cache-Control", "max-age=0")
                .header("Authorization", "Bearer " + apiKey)
                .get();
            return new ResultImpl<>(response, clazz);
        } catch (ProcessingException | WebApplicationException ex) {
            throw genWebApplicationException(ex);
        }
    }

    @Override
    public <T> T getRequest(WebTarget wr, Type type, String arg0Name, String arg0Value) {
        try {
            String json = wr
                .queryParam(arg0Name, arg0Value)
                .request(DEFAULT_MEDIA_TYPES)
                .header("Cache-Control", "max-age=0")
                .get(String.class);
            return jsonToObject(json, type);
        } catch (ProcessingException | WebApplicationException ex) {
            throw genWebApplicationException(ex);
        }
    }

    @Override
    public <T> T getRequest(WebTarget wr, String apiKey, Class<T> clazz, String arg0Name, String arg0Value) {
        try {
            String json = wr
                .queryParam(arg0Name, arg0Value)
                .request(DEFAULT_MEDIA_TYPES)
                .header("Cache-Control", "max-age=0")
                .header("Authorization", "Bearer " + apiKey)
                .get(String.class);
            return jsonToObject(json, clazz);
        } catch (ProcessingException | WebApplicationException ex) {
            throw genWebApplicationException(ex);
        }
    }

    @Override
    public <T> PaginationResult<T> getRequestExtended(WebTarget wr, String apiKey, Class<T> clazz, String arg0Name, String arg0Value) {
        try {
            Response response = wr
                .queryParam(arg0Name, arg0Value)
                .request(DEFAULT_MEDIA_TYPES)
                .header("Cache-Control", "max-age=0")
                .header("Authorization", "Bearer " + apiKey)
                .get();
            return new ResultImpl<>(response, clazz);
        } catch (ProcessingException | WebApplicationException ex) {
            throw genWebApplicationException(ex);
        }
    }

    @Override
    public <T> T getRequest(WebTarget wr, Type type, String arg0Name, String arg0Value, String arg1Name, String arg1Value) {
        try {
            String json = wr
                .queryParam(arg0Name, arg0Value)
                .queryParam(arg1Name, arg1Value)
                .request(DEFAULT_MEDIA_TYPES)
                .header("Cache-Control", "max-age=0")
                .get(String.class);
            return jsonToObject(json, type);
        } catch (ProcessingException | WebApplicationException ex) {
            throw genWebApplicationException(ex);
        }
    }

    @Override
    public <T> PaginationResult<T> getRequestExtended(WebTarget wr, String apiKey, Class<T> clazz, String arg0Name, String arg0Value, String arg1Name, String arg1Value) {
        try {
            Response response = wr
                .queryParam(arg0Name, arg0Value)
                .queryParam(arg1Name, arg1Value)
                .request(DEFAULT_MEDIA_TYPES)
                .header("Authorization", "Bearer " + apiKey)
                .get();
            return new ResultImpl<>(response, clazz);
        } catch (ProcessingException | WebApplicationException ex) {
            throw genWebApplicationException(ex);
        }
    }

    private static GuildWars2ApiIOException genWebApplicationException(Exception ex) {
        return new GuildWars2ApiIOException("The server could not handle the request!", ex);
    }

    static <T> T jsonToObject(String json, Type type) {
        try {
            //First try normal mapping
            return GuildWars2Api.GSON.fromJson(json, type);
        } catch (JsonSyntaxException mappingEx) {
            //If that fails...
            try {
                //Check if it is a error response in json format
                JsonApiError jae = GuildWars2Api.GSON.fromJson(json, JsonApiError.class);
                throw new GuildWars2ApiRequestException("The api returned the following json error string: " + jae.getText());
            } catch (JsonSyntaxException droppedEx) {
                //If it was no json error then assume mapping to type failed
                throw new GuildWars2ApiMappingException("Unable to map json to " + type + ": " + json, mappingEx);
            }
        }
    }

    private static class JsonApiError {
        private String text;

        public String getText() {
            return text;
        }
    }

    RequestHelperImpl() {
    }
}

@@ -720,16 +720,94 @@
 N_TYPE%7D;
+%0A    private static final String HEADER_CACHE_CONTROL = %22max-age=0, no-cache%22;
 %0A%0A    @O
@@ -995,35 +995,44 @@
 e-Control%22, 
-%22max-age=0%22
+HEADER_CACHE_CONTROL
 )%0A          
@@ -1453,35 +1453,44 @@
 e-Control%22, 
-%22max-age=0%22
+HEADER_CACHE_CONTROL
 )%0A          
@@ -2005,35 +2005,44 @@
 e-Control%22, 
-%22max-age=0%22
+HEADER_CACHE_CONTROL
 )%0A          
@@ -2585,35 +2585,44 @@
 e-Control%22, 
-%22max-age=0%22
+HEADER_CACHE_CONTROL
 )%0A          
@@ -3127,35 +3127,44 @@
 e-Control%22, 
-%22max-age=0%22
+HEADER_CACHE_CONTROL
 )%0A          
@@ -3763,35 +3763,44 @@
 e-Control%22, 
-%22max-age=0%22
+HEADER_CACHE_CONTROL
 )%0A          
@@ -4434,20 +4434,28 @@
 ol%22,
- %22max-age=0%22
+HEADER_CACHE_CONTROL
 )%0A  
@@ -4993,32 +4993,32 @@
 ame, arg1Value)%0A
-
                 
@@ -5039,32 +5039,95 @@
 LT_MEDIA_TYPES)%0A
+                .header(%22Cache-Control%22, HEADER_CACHE_CONTROL)%0A
                 

Use no-cache http header additionally to max-age #20