/* BdfServer - Copyright (c) 2022 Vincent Calame - Exemole
 * Logiciel libre donné sous triple licence :
 * 1) selon les termes de la CeCILL V2
 * 2) selon les termes de l’EUPL V.1.1
 * 3) selon les termes de la GNU GPLv3
 * Voir le fichier licences.txt
 */


package fr.exemole.bdfserver.tools.diagnostic.urlscan;

import fr.exemole.bdfserver.api.BdfServer;
import fr.exemole.bdfserver.api.storage.BdfStorageException;
import fr.exemole.bdfserver.api.storage.StorageRoot;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import net.mapeadores.util.http.UrlStatus;
import net.mapeadores.util.http.UrlStatusPrimitives;
import net.mapeadores.util.primitives.io.PrimitivesIOFactory;
import net.mapeadores.util.primitives.io.PrimitivesReader;
import net.mapeadores.util.primitives.io.PrimitivesWriter;
import net.mapeadores.util.text.RelativePath;


/**
 *
 * @author Vincent Calame
 */
public class UrlReportCache {

    private final static long CACHE_DURATION = 1000 * 60 * 60 * 24 * 15;
    private final static long ONE_DAY_CACHE_DURATION = 1000 * 60 * 60 * 24;
    private final static RelativePath DIR_PATH = RelativePath.build("urlstatus");
    private final BdfServer bdfServer;
    private final StorageRoot cacheStorage;
    private final File cacheDir;
    private final StorageRoot.Lock lock;

    public UrlReportCache(BdfServer bdfServer) {
        this.bdfServer = bdfServer;
        this.cacheStorage = bdfServer.getCacheStorage();
        this.cacheDir = cacheStorage.getFile(DIR_PATH);
        this.lock = cacheStorage.getLock(DIR_PATH);
        cacheDir.mkdirs();
    }

    public void cache(Collection<UrlReport> reports, boolean append) {
        File file = getCacheFile();
        synchronized (lock) {
            try (BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(file, append))) {
                PrimitivesWriter dataPrimitivesWriter = PrimitivesIOFactory.newWriter(os);
                for (UrlReport report : reports) {
                    dataPrimitivesWriter.writeString(report.getUrl());
                    dataPrimitivesWriter.writeLong(report.getTime());
                    UrlStatusPrimitives.writeUrlStatus(report.getUrlStatus(), dataPrimitivesWriter);
                }
            } catch (IOException ioe) {
                throw new BdfStorageException(ioe);
            }
        }
    }

    public Map<String, UrlReport> read() {
        Map<String, UrlReport> map = new HashMap<String, UrlReport>();
        File file = getCacheFile();
        if (!file.exists()) {
            return map;
        }
        synchronized (lock) {
            long currentTime = System.currentTimeMillis();
            try (BufferedInputStream is = new BufferedInputStream(new FileInputStream(file))) {
                PrimitivesReader primitivesReader = PrimitivesIOFactory.newReader(is);
                while (true) {
                    String url = primitivesReader.readString();
                    long time = primitivesReader.readLong();
                    UrlStatus urlStatus = UrlStatusPrimitives.readUrlStatus(primitivesReader);
                    if (isStillValid(urlStatus, time, currentTime)) {
                        map.put(url, new UrlReport(url, urlStatus, time));
                    }
                }
            } catch (EOFException eof) {

            } catch (IOException ioe) {
                throw new BdfStorageException(ioe);
            }
        }
        return map;
    }

    private File getCacheFile() {
        return new File(cacheDir, "urlstatus.primitives");
    }

    private static boolean isStillValid(UrlStatus urlStatus, long time, long currentTime) {
        long cacheDuration = getCacheDuration(urlStatus);
        return (currentTime - time) < CACHE_DURATION;
    }

    private static long getCacheDuration(UrlStatus urlStatus) {
        if (urlStatus.hasResponse()) {
            if (urlStatus.getResponseCode() >= 500) {
                return ONE_DAY_CACHE_DURATION;
            }
        }
        return CACHE_DURATION;
    }


}
