package edu.tamu.weaver.auth.whitelist;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Iterator;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component("whitelist")
public class Whitelist {

    private static final Logger logger = LoggerFactory.getLogger(Whitelist.class);

    private static final String HEADER_X_REAL_IP = "x-real-ip";

    private static final String HEADER_X_FORWARDED_FOR = "x-forwarded-for";

    @Value("${app.whitelist:127.0.0.1}")
    private String[] whitelist;

    @PostConstruct
    public void info() {
        logger.info("Component whitelist initialized");
    }

    public boolean isAllowed(HttpServletRequest req) throws UnknownHostException {
        String ip = req.getRemoteAddr();
        logger.info("Request ip: " + ip);

        String realIp = req.getHeader(HEADER_X_REAL_IP);
        logger.info("Request real ip: " + realIp);

        String forwardForIps = req.getHeader(HEADER_X_FORWARDED_FOR);
        logger.info("Request forwarded for ip: " + forwardForIps);

        Enumeration<String> headerNames = req.getHeaderNames();
        if (headerNames != null) {
            while (headerNames.hasMoreElements()) {
                String headerName = headerNames.nextElement();
                String headerValue = req.getHeader(headerName);
                logger.info(headerName + ": " + headerValue);
            }
        }

        boolean allowed = false;

        for (String entry : whitelist) {
            if (ip != null && entry.trim().equals(ip.trim())) {
                logger.info("Allowing whitelist ip " + entry + " for " + req.getRequestURI());
                allowed = true;
                break;
            }
            if (realIp != null && entry.trim().equals(realIp.trim())) {
                logger.info("Allowing whitelist real ip " + realIp + " for " + req.getRequestURI());
                allowed = true;
                break;
            }
            if (forwardForIps != null && forwardForIps.contains(entry.trim())) {
                logger.info("Allowing whitelist forwarded for ips " + forwardForIps + " for " + req.getRequestURI());
                allowed = true;
                break;
            }
        }

        String realHost = null;
        String forwardForHosts = null;

        if (!allowed) {
            if (realIp != null) {
                realHost = getHostFromIp(realIp);
                if (realHost != null) {
                    logger.info("Request real host: " + realHost);
                }
            }

            for (String entry : whitelist) {
                if (realHost != null && entry.trim().equals(realHost.trim())) {
                    logger.info("Allowing whitelist real host " + realHost + " for " + req.getRequestURI());
                    allowed = true;
                    break;
                }
            }
        }

        if (!allowed) {
            if (forwardForIps != null) {
                forwardForHosts = getForwardedForHosts(forwardForIps);
            }

            for (String entry : whitelist) {
                if (forwardForHosts != null && forwardForHosts.contains(entry.trim())) {
                    logger.info("Allowing whitelist forwarded for hosts " + forwardForHosts + " for " + req.getRequestURI());
                    allowed = true;
                    break;
                }
            }
        }

        if (!allowed) {
            logger.warn("Disallowing request for " + req.getRequestURI());
            if (ip != null) {
                logger.warn("  ip: " + ip);
            }
            if (realIp != null) {
                logger.warn("  real ip: " + realIp);
            }
            if (forwardForIps != null) {
                logger.warn("  forwarded for IPs: " + forwardForIps);
            }
            if (realHost != null) {
                logger.warn("  real host: " + realHost);
            }
            if (forwardForIps != null) {
                logger.warn("  forwarded for IPs: " + forwardForIps);
            }
        }
        return allowed;
    }

    private String getHostFromIp(String ip) {
        try {
            InetAddress addr = InetAddress.getByName(ip);
            return addr.getHostName();
        } catch (UnknownHostException e) {
            logger.warn("Unknown host for ip: " + ip);
        }
        return null;
    }

    private String getForwardedForHosts(String forwardForIps) {
        String forwardForHosts = "";
        Iterator<String> forwardForIpsIterator = Arrays.stream(forwardForIps.split(",")).iterator();
        while (forwardForIpsIterator.hasNext()) {
            String forwardForHost = getHostFromIp(forwardForIpsIterator.next());
            if (forwardForHost != null) {
                forwardForHosts += forwardForHost;
                if (forwardForIpsIterator.hasNext()) {
                    forwardForHosts += ",";
                }
            }
        }
        if (forwardForHosts.isEmpty()) {
            return null;
        } else {
            logger.info("Request forwarded for hosts: " + forwardForHosts);
            return forwardForHosts;
        }
    }

}

@@ -130,38 +130,8 @@
 ys;%0A
-import java.util.Enumeration;%0A
 impo
@@ -153,16 +153,16 @@
 erator;%0A
+
 %0Aimport 
@@ -815,20 +815,21 @@
  logger.
-info
+debug
 (%22Compon
@@ -995,36 +995,37 @@
 %0A        logger.
-info
+debug
 (%22Request ip: %22 
@@ -1096,36 +1096,37 @@
 %0A        logger.
-info
+debug
 (%22Request real i
@@ -1219,36 +1219,37 @@
 %0A        logger.
-info
+debug
 (%22Request forwar
@@ -1285,373 +1285,8 @@
 );%0A%0A
-        Enumeration%3CString%3E headerNames = req.getHeaderNames();%0A        if (headerNames != null) %7B%0A            while (headerNames.hasMoreElements()) %7B%0A                String headerName = headerNames.nextElement();%0A                String headerValue = req.getHeader(headerName);%0A                logger.info(headerName + %22: %22 + headerValue);%0A            %7D%0A        %7D%0A%0A
     
@@ -1435,36 +1435,37 @@
          logger.
-info
+debug
 (%22Allowing white
@@ -1672,36 +1672,37 @@
          logger.
-info
+debug
 (%22Allowing white
@@ -1924,36 +1924,37 @@
          logger.
-info
+debug
 (%22Allowing white
@@ -2347,36 +2347,37 @@
          logger.
-info
+debug
 (%22Request real h
@@ -2573,36 +2573,37 @@
          logger.
-info
+debug
 (%22Allowing white
@@ -3082,20 +3082,21 @@
  logger.
-info
+debug
 (%22Allowi

update logging and removed debugging code