/* ----------------------------------------
 * Origin  : GFI INFORMATIQUE 
 * Project : CDPP Propagation Tool 
 * ----------------------------------------
 * History 
 * Version : 01/05/2015 : SCA : V2.1
 * Version : 06/04/2023 : LBE : V2.7
 * DM-ID : redmine#8642 : 06/04/2023 : Added 3D shockwave
 * ----------------------------------------
 */
package fr.tlse.irap.server.serviceDAO.utils;

import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;

public abstract class ScanDirectory {

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

    /**
     * Scan the given directory to fetch files belonging to [t1,t2], theses files are named as "*_YYYYMMDD_YYYYYMMDD.*"
     * or as "*_YYYYMMDD.*", suffix is .asc or .txt
     *
     * @param directory
     * @param calendarT1
     * @param calendarT2
     * @return wanted files or null if no matched file.
     */
    public static File[] fetchFiles(final File directory, final Date dateT1, final Date dateT2) {

        // Filter to fetch files belonging to [t1,t2] (endTime>=t1 and startTime<=t2)
        FileFilter timeFileFilter = new FileFilter() {
            public boolean accept(File file) {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
                String strT1 = sdf.format(dateT1);
                String strT2 = sdf.format(dateT2);
                // extract start/end dates from filename as "*_YYYYMMDD_YYYYYMMDD.*" or as "*_YYYYMMDD.*"
                String[] splitResults = file.getName().split("_");
                int lg = splitResults.length;
                String strUnknown = "UNKNOWN";
                String strSTART = strUnknown;
                String strEND = strUnknown;
                // skip directory, hidden file and not expected nomenclature
                if ((file.isFile() && !file.isHidden()) && (file.getName().endsWith(".asc") || file.getName().endsWith(".txt") || file.getName().endsWith(".csv"))) {
                    if (Pattern.matches(".*_\\d{8}_\\d{8}.*", file.getName())) {
                        // extract START/END date from filename
                        strSTART = splitResults[lg - 2];
                        strEND = splitResults[lg - 1].substring(0, Math.min(8, splitResults[lg - 1].length()));
                    } else if (file.isFile() && !file.isHidden() && Pattern.matches(".*_\\d{8}.*", file.getName())) {
                        // case of filename as  "*_YYYYYMMDD.*", i.e. only one date ==> START=END
                        strSTART = splitResults[lg - 1].substring(0, Math.min(8, splitResults[lg - 1].length()));
                        strEND = strSTART;
                    }
                    // check date format
                    try {
                        sdf.parse(strSTART);
                        sdf.parse(strEND);
                    } catch (ParseException e) {
                        strSTART = strUnknown;
                        strEND = strUnknown;
                    }
                    if (strSTART.equals(strUnknown) || strEND.equals(strUnknown)) {
                        logger.warn("Not expected nomenclature for " + file.getName());
                    }
                    // accept if current file belongs to [t1,t2]
                    return (strSTART.compareTo(strT2) <= 0 && strEND.compareTo(strT1) >= 0);
                } else {
                    return false;
                }
            }
        };

        File[] files = directory.listFiles(timeFileFilter);
        if (files != null) {
            Arrays.sort(files);
        }
        return files;
    }

    /**
     * Scan the given directory to fetch files belonging to [t1,t2]
     * @return wanted files or null if no matched file.
     */
    public static File[] fetchDirectories(final File directory, final String pDateFormat, final Date dateT1, final Date dateT2) {

        // Filter to fetch files belonging to [t1,t2] (endTime>=t1 and startTime<=t2)
        FileFilter timeFileFilter = new FileFilter() {
            public boolean accept(File file) {
                SimpleDateFormat sdf = new SimpleDateFormat(pDateFormat);
                String strT1 = sdf.format(dateT1);
                String strT2 = sdf.format(dateT2);
                int lFormatLength = pDateFormat.length();
                // extract start/end dates from filename as "*pDateFormat_pDateFormat.*" or as "*pDateFormat.*"
                String[] splitResults = file.getName().split("_");
                int lg = splitResults.length;
                String strUnknown = "UNKNOWN";
                String strSTART = strUnknown;
                String strEND = strUnknown;
                // skip directory, hidden file and not expected nomenclature
                if ((!file.isFile() && !file.isHidden()) ) {
                    if (Pattern.matches(".*\\d{"+lFormatLength+"}_\\d{"+lFormatLength+"}.*", file.getName())) {
                        // extract START/END date from filename
                        strSTART = splitResults[lg - 2];
                        strEND = splitResults[lg - 1].substring(0, Math.min(lFormatLength, splitResults[lg - 1].length()));
                    } else if (!file.isFile() && !file.isHidden() && Pattern.matches(".*\\d{"+lFormatLength+"}.*", file.getName())) {
                        // case of filename as  "*pDateFormat.*", i.e. only one date ==> START=END
                        strSTART = splitResults[lg - 1].substring(0, Math.min(lFormatLength, splitResults[lg - 1].length()));
                        strEND = strSTART;
                    }
                    // check date format
                    try {
                        sdf.parse(strSTART);
                        sdf.parse(strEND);
                    } catch (ParseException e) {
                        strSTART = strUnknown;
                        strEND = strUnknown;
                    }
                    if (strSTART.equals(strUnknown) || strEND.equals(strUnknown)) {
                        logger.warn("Not expected nomenclature for " + file.getName());
                    }
                    // accept if current file belongs to [t1,t2]
                    return (strSTART.compareTo(strT2) <= 0 && strEND.compareTo(strT1) >= 0);
                } else {
                    return false;
                }
            }
        };

        File[] files = directory.listFiles(timeFileFilter);
        if (files != null) {
            Arrays.sort(files);
        }
        return files;
    }

    /**
     * Scan the given directory to fetch files with name containing the given expression.
     *
     * @param directory
     * @param expression
     * @param suffix
     * @return wanted files or null if no matched file.
     */
    public static File[] fetchMatchingFiles(File directory, final String expression, final String suffix) {

        // Filter the list of returned files, return files that contain the given expression
        FilenameFilter filter = new FilenameFilter() {
            public boolean accept(File dir, String name) {
                return name.contains(expression) && name.endsWith(suffix);
            }
        };
        File[] files = directory.listFiles(filter);
        if (files != null) {
            Arrays.sort(files);
        }
        return files;
    }

}
