package usda.weru.remoteDataAccess;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.swing.SwingWorker;
import usda.weru.util.ConfigData;

/**
 *
 * @author mhaas
 */
abstract public class RdaInputControllerCacheLoader {

    private static final Logger LOGGER = LogManager.getLogger(RdaInputControllerCacheLoader.class);
    protected RdaInputControllerCachingSupport cachingSupport;

    protected long bgPauseLengthLong;
    protected long bgPauseLengthShort;

    protected File baseCacheDir;

    protected RdaInputController rdaControllerCache;
    protected RdaInterface rdaInterface;
    protected String interfaceName;
    SwingWorker<Boolean, Object> bgTask;

    protected boolean skipUpdateTimeCheck;

    public static final String PROP_CSIP_BGFILLCACHE_COMPLETE_INTERNAL = "PropCsipBgFillCacheCompleteInternal";

    public RdaInputControllerCacheLoader(RdaInputController controllerCache, RdaInputControllerCachingSupport support) {
        rdaControllerCache = controllerCache;
        cachingSupport = support;
        interfaceName = null;
        skipUpdateTimeCheck = false;
        bgTask = null;

        baseCacheDir = cachingSupport.getBaseCacheDir();

        bgPauseLengthLong = ConfigData.getLongParm("CD-WS-Cache-BgPauseLong", 0);
        bgPauseLengthShort = ConfigData.getLongParm("CD-WS-Cache-BgPauseShort", 0);

        if (rdaControllerCache != null) {
            rdaInterface = rdaControllerCache.getInterface();
        }
    }

    abstract protected boolean backgroundTraverseCacheFiles(RdaHierarchicalItem dataTree, File idxFile, boolean skip, File skipRefFile);

    public void cacheFilesInBackground(RdaHierarchicalItem dataTree) {
        interfaceName = rdaControllerCache.getInterfaceName();

        bgTask = new SwingWorker<Boolean, Object>() {

            @Override
            public Boolean doInBackground() {
                backgroundProcessCacheFiles(dataTree);
                //publish (new Integer(1), new Integer(2));
                return true;
            }

            @Override
            protected void done() {
                try {
                    Boolean lmodResults = get();
                    LOGGER.log(Level.INFO,
                            "Background load complete: {0} result={1}", new Object[]{interfaceName, lmodResults});

                    rdaControllerCache.getChangeObj().firePropertyChange(PROP_CSIP_BGFILLCACHE_COMPLETE_INTERNAL, true, false);

                    bgTask = null;
                } catch (Exception ignore) {
                }
            }
        };
        bgTask.execute();
    }

    public void setInterfaceName() {
        interfaceName = rdaControllerCache.getInterfaceName();
    }

    public void cancelBackground() {
        if (bgTask != null) {
            bgTask.cancel(true);
        }
    }

    public boolean checkCacheFilesValid(boolean catalogOnly) {
        if (checkIdxFileForSkip()) {
            return true;
        } else if (!catalogOnly) {
            checkAndCleanCacheFiles();
        }
        return false;
    }

    protected File getIdxFile() {
        return new File(baseCacheDir, interfaceName + ".idx");
    }

    protected void backgroundProcessCacheFiles(RdaHierarchicalItem dataTree) {
        boolean skip = true;
        File skipToFile = null;

        File idxFile = getIdxFile();

        if (!skipUpdateTimeCheck) {
            if (checkIdxFileForSkip()) {
                return;
            } else {
                skipToFile = checkIdxFileGetSkipFile(idxFile, interfaceName);
                if (!skipToFile.exists()) {
                    skip = false;
                }
            }
        } else {
            skip = false;
            try {
                idxFile.createNewFile();
            } catch (IOException ex) {
                LOGGER.log(Level.INFO, 
                        "Cache for {0} fail creating idx file: {1}", new Object[]{interfaceName, idxFile.getAbsolutePath()});
            }

        }
        backgroundTraverseCacheFiles(dataTree, idxFile, skip, skipToFile);
        writeIdxComplete(idxFile, interfaceName);
    }

//    protected void writeIdxFile (File idxFile, String str) throws IOException {
//        FileWriter writer = new FileWriter (idxFile);
//        writer.write(str);
//        writer.close();
//    }
    protected void appendIdxFile(File idxFile, String str) throws IOException {
        try (FileWriter writer = new FileWriter(idxFile, true)) {
            writer.append(str);
        }
    }

    protected String readIdxFile(File idxFile) throws IOException {
        char[] line;
        int len;
        try (FileReader reader = new FileReader(idxFile)) {
            line = new char[255];
            len = reader.read(line, 0, 255);
        }
        return new String(line, 0, len);
    }

    protected boolean checkIdxFileForSkip() {
        File idxFile = getIdxFile();

        if (idxFile.exists()) {
            try {
                String fileDateStr = readIdxFile(idxFile);
                if (fileDateStr.startsWith("Complete:")) {
                    LOGGER.log(Level.INFO, 
                            "Background load {0} last update:{1}", new Object[]{interfaceName, fileDateStr.substring(9, 19)});
                    return checkIdxFileDate(fileDateStr.substring(9, 19));
                }
            } catch (IOException ex) {
            }
        }
        return false;
    }

    protected boolean checkIdxFileDate(String fileDateStr) {
        LocalDate lastUpdate = LocalDate.parse(fileDateStr);
        long elapsedDays = ChronoUnit.DAYS.between(lastUpdate, LocalDate.now());

        return (elapsedDays < ConfigData.getLongParm("CD-WS-Cache-CsipUpdateFreq", 1000000000));
    }

    protected File checkIdxFileGetSkipFile(File idxFile, String serviceName) {
        if (idxFile.exists()) {
            try {
                File f = new File(readIdxFile(idxFile));
                if (f.getName().startsWith("Complete:")) {
                    f = new File("");
                }
                LOGGER.log(Level.INFO, 
                        "Cache {0} skipping to file: {1}", new Object[]{serviceName, f.getAbsolutePath()});
                return f;
            } catch (IOException ex) {
            }
        }
        return new File("");
    }

    protected void writeIdxComplete(File idxFile, String serviceName) {
        try {
            appendIdxFile(idxFile, "Complete:" + LocalDate.now().toString());
        } catch (IOException ex) {
            LOGGER.log(Level.INFO, 
                    "Cache {0} fail updating idx file: {1}", new Object[]{serviceName, idxFile.getAbsolutePath()});
        }
    }

    protected void checkAndCleanCacheFiles() {
        File idxFile = getIdxFile();
        if (!idxFile.exists()) {
            String catFilename = idxFile.getName();
            catFilename = catFilename.replace(".idx", ".catalog");
            File catFile = new File(idxFile.getParent(), catFilename);
            catFile.delete();
        }

    }
}
