class XlsImExporter {

  public static void importXls(final FileMatcher fileMatcher,
                               final File xlsFile,
                               final Charset propertyFileEncoding,
                               final MissingKeyAction missingKeyAction) {
    Require.nonNull(fileMatcher);
    Require.nonNull(xlsFile);

    final ApronOptions apronOptions= ApronOptions.create()
      .with(propertyFileEncoding != null ? propertyFileEncoding : UTF_8)
      .with(missingKeyAction);

    // read XLS file
    final XlsFile xlsFileObject= new XlsFile(xlsFile);
    final Map<I18nBundleKey, Collection<Translation>> content= xlsFileObject.getContent();

    // stores the mapping of resource bundle basenames and languages to the corresponding property files
    final Map<String, Map<Language, RememberingPropertyFile>> bundleFileMapping= new LinkedHashMap<>();

    // FIXME: Sort by bundleBasename and language? In that case we only have to have 1 property file open at a time
    content.entrySet().forEach((entry) -> {
      final I18nBundleKey bundleKey= entry.getKey();
      final String bundleBasename= bundleKey.getBundleBaseName();
      final String propertyKey= bundleKey.getKey();
      final Collection<Translation> translations= entry.getValue();

      // for each bundle…
      for (final Translation translation : translations) {
        if (!bundleFileMapping.containsKey(bundleBasename)) {
          bundleFileMapping.put(bundleBasename, new LinkedHashMap<>());
        }

        if (!bundleFileMapping.get(bundleBasename).containsKey(translation.getLang())) {
          final File fileForBundle= getFileForBundle(fileMatcher.getRoot().toFile(), bundleBasename, translation.getLang());

          if (!fileMatcher.matches(fileForBundle.toPath())) {
            LOGGER.log(Level.DEBUG, "Skipping import to file {} since it does not match inclusion pattern", fileForBundle);
            continue;
          }

          final PropertyFile propertyFile= new PropertyFile();
          bundleFileMapping.get(bundleBasename).put(translation.getLang(), new RememberingPropertyFile(fileForBundle, propertyFile));
        }

        final RememberingPropertyFile rpf= bundleFileMapping.get(bundleBasename).get(translation.getLang());
        // only write empty values if the key already exists in in the PropertyFile
        if ((translation.getValue() != null && !translation.getValue().isEmpty())
          || rpf.propertyFile.containsKey(propertyKey)) {
          rpf.propertyFile.setValue(propertyKey, translation.getValue());
        }
      }
    });

    //now write the property files back to disk
    bundleFileMapping.values().forEach((Map<Language, RememberingPropertyFile> langPropMap) -> {
      langPropMap.values().forEach((RememberingPropertyFile rpf) -> {
        // only write files if they have some content (avoid creating unwanted empty files for unsupported locales)
        if (rpf.propertyFile.propertiesSize()> 0) {
          rpf.propertyFile.saveTo(rpf.actualFile, apronOptions);
        }
      });
    });
  }

}