FileUtil.java

package com.sintia.ffl.admin.optique.catalogue.util;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.sintia.ffl.admin.optique.catalogue.models.Catalog;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.io.FileSystemResource;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Component
@Lazy
@JsonInclude(JsonInclude.Include.NON_NULL)
@Slf4j
public class FileUtil {

	public static final String FILE_DOESN_T_EXIST_ERRM = "The file '{}' doesn't exist and so can't be set in a Catalog dto.";
	public static final String THE_FILE = "The file '";
	public static final String DOESN_T_EXIST = "' doesn't exist";

	@Value("${archives.directory}")
	private String archiveRepo;

	@Value("${catalog.associations.name.pattern}")
	private String	associationsFileNamePattern;
	@Value("${catalog.glasses.name.pattern}")
	private String	glassesFileNamePattern;
	@Value("${catalog.extras.name.pattern}")
	private String	extrasFileNamePattern;

	@Value("${catalog.corrected.associations.name.pattern}")
	private String	correctedAssociationsFileNamePattern;
	@Value("${catalog.corrected.glasses.name.pattern}")
	private String	correctedGlassesFileNamePattern;
	@Value("${catalog.corrected.extras.name.pattern}")
	private String	correctedExtrasFileNamePattern;

	public void deleteFile(String filePath)
		throws IOException {
		Path toDelete = Paths.get(filePath);
		if (Files.isDirectory(toDelete, LinkOption.NOFOLLOW_LINKS)) {
			throw new IllegalArgumentException("File expected, but found a directory instead");
		}
		Files.delete(toDelete);
	}

	public void emptyDirectory(String directory)
		throws IOException {
		Path toEmpty = Paths.get(directory);
		if (!Files.isDirectory(toEmpty, LinkOption.NOFOLLOW_LINKS)) {
			throw new IllegalArgumentException("Directory expected, but found a file instead");
		}
		try(Stream<Path> pathStream = Files.list(toEmpty)) {
			pathStream.forEach(filePath -> {
				try {
					Files.delete(filePath);
				} catch (IOException e) {
					log.error("Error deleting file '" + filePath + "'", e);
				}
			});
		}
	}

	/**
	 * Archive the given file by copying it to the corresponding directory in the hierarchy tree
	 *
	 * @param filePath Fichier à copier dans le dossier d'archivage
	 * @throws IOException En cas d'erreur de copie
	 */
	public String archiveByCopy(String filePath)
		throws IOException {
		if (StringUtils.isEmpty(filePath)) {
			throw new IllegalArgumentException("File path is empty");
		}
		File sourceFile = new File(filePath);
		String fileName = sourceFile.getName();
		String directory = sourceFile.getParentFile().getName();
		String archiveRootDirectory = sourceFile.getParentFile().getParentFile() + "/" + archiveRepo;
		String archivedFile = archiveRootDirectory + "/" + directory + "/" + addTimestamp(fileName);
		Files.copy(new File(filePath).toPath(), new File(archivedFile).toPath());
		return archivedFile;
	}

	/**
	 * Archive the given file by moving it to the corresponding directory in the hierarchy tree
	 *
	 * @param filePath
	 * @throws IOException
	 */
	public String archiveByMove(String filePath)
		throws IOException {
		if (StringUtils.isEmpty(filePath)) {
			throw new IllegalArgumentException("File path is empty");
		}

		if(!Files.exists(Path.of(filePath))){
			log.error("Le fichier source {} n'existe pas", filePath);
			return null;
		}

		File sourceFile = new File(filePath);
		String fileName = sourceFile.getName();
		String directory = sourceFile.getParentFile().getName();
		String archiveRootDirectory = sourceFile.getParentFile().getParentFile() + "/" + archiveRepo;
		String archivedFile = archiveRootDirectory + "/" + directory + "/" + addTimestamp(fileName);
		Files.copy(new File(filePath).toPath(), new File(archivedFile).toPath());
		Files.delete(new File(filePath).toPath());
		return archivedFile;
	}

