
package de.ivu.elect.business.datei.entity;

import static java.util.Collections.emptyList;
import static java.util.Collections.emptySet;
import static java.util.Objects.nonNull;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
import static org.apache.commons.lang3.StringUtils.endsWithIgnoreCase;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.lowerCase;
import static org.apache.commons.lang3.StringUtils.trimToEmpty;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import javax.inject.Inject;

import de.ivu.elect.jee.faces.Messages;
import de.ivu.elect.jee.faces.upload.AllowedTypesFilter;

public class FileTypeResolver {

  public static final FileType F_DATEI_FILE_TYPE = FileType.XML;

  public static final String FILE_TYPE_HTML_REG_EX_ALL = new AllowedTypesFilter().getAllowedTypesRegEx(emptyList());

  public static final String FILE_TYPE_HTML_ACCEPT_ALL = "*";

  @Inject
  private transient Messages messages;

  public FileTypeResolver() {
    super();
  }

  public Optional<FileType> getFileType(File file) {
    if (nonNull(file)) {
      return getFileType(file.getName());
    }

    return Optional.empty();
  }

  public Optional<FileType> getFileType(CharSequence fileName) {
    for (FileType fileType : FileType.values()) {
      if (isFileTypeMatchingFileName(fileType, fileName)) {
        return Optional.of(fileType);
      }
    }

    return Optional.empty();
  }

  protected boolean isFileTypeMatchingFileName(FileType fileType, CharSequence fileName) {
    if (isNotBlank(fileName)) {
      String fileNameNormalized = trimToEmpty(fileName.toString());

      return isFileTypeForSimpleFile(fileType, fileNameNormalized) || isFileTypeForFDatei(fileType, fileNameNormalized);
    }

    return false;
  }

  private boolean isFileTypeForSimpleFile(FileType fileType, String fileNameNormalized) {
    return endsWithIgnoreCase(fileNameNormalized, "." + fileType.getFileExtension());
  }

  // WASDE-1222
  private boolean isFileTypeForFDatei(FileType fileType, String fileNameNormalized) {
    return F_DATEI_FILE_TYPE.equals(fileType) && fileNameNormalized.matches("(?i)F\\..+\\." + fileType.getFileExtension() + "\\.\\d+");
  }

  public String getFileTypesHtmlRegEx(List<FileType> fileTypes) {
    return new AllowedTypesFilter().getAllowedTypesRegEx(collectFileExtensionsIncludingAliases(fileTypes));
  }

  // ELECTVAPP-1274
  public String getFileTypesHtmlAccept(List<FileType> fileTypes) {
    Set<String> fileTypesHtmlAccept = new HashSet<>();

    if (fileTypes != null) {
      for (FileType fileType : fileTypes) {
        String fileExtension = fileType.getFileExtension();

        if (fileType.isImage()) {
          fileTypesHtmlAccept.add("image/*");
        } else {
          fileTypesHtmlAccept.add(lowerCase("." + fileExtension));
        }

        if (FileType.ALL.equals(fileType) || fileTypesHtmlAccept.size() > 3 || isBlank(fileExtension)) {
          fileTypesHtmlAccept.clear();

          break;
        }
      }
    }

    if (fileTypesHtmlAccept.isEmpty()) {
      return FILE_TYPE_HTML_ACCEPT_ALL;
    }

    return fileTypesHtmlAccept.stream() //
        .sorted() //
        .collect(joining(","));
  }

  public String formatFileTypes(List<FileType> fileTypes) {
    List<String> fileExtensions = new ArrayList<>(collectFileExtensions(fileTypes));

    if (fileExtensions.isEmpty()) {
      fileExtensions.add(FileType.ALL.getFileExtension());
    }

    return fileExtensions.stream() //
        .map(fileExtension -> "*." + fileExtension) //
        .collect(joining(", "));
  }

  private List<String> collectFileExtensionsIncludingAliases(List<FileType> fileTypes) {
    List<String> result = new ArrayList<>(collectFileExtensions(fileTypes));
    result.addAll(collectFileExtensionAliases(fileTypes));

    Collections.sort(result);

    return result;
  }

  private List<String> collectFileExtensions(List<FileType> fileTypes) {
    if (fileTypes == null || fileTypes.isEmpty()) {
      return emptyList();
    }

    return fileTypes.stream() //
        .map(fileType -> fileType.getFileExtension().toLowerCase()) //
        .sorted() //
        .collect(toList());
  }

  protected Set<String> collectFileExtensionAliases(List<FileType> fileTypes) {
    return emptySet();
  }

  protected String getMessage(String msgKey, Object... params) {
    return messages.getMessageForMessageKey(msgKey, params);
  }
}
