package org.atea.nlptools.macroniser.util;

import com.glaforge.i18n.io.CharsetToolkit;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.UUID;

/**
 * @author University of Waikato - Te Whare Wānanga o Waikato
 * @version 1.0
 * @since   2014-11-20 
 */
public class FileUtil
{
    public static final String TMP_FILE_PREFIX = "mi-tmp-";

    /**
     * Find the file type of a file. This is based of the file suffix eg(.txt) 
     * @param File file to find out the file type of. 
     * @return String file type. 
     */
    public static String guessFileType(File file)
    {
        int dotPos = file.getName().lastIndexOf(".");
        return dotPos != -1 ? file.getName().substring(dotPos) : null;
    }

    /**
     * Find the file charset encoding that a file used. 
     * @param File file to find out what charset encoding has been used. 
     * @return String file charset. 
     */
    public static String guessCharsetEncoding(File file)
    {
        String charsetEncoding = null;
        try {
            charsetEncoding = CharsetToolkit.guessEncoding(file, 4096).name().toLowerCase();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return charsetEncoding;
    }
    
    /**
     * Converts the character set of a text file.
     * @param fileIn
     * @param charSetIn
     * @param fileOut
     * @param charSetOut
     * @return
     */
    public static boolean convertCharSet(File fileIn, String charSetIn, File fileOut, String charSetOut)
    {
        BufferedReader reader = null;
        BufferedWriter writer = null;

        try
        {
            reader = new BufferedReader(new InputStreamReader(new FileInputStream(fileIn), charSetIn));
            writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileOut), charSetOut));
            String line;
            while ((line = reader.readLine()) != null) {
                writer.write(line);
                writer.newLine();
            }
            return true;
        }
        catch (IOException e)
        {
            e.printStackTrace();
            return false;
        }
        finally
        {
            IOUtil.safeClose(reader);
            IOUtil.safeClose(writer);
        }
    }

    /**
     * Deletes a file
     * @param File The file to be deleted.
     * @return A boolean value indicating whether or not the file was deleted. 
     */
    public static boolean deleteFile(File file)
    {
        if (file == null || !file.exists())
        {
            return false;
        }
        else if (file.isFile())
        {
            return file.delete();
        }
        else
        {
            File[] listFiles = file.listFiles();
            for (File listFile : listFiles) {
                deleteFile(listFile);
            }

            return file.delete();
        }
    }

    /**
     * Check to see if a file exists and is valid
     * @param File file path to be tested. Will throw error if the file dose not exists or is not valid.
     * @throws IllegalArgumentException if the file is == null
     * @throws IllegalArgumentException if the file dose not exists 
     * @throws IllegalArgumentException if the file is not a file
     */
    public static void checkValidFile(final File file)
    {
        if (file == null) {
            throw new IllegalArgumentException("The file '" + file + "' is null!");
        }
        else if (!file.exists()) {
            throw new IllegalArgumentException("The file '" + file + "' does not exist!");
        }
        else if (!file.isFile()) {
            throw new IllegalArgumentException("The name '" + file + "' is not a file!");
        }
    }

    /**
     * Check to see if a directory exists and is valid
     * @param File directory path to be tested. Will throw error if the directory dose not exists or is not valid.\
     * @throws IllegalArgumentException if the directory is null
     * @throws IllegalArgumentException if the directory does not exists 
     * @throws IllegalArgumentException if the directory is not a directory
     */
    public static void checkValidDir(final File dir)
    {
        if (dir == null) {
            throw new IllegalArgumentException("The directory '" + dir + "' is null!");
        }
        else if (!dir.exists()) {
            throw new IllegalArgumentException("The directory '" + dir + "' does not exist!");
        }
        else if (!dir.isDirectory()) {
            throw new IllegalArgumentException("The name '" + dir + "' is not a directory!");
        }
    }
    
    /**
     * Attempts to create a random directory.
     * @param rootLocation The location under which to make the directory.
     * @return The {@link File} object denoting the random directory.
     * @throws IOException If the directory could not be created.
     */
    public static File createRandomDirectory(File rootLocation)
        throws IOException
    {
        final int maxAttempts = 10;
        int attempt = 0;

        do
        {
            String random = UUID.randomUUID().toString();
            File dir = new File(rootLocation + File.separator + FileUtil.TMP_FILE_PREFIX + random);

            if (!dir.exists() && dir.mkdir()) {
                return dir;
            }
        }
        while (++attempt < maxAttempts);

        throw new IOException("Could not create temp directory.");
    }
}