	/**
	 * Search for a value in a file.<br>
	 * The file must be in csv format.
	 * If the file is absent, or not in the CSV format, or doesn't use {@link Constants#CSV_SEPARATOR}, than will return false
	 *
	 * @param filePath
	 *            - Full path to the file
	 * @param value
	 * @param pos
	 * @return
	 */
	public boolean isInCSVFile(String filePath, String value, int pos) {
		if (StringUtils.isEmpty(filePath) || StringUtils.isEmpty(value) || pos < 0) {
			return false;
		}
		InputStream inputFS = null;
		BufferedReader br = null;
		FileSystemResource resource = new FileSystemResource(filePath);
		try {
			inputFS = resource.getInputStream();
			br = new BufferedReader(new InputStreamReader(inputFS));
			boolean boolToReturn = false;
			for(String line : br.lines().collect(Collectors.toList())){
				String[] chunks = line.split(Constants.CSV_SEPARATOR);
				if(chunks[pos].equals(value)) {
					boolToReturn = chunks[pos].equals(value);
					break;
				}
			}
			return boolToReturn;
		}
		catch (IOException ioe) {
			log.error(String.format("Error parsing the file '%s' for the value '%s' at the position '%d'", filePath, value, pos), ioe);
			return false;
		}
		finally {
			if (inputFS != null) {
				try {
					inputFS.close();
				}
				catch (IOException e) {
					log.error("Error closing InputStream after checking if the value '{}' is in the file {}", value, filePath, e);
				}
			}
			if (br != null) {
				try {
					br.close();
				}
				catch (IOException e) {
					log.error("Error closing BufferReader after checking if the value '{}' is in the file {}", value, filePath, e);
				}
			}
		}
	}

	/**
	 * Move one file from the sourcePath to the targetPath
	 *
	 * @param fileName
	 * @param sourcePath
	 * @param targetPath
	 * @throws IOException
	 */
	public void moveFile(String fileName, String sourcePath, String targetPath)
		throws IOException {
		Path source = Paths.get(sourcePath).resolve(fileName);
		Path target = Paths.get(targetPath).resolve(fileName);
		Files.move(source, target);
	}

	/**
	 * Copy one file from the sourcePath to the targetPath
	 *
	 * @param fileName
	 * @param sourcePath
	 * @param targetPath
	 * @throws IOException
	 */
	public void copyFile(String fileName, String sourcePath, String targetPath)
		throws IOException {
		Path source = Paths.get(sourcePath).resolve(fileName);
		Path target = Paths.get(targetPath).resolve(fileName);
		Files.copy(source, target);
	}

	/**
	 * Return the provider id for a given associations file name.
	 * The value is extracted from the file name, using the right regexp
	 *
	 * @param associationsFileName
	 * @param fileType
	 *            - a String indicating the type of the associationsFileName. Must be one of the following value :
	 *            <ul>
	 *            <li>{@see Constants.INITAL_FILE}</li>
	 *            <li>{@see Constants.CORRECTED_FILE}</li>
	 *            </ul>
	 *            otherwise will launch an IllegalArgumentException
	 * @return
	 * @throws FileNameNotMatchException
	 */
	public String extractProviderFromAssociationFileName(String associationsFileName, String fileType)
		throws FileNameNotMatchException {

		switch (fileType) {
			case Constants.INITAL_FILE:
				return extractProviderFromFileName(associationsFileName, associationsFileNamePattern, "associations");
			case Constants.CORRECTED_FILE:
				return extractProviderFromFileName(associationsFileName, correctedAssociationsFileNamePattern, "associations");
			default:
				throw new IllegalArgumentException("The fileType '" + fileType + "' is invalid.");
		}

	}

	/**
	 * Set the value for the associations file name for the catalog.<br>
	 * A file can only be set if the corresponding maker/provider/label/date exactly match the maker/provider/label/date of the catalog. (or if the file is the
	 * first to be set).
	 *
	 * @param associationsFileName
	 *            the associationsFileName to set
	 */
	public void defineAssociationsFileName(Catalog catalog, String associationsFileName) {

		try {
			String date = this.extractDateFromAssociationFileName(associationsFileName, catalog.getCatalogType());
			String maker = this.extractMakerFromAssociationFileName(associationsFileName, catalog.getCatalogType());
			String provider = this.extractProviderFromAssociationFileName(associationsFileName, catalog.getCatalogType());
			String label = this.extractLabelFromAssociationsFileName(associationsFileName, catalog.getCatalogType());

			// If it's the first file set, then the attributes will be empty, so we must set then and the file
			if (catalog.getDate() == null && catalog.getMaker() == null && catalog.getProvider() == null && catalog.getLabel() == null) {
				catalog.setDate(date);
				catalog.setMaker(maker);
				catalog.setProvider(provider);
				catalog.setLabel(label);
				catalog.setAssociationsFileName(associationsFileName);
			} else if (date.equals(catalog.getDate()) && maker.equals(catalog.getMaker()) && provider.equals(catalog.getProvider()) && label.equals(catalog.getLabel())) {
				// else we only set the file if all the attribute match
				catalog.setAssociationsFileName(associationsFileName);
				// if the 3 files have been set, then the catalog is complete
				catalog.setValid(catalog.getExtrasFileName() != null && catalog.getGlassesFileName() != null);
			} else {
				// otherwise we throw an exception
				throw new IllegalArgumentException(THE_FILE + associationsFileName + "' doesn't match to the current catalog : " + this);
			}
		}
		catch (FileNameNotMatchException e) {
			log.error(FILE_DOESN_T_EXIST_ERRM, associationsFileName, e);
			throw new IllegalArgumentException(THE_FILE + associationsFileName + DOESN_T_EXIST);
		}
	}

