/**
 * Copyright (c) 2016, German Neuroinformatics Node (G-Node)
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted under the terms of the BSD License. See
 * LICENSE file in the root of the Project.
 */

package org.g_node.mergers;

import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import java.util.Locale;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.log4j.Logger;
import org.g_node.micro.commons.CliToolController;
import org.g_node.micro.commons.FileService;
import org.g_node.micro.commons.RDFService;
import org.g_node.srv.CliOptionService;
import org.g_node.srv.CtrlCheckService;
import org.g_node.srv.ModelUtils;

/**
 * Class handling the merging of RDF documents of the Use case of Kay Thurley.
 * TODO rename this class!
 * TODO add more in depth description.
 *
 * @author Michael Sonntag (sonntag@bio.lmu.de)
 */
public class LktCliController implements CliToolController {
    /**
     * Access to the main LOGGER.
     */
    private static final Logger LOGGER = Logger.getLogger(LktCliController.class.getName());

    /**
     * Method returning the commandline options of the LKT merge tool.
     *
     * Option mergeRDF: Returns merge RDF file option required to merge a given RDF file with another
     * RDF file from the command line. Commandline option shorthands are "-i" and "-merge-file".
     * This option will always be "required".
     *
     * Option mainRDF: Returns main RDF file option required to merge a given RDF file with another
     * RDF file from the command line. Commandline option shorthands are "-m" and "-main-file".
     * This option will always be "required".
     *
     * @return Available {@link CommandLine} {@link Options}.
     */
    public final Options options() {

        final Options options = new Options();

        final Option opHelp = CliOptionService.getHelpOption("");

        final Option opMergeFile = Option.builder("i")
                .longOpt("merge-file")
                .desc("RDF file that will be merged with a main RDF file.")
                .required()
                .hasArg()
                .valueSeparator()
                .build();

        final String mainDesc = String.join("",
                "RDF file containing the main database. Entries from the merge RDF file ",
                "will be integrated into this file. Duplicate entries between the merge RDF file and this file ",
                "will be removed from the main database and replaced by the entries found in the merge RDF file.");

        final Option opMainFile = Option.builder("m")
                .longOpt("main-file")
                .desc(mainDesc)
                .required()
                .hasArg()
                .valueSeparator()
                .build();

        final Option opOut = CliOptionService.getOutFileOption("");
        final Option opFormat = CliOptionService.getOutFormatOption("");

        options.addOption(opHelp);
        options.addOption(opMergeFile);
        options.addOption(opMainFile);
        options.addOption(opOut);
        options.addOption(opFormat);

        return options;
    }

    /**
     * Method to merge two RDF files, one named mergeRDF, the other mainRDF. Information will be merged from the
     * mergeRDF file with the mainRDF file. If an output filename is provided, the merged RDF graph will be
     * saved to this output file. If no output filename is specified, a backup of the mainRDF file will be created,
     * using the format '[date_time]_backup_[main file name]' and the mainRDF file will be replaced with the merged
     * RDF graph.
     * If RDF Resources with the same URI are encountered in both mergeRDF and mainRDF, this Resource including all
     * referenced Blank Nodes will be removed from the mainRDF before the merge of the two graphs is performed. This
     * ensures, that only the information of the mergeRDF graph will be present in the merged final graph.
     *
     * @param cmd User provided {@link CommandLine} input containing information about the mergeRDF file, mainRDF file,
     *            the output filename and the output format.
     */
    public final void run(final CommandLine cmd) {
        final String mergeFile = cmd.getOptionValue("i");
        if (!CtrlCheckService.isExistingFile(mergeFile)) {
            return;
        }

        final String mainFile = cmd.getOptionValue("m");
        if (!CtrlCheckService.isExistingFile(mainFile)) {
            return;
        }

        final String outputFormat = cmd.getOptionValue("f", "TTL").toUpperCase(Locale.ENGLISH);
        if (!CtrlCheckService.isSupportedOutputFormat(outputFormat, RDFService.RDF_FORMAT_MAP.keySet())) {
            return;
        }

        String outputFile = cmd.getOptionValue("o", mainFile);
        if (!outputFile.toLowerCase().endsWith(RDFService.RDF_FORMAT_EXTENSION.get(outputFormat))) {
            outputFile = String.join("", outputFile, ".", RDFService.RDF_FORMAT_EXTENSION.get(outputFormat));
        }

        if (!CtrlCheckService.isValidRdfFile(mainFile) || !CtrlCheckService.isValidRdfFile(mergeFile)) {
            return;
        }

        final Model mainModel = RDFService.openModelFromFile(mainFile);
        final Model addModel = RDFService.openModelFromFile(mergeFile);

        Model mergeModel = ModelFactory.createDefaultModel();

        mergeModel.setNsPrefixes(mainModel.getNsPrefixMap());
        mergeModel.setNsPrefixes(addModel.getNsPrefixMap());

        mergeModel = ModelUtils.removePropertiesFromModel(addModel, mainModel, true);
        mergeModel.add(addModel);

        // TODO test if this conditional works as required and maybe come up with a better solution.
        // Create backup, if the output file is the same as the main RDF file.
        if (mainFile.equals(outputFile) && !FileService.createTimeStampBackupFile(mainFile, "yyyyMMddHHmm")) {
            LktCliController.LOGGER.error(
                    String.join("", "[ERROR ] While saving backup for file '", mainFile, "'")
            );
            return;
        }

        RDFService.saveModelToFile(outputFile, mergeModel, outputFormat);
    }

}

