class HttpHeaderParser {

    public static Cache.Entry parseCacheHeaders(NetworkResponse response) {
        long now = System.currentTimeMillis();

        Headers headers = response.headers;

        long serverDate = 0;
        long lastModified = 0;
        long serverExpires = 0;
        long softExpire = 0;
        long finalExpire = 0;
        long maxAge = 0;
        long staleWhileRevalidate = 0;
        boolean hasCacheControl = false;
        boolean mustRevalidate = false;

        String serverEtag = null;
        String headerValue;
        List<String> headerValues;

        headerValue = headers.get("Date");
        if (headerValue != null) {
            serverDate = parseDateAsEpoch(headerValue);
        }

        //TODO check multiple cache and make stale if more than 1 value for given directive
        headerValues = headers.values("Cache-Control");
        if (headerValues != null && headerValues.size() > 0) {
            hasCacheControl = true;
            for (int i = 0; i < headerValues.size(); i++) {
                String[] tokens = headerValues.get(i).trim().split(",");
                for (int j = 0; j < tokens.length; j++) {
                    String token = tokens[j].trim();
                    if (token.equals("no-cache") || token.equals("no-store")) {
                        return null;
                    } else if (token.startsWith("max-age=")) {
                        try {
                            maxAge = Long.parseLong(token.substring(8));
                        } catch (Exception e) {
                        }
                    } else if (token.startsWith("stale-while-revalidate=")) {
                        try {
                            staleWhileRevalidate = Long.parseLong(token.substring(23));
                        } catch (Exception e) {
                        }
                    } else if (token.equals("must-revalidate") || token.equals("proxy-revalidate")) {

                        mustRevalidate = true;
                    }
                }
            }
        }

        headerValue = headers.get("Expires");
        if (headerValue != null) {
            serverExpires = parseDateAsEpoch(headerValue);
        }

        headerValue = headers.get("Last-Modified");
        if (headerValue != null) {
            lastModified = parseDateAsEpoch(headerValue);
        }

        serverEtag = headers.get("ETag");

        // Cache-Control takes precedence over an Expires header, even if both exist and Expires
        // is more restrictive.
        if (hasCacheControl) {
            softExpire = now + maxAge * 1000;
            finalExpire = mustRevalidate
                    ? softExpire
                    : softExpire + staleWhileRevalidate * 1000;
        } else if (serverDate > 0 && serverExpires >= serverDate) {
            // Default semantic for Expire header in HTTP specification is softExpire.
            softExpire = now + (serverExpires - serverDate);
            finalExpire = softExpire;
        }

        Cache.Entry entry = new Cache.Entry();
        entry.data = response.data;
        entry.etag = serverEtag;
        entry.softTtl = softExpire;
        entry.ttl = finalExpire;
        entry.serverDate = serverDate;
        entry.lastModified = lastModified;
        entry.responseHeaders = headers;

        return entry;
    }

}

class HttpHeaderParserTest {

    private static long ONE_MINUTE_MILLIS;
    private static long ONE_HOUR_MILLIS;
    private static long ONE_DAY_MILLIS;
    private static long ONE_WEEK_MILLIS;
    private Map<String, String> headers;

    @Test public void parseCacheHeaders_headersSet() {

        headers.put("MyCustomHeader", "42");
        NetworkResponse response = new NetworkResponse(0, new byte[0], Headers.of(headers), 0);
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
        assertNotNull(entry);
        assertNotNull(entry.responseHeaders);
        assertEquals(1, entry.responseHeaders.size());
        assertEquals("42", entry.responseHeaders.get("MyCustomHeader"));
    }

}