	/**
	 * Set the value for the extras file name for the catalog.<br>
	 * A file can only be set if the corresponding maker/provider/label/date exactly match the maker/provider/label/date of the catalog. (or if the file is the
	 * first to be set)
	 *
	 * @param extrasFileName
	 *            the extrasFileName to set
	 */
	public void defineExtrasFileName(Catalog catalog, String extrasFileName) {
		try {
			String date = this.extractDateFromExtrasFileName(extrasFileName, catalog.getCatalogType());
			String maker = this.extractMakerFromExtrasFileName(extrasFileName, catalog.getCatalogType());
			String provider = this.extractProviderFromExtrasFileName(extrasFileName, catalog.getCatalogType());
			String label = this.extractLabelFromExtrasFileName(extrasFileName, catalog.getCatalogType());

			// If it's the first file set, then the attributes will be empty, so we must set then and the file
			if (catalog.getDate() == null && catalog.getMaker() == null && catalog.getProvider() == null && catalog.getLabel() == null) {
				catalog.setDate(date);
				catalog.setMaker(maker);
				catalog.setProvider(provider);
				catalog.setLabel(label);
				catalog.setExtrasFileName(extrasFileName);
			} else if (date.equals(catalog.getDate()) && maker.equals(catalog.getMaker()) && provider.equals(catalog.getProvider()) && label.equals(catalog.getLabel())) {
				// else we only set the file if all the attribute match
				catalog.setExtrasFileName(extrasFileName);
				// if the 3 files have been set, then the catalog is complete
				catalog.setValid(catalog.getAssociationsFileName() != null && catalog.getGlassesFileName() != null);
			} else {
				// otherwise we throw an exception
				throw new IllegalArgumentException(THE_FILE + extrasFileName + "' doesn't correspond to the current catalog : " + this);
			}
		}
		catch (FileNameNotMatchException e) {
			log.error(FILE_DOESN_T_EXIST_ERRM, extrasFileName, e);
			throw new IllegalArgumentException(THE_FILE + extrasFileName + DOESN_T_EXIST);
		}
	}

	/**
	 * Set the value for the glasses file name for the catalog.<br>
	 * A file can only be set if the corresponding maker/provider/label/date exactly match the maker/provider/label/date of the catalog. (or if the file is the
	 * first to be set)
	 *
	 * @param glassesFileName
	 *            the glassesFileName to set
	 */
	public void defineGlassesFileName(Catalog catalog, String glassesFileName) {
		try {
			String date = this.extractDateFromGlassesFileName(glassesFileName, catalog.getCatalogType());
			String maker = this.extractMakerFromGlassesFileName(glassesFileName, catalog.getCatalogType());
			String provider = this.extractProviderFromGlassesFileName(glassesFileName, catalog.getCatalogType());
			String label = this.extractLabelFromGlassesFileName(glassesFileName, catalog.getCatalogType());

			// If it's the first file set, then the attributes will be empty, so we must set then and the file
			if (catalog.getDate() == null && catalog.getMaker() == null && catalog.getProvider() == null && catalog.getLabel() == null) {
				catalog.setDate(date);
				catalog.setMaker(maker);
				catalog.setProvider(provider);
				catalog.setLabel(label);
				catalog.setGlassesFileName(glassesFileName);
			} else if (date.equals(catalog.getDate()) && maker.equals(catalog.getMaker()) && provider.equals(catalog.getProvider()) && label.equals(catalog.getLabel())) {
				// else we only set the file if all the attribute match
				catalog.setGlassesFileName(glassesFileName);
				// if the 3 files have been set, then the catalog is complete
				catalog.setValid(catalog.getExtrasFileName() != null && catalog.getAssociationsFileName() != null);
			} else {
				// otherwise we throw an exception
				throw new IllegalArgumentException(THE_FILE + glassesFileName + "' doesn't correspond to the current catalog : " + this);
			}
		}
		catch (FileNameNotMatchException e) {
			log.error(FILE_DOESN_T_EXIST_ERRM, glassesFileName, e);
			throw new IllegalArgumentException(THE_FILE + glassesFileName + DOESN_T_EXIST);
		}

	}