@@ -311,95 +311,8 @@
 s;%0A%0A
-import com.hp.hpl.jena.rdf.model.Model;%0Aimport com.hp.hpl.jena.rdf.model.ModelFactory;%0A
 impo
@@ -456,40 +456,8 @@
 ns;%0A
-import org.apache.log4j.Logger;%0A
 impo
@@ -507,53 +507,8 @@
 er;%0A
-import org.g_node.micro.commons.FileService;%0A
 impo
@@ -631,55 +631,63 @@
 ce;%0A
-import org.g_node.srv.ModelUtils;%0A%0A/**%0A * Class
+%0A/**%0A * Class handling validating commandline input and
  han
@@ -724,17 +724,26 @@
 ents
- of the U
+%0A * for the main u
 se c
@@ -766,74 +766,8 @@
 ey.%0A
- * TODO rename this class!%0A * TODO add more in depth description.%0A
  *%0A 
@@ -882,152 +882,8 @@
 r %7B%0A
-    /**%0A     * Access to the main LOGGER.%0A     */%0A    private static final Logger LOGGER = Logger.getLogger(LktCliController.class.getName());%0A%0A
     
@@ -2967,803 +2967,185 @@
 hod 
-to merge two RDF files, one named mergeRDF, the other mainRDF. Information will be merged from the%0A     * mergeRDF file with the mainRDF file. If an output filename is provided, the
+validates the commandline input for this
  merge
-d RDF graph will be%0A     * saved to this output file. If no output filename is specified, a backup of the mainRDF file will be created,%0A     * using the format '%5Bdate_time%5D_backup_%5Bmain file name%5D' and the mainRDF file will be replaced with the merged%0A     * RDF graph.%0A     * If RDF Resources with the same URI are encountered in both mergeRDF and mainRDF, this Resource including all%0A     * referenced Blank Nodes will be removed from the mainRDF before the merge of the two graphs is performed. This%0A     * ensures, that only the information of the mergeRDF graph will be present in the merged final graph
+r. When all checks pass, all relevant information is%0A     * passed to the actual class that merges the content of the two RDF files
 .%0A  
@@ -4350,984 +4350,66 @@
     
-final Model mainModel = RDFService.openModelFromFile(mainFile);%0A        final Model addModel = RDFService.openModelFromFile(mergeFile);%0A%0A        Model mergeModel = ModelFactory.createDefaultModel();%0A%0A        mergeModel.setNsPrefixes(mainModel.getNsPrefixMap());%0A        mergeModel.setNsPrefixes(addModel.getNsPrefixMap());%0A%0A        mergeModel = ModelUtils.removePropertiesFromModel(addModel, mainModel, true);%0A        mergeModel.add(addModel);%0A%0A        // TODO test if this conditional works as required and maybe come up with a better solution.%0A        // Create backup, if the output file is the same as the main RDF file.%0A        if (mainFile.equals(outputFile) && !FileService.createTimeStampBackupFile(mainFile, %22yyyyMMddHHmm%22)) %7B%0A            LktCliController.LOGGER.error(%0A                    String.join(%22%22, %22%5BERROR %5D While saving backup for file '%22, mainFile, %22'%22)%0A            );%0A            return;%0A        %7D%0A%0A        RDFService.saveModelToFile(outputFile, mergeModel
+LktJenaMerger.mergeAndSave(mainFile, mergeFile, outputFile
 , ou

Move merging step to Merger file