/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
package com.scytl.products.ov.utils;

import org.apache.commons.io.IOUtils;

import com.scytl.products.ov.config.exceptions.specific.ConfigFileUtilsException;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParseException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 *  A utility class for file management.
 */
public class ConfigFileUtils {

    private final TimestampGenerator _timestampGenerator = new TimestampGenerator();

    public File saveTimestampedFile(final File sourceFile, final String outputFolder) throws IOException {

       try(FileInputStream in = new FileInputStream(sourceFile)) {
          return saveTimestampedFileFromInputStream(in, outputFolder, sourceFile.getName());
       }
    }

    public File saveTimestampedFileFromInputStream(final InputStream inputStream, final String outputFolder,
            final String fileName) throws IOException {

        final String timeStamp = _timestampGenerator.getNewTimeStamp();

        final String candidatePath = outputFolder + File.separator + timeStamp;

        final String finalPath = createTimestampedPath(candidatePath, new BigInteger(timeStamp), outputFolder);

        return saveFile(finalPath + File.separator + fileName, inputStream);
    }

    /**
     * Creates the directory specified by {@code outputFolder}, and returns the
     * full path of the created directory.
     *
     * @param outputFolder the path of the directory to be created (relative to the
     *                     current working directory).
     * @return the full path of the created directory.
     * @throws IOException if there are any problems when attempting to create the
     *                     directory.
     */
    public Path createTimestampedDirectory(final String outputFolder) throws IOException {

        final String timeStamp = _timestampGenerator.getNewTimeStamp();

        final Path absolutePath = Paths.get(outputFolder, timeStamp).toAbsolutePath();

        Files.createDirectories(absolutePath);

        return absolutePath;
    }

    /**
     * Return the last folder following timestampGenerator pattern created on a
     * parent folder.
     *
     * @param parentFolder the folder with all the timestamped folders
     * @return the last folder timestamped created
     * @throws ParseException
     */
    public File getLastFolderTimestamp(final File parentFolder) throws ParseException {

        final List<LocalDateTime> timestamps = new ArrayList<>();

        for (final File timestampFolder : parentFolder.listFiles()) {

            final LocalDateTime parsedFromPatern = LocalDateTime.parse(timestampFolder.getName(),
                    _timestampGenerator.getDateFormat());

            timestamps.add(parsedFromPatern);
        }

        if (timestamps.isEmpty()) {
            throw new ConfigFileUtilsException("Folder empty: no timestamps on " + parentFolder.getAbsolutePath());
        }

        final String lastTimeStamp = getLastTimestamp(timestamps);

        return new File(parentFolder, lastTimeStamp);
    }

    /**
     * Saves a inputStream in the file system.
     *
     * @param inputStream the file content to be stored in the file system
     * @param path        Absolute path (including file name) to be created
     * @throws java.io.IOException
     */
    public synchronized File saveFile(final String path, final InputStream inputStream) throws IOException {

        final File file = new File(path);
		if (!file.exists() && !file.createNewFile()) {
			throw new ConfigFileUtilsException("An error occurred while creating the file " + file.toString());
		}

        try (FileOutputStream fop = new FileOutputStream(file)) {
            IOUtils.copy(inputStream, fop);
        }

        return file;
    }

    public synchronized String createTimestampedPath(String path, BigInteger timestamp,
            final String destinationFolder) {

    	BigInteger timestampInc = timestamp;
    	String timestampedPath = path; 
    	while (!(new File(timestampedPath)).mkdirs()) {

    		timestampInc = timestampInc.add(BigInteger.ONE);
    		timestampedPath = destinationFolder + File.separator + timestampInc;

        }

        return timestampedPath;
    }

    public String getTempFolder() {
        return System.getProperty("java.io.tmpdir");
    }

    private String getLastTimestamp(final List<LocalDateTime> dates) {

        final LocalDateTime moreRecentDate = Collections.max(dates);

        return _timestampGenerator.getDateFormat()
                .format(moreRecentDate);
    }

    public static File[] listOnlyFiles(final Path directory) {
        return directory.toFile().listFiles(File::isFile);
    }
}