	/**
	 * Return the provider id for a given glasses file name.
	 * The value is extracted from the file name, using the right regexp
	 *
	 * @param glassesFileName
	 * @param fileType
	 *            - a String indicating the type of the associationsFileName. Must be one of the following value :
	 *            <ul>
	 *            <li>{@see Constants.INITAL_FILE}</li>
	 *            <li>{@see Constants.CORRECTED_FILE}</li>
	 *            </ul>
	 *            otherwise will launch an IllegalArgumentException
	 * @return
	 * @throws FileNameNotMatchException
	 */
	public String extractProviderFromGlassesFileName(String glassesFileName, String fileType)
		throws FileNameNotMatchException {
		switch (fileType) {
			case Constants.INITAL_FILE:
				return extractProviderFromFileName(glassesFileName, glassesFileNamePattern, "glasses");
			case Constants.CORRECTED_FILE:
				return extractProviderFromFileName(glassesFileName, correctedGlassesFileNamePattern, "glasses");
			default:
				throw new IllegalArgumentException("The fileType '" + fileType + "' is invalid.");
		}

	}

	/**
	 * Return the provider id for a given extras file name.
	 * The value is extracted from the file name, using the right regexp
	 *
	 * @param extrasFileName
	 * @param fileType
	 *            - a String indicating the type of the associationsFileName. Must be one of the following value :
	 *            <ul>
	 *            <li>{@see Constants.INITAL_FILE}</li>
	 *            <li>{@see Constants.CORRECTED_FILE}</li>
	 *            </ul>
	 *            otherwise will launch an IllegalArgumentException
	 * @return
	 * @throws FileNameNotMatchException
	 */
	public String extractProviderFromExtrasFileName(String extrasFileName, String fileType)
		throws FileNameNotMatchException {
		switch (fileType) {
			case Constants.INITAL_FILE:
				return extractProviderFromFileName(extrasFileName, extrasFileNamePattern, "extras");
			case Constants.CORRECTED_FILE:
				return extractProviderFromFileName(extrasFileName, correctedExtrasFileNamePattern, "extras");
			default:
				throw new IllegalArgumentException("The fileType '" + fileType + "' is invalid.");
		}

	}

	/**
	 * Return the maker id for a given associations file name.
	 * The value is extracted from the file name, using the right regexp
	 *
	 * @param associationsFileName
	 * @param fileType
	 *            - a String indicating the type of the associationsFileName. Must be one of the following value :
	 *            <ul>
	 *            <li>{@see Constants.INITAL_FILE}</li>
	 *            <li>{@see Constants.CORRECTED_FILE}</li>
	 *            </ul>
	 *            otherwise will launch an IllegalArgumentException
	 * @return
	 * @throws FileNameNotMatchException
	 */
	public String extractMakerFromAssociationFileName(String associationsFileName, String fileType)
		throws FileNameNotMatchException {
		switch (fileType) {
			case Constants.INITAL_FILE:
				return extractMakerFromFileName(associationsFileName, associationsFileNamePattern, "associations");
			case Constants.CORRECTED_FILE:
				return extractMakerFromFileName(associationsFileName, correctedAssociationsFileNamePattern, "associations");
			default:
				throw new IllegalArgumentException("The fileType '" + fileType + "' is invalid.");
		}

	}

