/*
 * Copyright 2021 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.tomcat.vestige.installer;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.regex.Pattern;

import org.apache.commons.io.FileUtils;

/**
 * @author Gael Lalire
 */
public final class InstallerUtils {
    
    public static Pattern textFilePattern = Pattern.compile(".*\\.(?:css|html|java|json|jsp|jspf|jspx|properties|tag|tld|txt|xhtml|xml|xsd|xsl)");

    private InstallerUtils() {
    }

    public static boolean isText(String name) {
        return textFilePattern.matcher(name).matches();
    }

    public static void addFiles(Class<?> clazz, FileAdder fileAdder) throws IOException {
        addFiles(clazz, "files.txt", fileAdder);
    }
    
    public static void addFiles(Class<?> clazz, String filesResourceName, FileAdder fileAdder) throws IOException {
        addFiles(clazz, null, filesResourceName, fileAdder);
    }


    public static void addFiles(Class<?> clazz, String resourcePrefix, String filesResourceName, FileAdder fileAdder) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(clazz.getResourceAsStream(filesResourceName), "UTF-8"));
        String line = bufferedReader.readLine();
        while (line != null) {
            if (resourcePrefix != null && resourcePrefix.length() != 0) {
                addFile(clazz, resourcePrefix + line, line, fileAdder);
            } else {
                addFile(clazz, line, line, fileAdder);
            }
            line = bufferedReader.readLine();
        }
    }

    public static void addFile(Class<?> clazz, String name, String destName, FileAdder fileAdder) throws IOException {
        String pathFromBase = destName.replace('/', File.separatorChar);
        fileAdder.addFile(pathFromBase, clazz.getResource(name), isText(name));
    }
        
    public static void cleanDirectory(File updateDirectory) {
        for (File file : FileUtils.listFiles(updateDirectory, new String[] {"tmp", "tmpdel", "tmpnew", "tmprep"}, true)) {
            file.delete();
        }
    }

    public static void commitDirectory(File realDirectory, File updateDirectory) {
        // tmp -> if real base exists, then create a .new, if not move it in real base
        // tmprep -> will remove the real base, and will be remove afterwards
        // tmpdel -> will remove the real base, and will be remove afterwards
        // tmpnew -> will remove the current new if exists, rename to new
        for (File subFile : updateDirectory.listFiles()) {
            if (subFile.isDirectory()) {
                commitDirectory(new File(realDirectory, subFile.getName()), subFile);
                continue;
            }
            String name = subFile.getName();
            if (name.endsWith(".tmp")) {
                File realFile = new File(realDirectory, name.substring(0, name.length() - ".tmp".length()));
                if (realFile.exists()) {
                    File currentNew = new File(updateDirectory, name.substring(0, name.length() - ".tmp".length()).concat(".new"));
                    currentNew.delete();
                    subFile.renameTo(currentNew);
                } else {
                    subFile.renameTo(realFile);
                }
            } else if (name.endsWith(".tmprep")) {
                File realFile = new File(realDirectory, name.substring(0, name.length() - ".tmprep".length()));
                realFile.delete();
                subFile.renameTo(realFile);
            } else if (name.endsWith(".tmpdel")) {
                File realFile = new File(realDirectory, name.substring(0, name.length() - ".tmpdel".length()));
                realFile.delete();
                subFile.delete();
            } else if (name.endsWith(".tmpnew")) {
                File currentNew = new File(updateDirectory, name.substring(0, name.length() - ".tmpnew".length()).concat(".new"));
                currentNew.delete();
                subFile.renameTo(currentNew);
            }
        }
    }


    public static boolean removeEmptyDirectories(File file) throws IOException {
        boolean empty = true;
        for (File subFile : file.listFiles()) {
            if (subFile.isDirectory()) {
                if (!removeEmptyDirectories(subFile)) {
                    empty = false;
                }
            } else if (subFile.getName().endsWith(".new")) {
                empty = false;
            }
        }
        if (empty) {
            FileUtils.deleteDirectory(file);
        }
        return empty;
    }

}
