package com.pnunes.sabproxy;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.LineIterator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class AdServers {
    private final Logger log = LoggerFactory.getLogger(this.getClass());

    public static String AD_SERVERS_FILE = "adservers.txt";
    public static int AD_SERVERS_FILE_VALID_DAYS = 1;
    private static String AD_SERVERS_SOURCE_URL = "https://raw.githubusercontent.com/StevenBlack/hosts/master/alternates/fakenews-gambling/hosts";

    private String DOMAIN_PATTERN = "^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{2,6}$";
    private Pattern domainPattern = Pattern.compile(DOMAIN_PATTERN);

    private List<String> adServers = new ArrayList<String>();
    private int sessionRequests = 0;
    private int sessionBlockedAds = 0;
    private HitCounter hitCounter = new HitCounter();

    public AdServers() {
        adServers = new ArrayList<String>();

        Utils.initializeUserSettings();
        updateAdServersList(false);
        loadListFromHostsFileFormat(getAdServersListFile());
    }

    public int numberOfLoadedAdServers() {
        return adServers.size();
    }

    public boolean contains(String domain) {
        sessionRequests++;
        if (domain == null || domain.equals("")) {
            return false;
        } else if (adServers.contains(domain)) {
            sessionBlockedAds++;
            hitCounter.addHit(domain);
            return true;
        }

        return false;
    }

    public int getSessionBlockedAds() {
        return sessionBlockedAds;
    }

    public int getSessionRequests() {
        return sessionRequests;
    }

    public Map<String, Integer> getBlockedDomainsHits() {
        return hitCounter.getTopHits();
    }

    public void loadListFromHostsFileFormat(String adServersHostFile) {
        adServers = new ArrayList<String>();
        LineIterator it = null;
        log.info("Loading Ad Server list from: " + adServersHostFile);
        try {
            it = FileUtils.lineIterator(new File(adServersHostFile), "UTF-8");

            while (it.hasNext()) {
                String line = it.nextLine();

                if (!getAdServerFromHostsLine(line).equals("")) {
                    adServers.add(getAdServerFromHostsLine(line));
                }
            }
            log.info("Loaded " + adServers.size() + " ad servers.");
        } catch (Exception e) {
            log.error("Failed to load ad servers from file " + adServersHostFile + ". " + e.getMessage());
        } finally {
            LineIterator.closeQuietly(it);
        }
    }


    private String getAdServerFromHostsLine(String line) {
        if (line.startsWith("#") || line.isEmpty()) {
            return "";
        }

        // remove IPV4 from string
        String noIPLine = line.replaceAll("(\\d+.){3}\\d+", "").trim();

        if (domainPattern.matcher(noIPLine).find()) {
            Matcher matcher = domainPattern.matcher(noIPLine);
            while (matcher.find()) {
                return matcher.group();
            }
        }

        return "";
    }

    public String getAdServersListFile() {
        return Utils.getAppSettingFolder() + "/" + AD_SERVERS_FILE;
    }

    public void updateAdServersList(boolean forceUpdate) {
        log.info("Trying to update ad servers list...");

        // check if file exists
        File adServersHostFile = new File(getAdServersListFile());
        if (adServersHostFile.exists()) {
            // check if its older than x days
            long timeDiff = new Date().getTime() - adServersHostFile.lastModified();
            if (timeDiff > AD_SERVERS_FILE_VALID_DAYS * 24 * 60 * 60 * 1000 || forceUpdate) { // update file only if older than AD_SERVERS_FILE_VALID_DAYS
                try {
                    FileUtils.copyURLToFile(new URL(AD_SERVERS_SOURCE_URL), new File(getAdServersListFile()));
                } catch (MalformedURLException e) {
                    log.warn("Can't update ads servers list from: " + AD_SERVERS_SOURCE_URL + ". " + e.getMessage());
                } catch (IOException e) {
                    log.warn("Failed to save ads servers list. " + e.getMessage());
                }
                log.info("Ad servers list updated.");
            } else {
                log.info("Ad servers list less than " + AD_SERVERS_FILE_VALID_DAYS + " day(s) old. Not updating.");
            }
        }


    }

}
@@ -482,84 +482,8 @@
  %7B%0D%0A
-    private final Logger log = LoggerFactory.getLogger(this.getClass());%0D%0A%0D%0A
     
@@ -742,16 +742,88 @@
 osts%22;%0D%0A
+    private final Logger log = LoggerFactory.getLogger(this.getClass());
 %0D%0A    pr
@@ -4187,39 +4187,569 @@
             
-try %7B%0D%0A        
+if (downloadAdServersList()) %7B%0D%0A                    log.info(%22Ad servers list successfully updated.%22);%0D%0A                %7D%0D%0A            %7D else %7B%0D%0A                log.info(%22Ad servers list less than %22 + AD_SERVERS_FILE_VALID_DAYS + %22 day(s) old. Not updating.%22);%0D%0A            %7D%0D%0A        %7D else %7B%0D%0A            if (downloadAdServersList()) %7B%0D%0A                log.info(%22Ad servers list successfully updated.%22);%0D%0A            %7D%0D%0A        %7D%0D%0A    %7D%0D%0A%0D%0A    private boolean downloadAdServersList() %7B%0D%0A        boolean downloadSuccess = true;%0D%0A        try %7B%0D%0A
             
@@ -4844,32 +4844,24 @@
 );%0D%0A        
-  
-      
 %7D catch (Mal
@@ -4897,32 +4897,25 @@
         
-        log.warn
+log.error
 (%22Can't 
@@ -5006,23 +5006,53 @@
         
+   downloadSuccess = false;%0D%0A
        
+ 
 %7D catch 
@@ -5086,24 +5086,17 @@
     
-        log.warn
+log.error
 (%22Fa
@@ -5164,244 +5164,87 @@
     
-    %7D%0D%0A                log.info(%22Ad servers list updated.%22);%0D%0A            %7D else %7B%0D%0A                log.info(%22Ad servers list less than %22 + AD_SERVERS_FILE_VALID_DAYS + %22 day(s) old. Not updating.%22);%0D%0A            %7D%0D%0A        %7D%0D%0A%0D%0A%0D%0A    %7D
+downloadSuccess = false;%0D%0A        %7D%0D%0A%0D%0A        return downloadSuccess;%0D%0A    %7D%0D%0A
 %0D%0A%0D%0A

Update ad server list if not exists locally