	/**
	 * Return the date for a given associations file name.
	 * The value is extracted from the file name, using the right regexp
	 *
	 * @param associationsFileName
	 * @param fileType
	 *            - a String indicating the type of the associationsFileName. Must be one of the following value :
	 *            <ul>
	 *            <li>{@see Constants.INITAL_FILE}</li>
	 *            <li>{@see Constants.CORRECTED_FILE}</li>
	 *            </ul>
	 *            otherwise will launch an IllegalArgumentException
	 * @return
	 * @throws FileNameNotMatchException
	 */
	public String extractDateFromAssociationFileName(String associationsFileName, String fileType)
		throws FileNameNotMatchException {
 		switch (fileType) {
			case Constants.INITAL_FILE:
				return extractDateFromFileName(associationsFileName, associationsFileNamePattern, "associations");
			case Constants.CORRECTED_FILE:
				return extractDateFromFileName(associationsFileName, correctedAssociationsFileNamePattern, "associations");
			default:
				throw new IllegalArgumentException("The fileType '" + fileType + "' is invalid.");
		}

	}

	/**
	 * Return the date for a given glasses file name.
	 * The value is extracted from the file name, using the right regexp
	 *
	 * @param glassesFileName
	 * @param fileType
	 *            - a String indicating the type of the associationsFileName. Must be one of the following value :
	 *            <ul>
	 *            <li>{@see Constants.INITAL_FILE}</li>
	 *            <li>{@see Constants.CORRECTED_FILE}</li>
	 *            </ul>
	 *            otherwise will launch an IllegalArgumentException
	 * @return
	 * @throws FileNameNotMatchException
	 */
	public String extractDateFromGlassesFileName(String glassesFileName, String fileType)
		throws FileNameNotMatchException {
		switch (fileType) {
			case Constants.INITAL_FILE:
				return extractDateFromFileName(glassesFileName, glassesFileNamePattern, "glasses");
			case Constants.CORRECTED_FILE:
				return extractDateFromFileName(glassesFileName, correctedGlassesFileNamePattern, "glasses");
			default:
				throw new IllegalArgumentException("The fileType '" + fileType + "' is invalid.");
		}

	}

	/**
	 * Return the date for a given extras file name.
	 * The value is extracted from the file name, using the right regexp
	 *
	 * @param extrasFileName
	 * @param fileType
	 *            - a String indicating the type of the associationsFileName. Must be one of the following value :
	 *            <ul>
	 *            <li>{@see Constants.INITAL_FILE}</li>
	 *            <li>{@see Constants.CORRECTED_FILE}</li>
	 *            </ul>
	 *            otherwise will launch an IllegalArgumentException
	 * @return
	 * @throws FileNameNotMatchException
	 */
	public String extractDateFromExtrasFileName(String extrasFileName, String fileType)
		throws FileNameNotMatchException {
		switch (fileType) {
			case Constants.INITAL_FILE:
				return extractDateFromFileName(extrasFileName, extrasFileNamePattern, "extras");
			case Constants.CORRECTED_FILE:
				return extractDateFromFileName(extrasFileName, correctedExtrasFileNamePattern, "extras");
			default:
				throw new IllegalArgumentException("The fileType '" + fileType + "' is invalid.");
		}

	}

	/**
	 * Return the maker id for a given glasses file name.
	 * The value is extracted from the file name, using the right regexp
	 *
	 * @param glassesFileName
	 * @param fileType
	 *            - a String indicating the type of the associationsFileName. Must be one of the following value :
	 *            <ul>
	 *            <li>{@see Constants.INITAL_FILE}</li>
	 *            <li>{@see Constants.CORRECTED_FILE}</li>
	 *            </ul>
	 *            otherwise will launch an IllegalArgumentException
	 * @return
	 * @throws FileNameNotMatchException
	 */
	public String extractMakerFromGlassesFileName(String glassesFileName, String fileType)
		throws FileNameNotMatchException {
		switch (fileType) {
			case Constants.INITAL_FILE:
				return extractMakerFromFileName(glassesFileName, glassesFileNamePattern, "glasses");
			case Constants.CORRECTED_FILE:
				return extractMakerFromFileName(glassesFileName, correctedGlassesFileNamePattern, "glasses");
			default:
				throw new IllegalArgumentException("The fileType '" + fileType + "' is invalid.");
		}

	}

	/**
	 * Return the maker id for a given extras file name.
	 * The value is extracted from the file name, using the right regexp
	 *
	 * @param extrasFileName
	 * @param fileType
	 *            - a String indicating the type of the associationsFileName. Must be one of the following value :
	 *            <ul>
	 *            <li>{@see Constants.INITAL_FILE}</li>
	 *            <li>{@see Constants.CORRECTED_FILE}</li>
	 *            </ul>
	 *            otherwise will launch an IllegalArgumentException
	 * @return
	 * @throws FileNameNotMatchException
	 */
	public String extractMakerFromExtrasFileName(String extrasFileName, String fileType)
		throws FileNameNotMatchException {
		switch (fileType) {
			case Constants.INITAL_FILE:
				return extractMakerFromFileName(extrasFileName, extrasFileNamePattern, "extras");
			case Constants.CORRECTED_FILE:
				return extractMakerFromFileName(extrasFileName, correctedExtrasFileNamePattern, "extras");
			default:
				throw new IllegalArgumentException("The fileType '" + fileType + "' is invalid.");
		}

	}

	/**
	 * Return the label for a given associations file name.
	 * The value is extracted from the file name, using the right regexp
	 *
	 * @param associationsFileName
	 * @param fileType
	 *            - a String indicating the type of the associationsFileName. Must be one of the following value :
	 *            <ul>
	 *            <li>{@see Constants.INITAL_FILE}</li>
	 *            <li>{@see Constants.CORRECTED_FILE}</li>
	 *            </ul>
	 *            otherwise will launch an IllegalArgumentException
	 * @return
	 * @throws FileNameNotMatchException
	 */
	public String extractLabelFromAssociationsFileName(String associationsFileName, String fileType)
		throws FileNameNotMatchException {
		switch (fileType) {
			case Constants.INITAL_FILE:
				return extractLabelFromFileName(associationsFileName, associationsFileNamePattern, "associations");
			case Constants.CORRECTED_FILE:
				return extractLabelFromFileName(associationsFileName, correctedAssociationsFileNamePattern, "associations");
			default:
				throw new IllegalArgumentException("The fileType '" + fileType + "' is invalid.");
		}

	}

	/**
	 * Return the label for a given glasses file name.
	 * The value is extracted from the file name, using the right regexp
	 *
	 * @param glassesFileName
	 * @param fileType
	 *            - a String indicating the type of the associationsFileName. Must be one of the following value :
	 *            <ul>
	 *            <li>{@see Constants.INITAL_FILE}</li>
	 *            <li>{@see Constants.CORRECTED_FILE}</li>
	 *            </ul>
	 *            otherwise will launch an IllegalArgumentException
	 * @return
	 * @throws FileNameNotMatchException
	 */
	public String extractLabelFromGlassesFileName(String glassesFileName, String fileType)
		throws FileNameNotMatchException {
		switch (fileType) {
			case Constants.INITAL_FILE:
				return extractLabelFromFileName(glassesFileName, glassesFileNamePattern, "glasses");
			case Constants.CORRECTED_FILE:
				return extractLabelFromFileName(glassesFileName, correctedGlassesFileNamePattern, "glasses");
			default:
				throw new IllegalArgumentException("The fileType '" + fileType + "' is invalid.");
		}

	}

	/**
	 * Return the label for a given extras file name.
	 * The value is extracted from the file name, using the right regexp
	 *
	 * @param extrasFileName
	 * @param fileType
	 *            - a String indicating the type of the associationsFileName. Must be one of the following value :
	 *            <ul>
	 *            <li>{@see Constants.INITAL_FILE}</li>
	 *            <li>{@see Constants.CORRECTED_FILE}</li>
	 *            </ul>
	 *            otherwise will launch an IllegalArgumentException
	 * @return
	 * @throws FileNameNotMatchException
	 */
	public String extractLabelFromExtrasFileName(String extrasFileName, String fileType)
		throws FileNameNotMatchException {
		switch (fileType) {
			case Constants.INITAL_FILE:
				return extractLabelFromFileName(extrasFileName, extrasFileNamePattern, "extras");
			case Constants.CORRECTED_FILE:
				return extractLabelFromFileName(extrasFileName, correctedExtrasFileNamePattern, "extras");
			default:
				throw new IllegalArgumentException("The fileType '" + fileType + "' is invalid.");
		}

	}

	/**
	 * Return the label for the given file name
	 *
	 * @param fileName
	 *            - The file name to process
	 * @param pattern
	 *            - The regex pattern to apply
	 * @param fileType
	 *            - The type of file (ie associations, glasses or extras)
	 * @return
	 * @throws FileNameNotMatchException
	 */
	private String extractLabelFromFileName(String fileName, String pattern, String fileType)
		throws FileNameNotMatchException {
		return extractElementFromFileName(fileName, pattern, fileType, "label");
	}

	/**
	 * Return the maker id for the given file name
	 *
	 * @param fileName
	 *            - The file name to process
	 * @param pattern
	 *            - The regex pattern to apply
	 * @param fileType
	 *            - The type of file (ie associations, glasses or extras)
	 * @return
	 * @throws FileNameNotMatchException
	 */
	private String extractMakerFromFileName(String fileName, String pattern, String fileType)
		throws FileNameNotMatchException {
		return extractElementFromFileName(fileName, pattern, fileType, "maker");
	}

	/**
	 * Return the date for the given file name
	 *
	 * @param fileName
	 *            - The file name to process
	 * @param pattern
	 *            - The regex pattern to apply
	 * @param fileType
	 *            - The type of file (ie associations, glasses or extras)
	 * @return
	 * @throws FileNameNotMatchException
	 */
	private String extractDateFromFileName(String fileName, String pattern, String fileType)
		throws FileNameNotMatchException {
		return extractElementFromFileName(fileName, pattern, fileType, "date");
	}

	/**
	 * Return the provider id for the given file name
	 *
	 * @param fileName
	 *            - The file name to process
	 * @param pattern
	 *            - The regex pattern to apply
	 * @param fileType
	 *            - The type of file processed (ie associations, glasses or extras)
	 * @return
	 * @throws FileNameNotMatchException
	 */
	private String extractProviderFromFileName(String fileName, String pattern, String fileType)
		throws FileNameNotMatchException {
		return extractElementFromFileName(fileName, pattern, fileType, "provider");
	}

	/**
	 * Return the expected tag from the given file name
	 *
	 * @param fileName
	 *            - The file name to process
	 * @param pattern
	 *            - The regex pattern to apply
	 * @param fileType
	 *            - The type of file processed (ie associations, glasses or extras)
	 * @param dataType
	 *            - The tag type wanted (ie maker or provider)
	 * @return
	 * @throws FileNameNotMatchException
	 *
	 */
	private String extractElementFromFileName(String fileName, String pattern, String fileType, String dataType)
		throws FileNameNotMatchException {
		Pattern p = Pattern.compile(pattern);
		Matcher m = p.matcher(fileName);
		if (m.matches()) {
			int groupId;
			switch (dataType) {
				case "maker":
					groupId = 1;
					break;
				case "provider":
					groupId = 2;
					break;
				case "label":
					groupId = 3;
					break;
				case "date":
					groupId = 4;
					break;
				default:
					throw new IllegalArgumentException("The dataType '" + dataType + "' is unknow. Expected values : 'maker' / 'provider' ");
			}
			return m.group(groupId);
		} else {

			throw new FileNameNotMatchException("The " + fileType + " file name " + fileName + " doesn't respect the defined pattern.");
		}
	}

	public String convertToCorrectedAssociationsFileName(String associationsFileName) {
		return convertToCorrectedFileName(associationsFileName, associationsFileNamePattern, "associations");
	}

	public String convertToCorrectedGlassessFileName(String glassesFileName) {
		return convertToCorrectedFileName(glassesFileName, glassesFileNamePattern, "glasses");
	}

	public String convertToCorrectedExtrasFileName(String extrasFileName) {
		return convertToCorrectedFileName(extrasFileName, extrasFileNamePattern, "extras");
	}

	private String convertToCorrectedFileName(String fileName, String pattern, String dataType) {
		Pattern p = Pattern.compile(pattern);
		Matcher m = p.matcher(fileName);
		if (m.matches()) {
			String newName;
			switch (dataType) {
				case "associations":
					// For now, we don't rename the associations file
					newName = fileName;
					break;
				case "glasses":
					newName = fileName.replace("verres-", "verres-enrichis-");
					break;
				case "extras":
					newName = fileName.replace("supplements-", "supplements-enrichis-");
					break;
				default:
					throw new IllegalArgumentException("The dataType '" + dataType + "' is unknown'");

			}
			return newName;
		} else {
			throw new IllegalArgumentException(
				"The " + dataType + " file name '" + fileName + "' doesn't respect the pattern '" + pattern + "'");
		}
	}

	public String addTimestamp(String fileName) {
		return addTimestamp(fileName, new Date());
	}

	public String addTimestamp(String fileName, Date date) {
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
		return fileName + "." + simpleDateFormat.format(date);
	}
}