/* Copyright (C) 2016-2026 Stephan Kreutzer
 *
 * This file is part of hyperdex_1 workflow, a submodule of the
 * digital_publishing_workflow_tools package.
 *
 * hyperdex_1 workflow is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License version 3 or any later version,
 * as published by the Free Software Foundation.
 *
 * hyperdex_1 workflow is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License 3 for more details.
 *
 * You should have received a copy of the GNU Affero General Public License 3
 * along with hyperdex_1 workflow. If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * @file $/htx/workflows/hyperdex/hyperdex_1/hyperdex_1.java
 * @brief Manages of how to call hyperdex_1 and handle the files.
 * @author Stephan Kreutzer
 * @since 2026-06-06
 */



import java.util.List;
import java.util.ArrayList;
import java.util.Locale;
import java.util.ResourceBundle;
import java.text.MessageFormat;
import java.io.File;
import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.io.FileOutputStream;
import java.io.StringWriter;
import java.io.PrintWriter;
import java.io.FileNotFoundException;
import java.io.UnsupportedEncodingException;
import java.io.IOException;
import java.net.URLDecoder;
import javax.xml.stream.XMLInputFactory;
import java.io.InputStream;
import java.io.FileInputStream;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.events.XMLEvent;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.Namespace;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import java.util.Scanner;
import java.util.Map;
import java.util.LinkedHashMap;
import java.util.Iterator;
import java.io.BufferedReader;
import java.io.InputStreamReader;



public class hyperdex_1
{
    public static void main(String[] args)
    {
        System.out.print("hyperdex_1 workflow Copyright (C) 2016-2026 Stephan Kreutzer\n" +
                         "This program comes with ABSOLUTELY NO WARRANTY.\n" +
                         "This is free software, and you are welcome to redistribute it\n" +
                         "under certain conditions. See the GNU Affero General Public License 3\n" +
                         "or any later version for details. Also, see the source code repository\n" +
                         "https://gitlab.com/publishing-systems/digital_publishing_workflow_tools/ and\n" +
                         "the project website https://hypertext-systems.org.\n\n");

        hyperdex_1 instance = new hyperdex_1();

        try
        {
            instance.Run(args);
        }
        catch (ProgramTerminationException ex)
        {
            instance.handleTermination(ex);
        }

        if (instance.resultInfoFile != null)
        {
            File outputFile = instance.GetOutputFile();
            File outputDimgraFile = instance.GetOutputDimgraFile();

            try
            {
                BufferedWriter writer = new BufferedWriter(
                                        new OutputStreamWriter(
                                        new FileOutputStream(instance.resultInfoFile),
                                        "UTF-8"));

                writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
                writer.write("<!-- This file was created by hyperdex_1 workflow, which is free software licensed under the GNU Affero General Public License 3 or any later version (see https://gitlab.com/publishing-systems/digital_publishing_workflow_tools/ and https://hypertext-systems.org). -->\n");
                writer.write("<hyperdex-1-workflow-result-information>\n");
                writer.write("  <success>\n");
                writer.write("    <output-files>\n");

                if (outputFile != null)
                {
                    writer.write("      <output-file path=\"" + outputFile.getAbsolutePath() + "\"/>\n");
                }

                if (outputDimgraFile != null)
                {
                    writer.write("      <output-dimgra-file path=\"" + outputDimgraFile.getAbsolutePath() + "\"/>\n");
                }

                writer.write("    </output-files>\n");

                if (instance.getInfoMessages().size() > 0)
                {
                    writer.write("    <info-messages>\n");

                    for (int i = 0, max = instance.getInfoMessages().size(); i < max; i++)
                    {
                        InfoMessage infoMessage = instance.getInfoMessages().get(i);

                        writer.write("      <info-message number=\"" + i + "\">\n");
                        writer.write("        <timestamp>" + infoMessage.getTimestamp() + "</timestamp>\n");

                        String infoMessageText = infoMessage.getMessage();
                        String infoMessageId = infoMessage.getId();
                        String infoMessageBundle = infoMessage.getBundle();
                        Object[] infoMessageArguments = infoMessage.getArguments();

                        if (infoMessageBundle != null)
                        {
                            // Ampersand needs to be the first, otherwise it would double-encode
                            // other entities.
                            infoMessageBundle = infoMessageBundle.replaceAll("&", "&amp;");
                            infoMessageBundle = infoMessageBundle.replaceAll("<", "&lt;");
                            infoMessageBundle = infoMessageBundle.replaceAll(">", "&gt;");

                            writer.write("        <id-bundle>" + infoMessageBundle + "</id-bundle>\n");
                        }

                        if (infoMessageId != null)
                        {
                            // Ampersand needs to be the first, otherwise it would double-encode
                            // other entities.
                            infoMessageId = infoMessageId.replaceAll("&", "&amp;");
                            infoMessageId = infoMessageId.replaceAll("<", "&lt;");
                            infoMessageId = infoMessageId.replaceAll(">", "&gt;");

                            writer.write("        <id>" + infoMessageId + "</id>\n");
                        }

                        if (infoMessageText != null)
                        {
                            // Ampersand needs to be the first, otherwise it would double-encode
                            // other entities.
                            infoMessageText = infoMessageText.replaceAll("&", "&amp;");
                            infoMessageText = infoMessageText.replaceAll("<", "&lt;");
                            infoMessageText = infoMessageText.replaceAll(">", "&gt;");

                            writer.write("        <message>" + infoMessageText + "</message>\n");
                        }

                        if (infoMessageArguments != null)
                        {
                            writer.write("        <arguments>\n");

                            int argumentCount = infoMessageArguments.length;

                            for (int j = 0; j < argumentCount; j++)
                            {
                                if (infoMessageArguments[j] == null)
                                {
                                    writer.write("          <argument number=\"" + j + "\">\n");
                                    writer.write("            <class></class>\n");
                                    writer.write("            <value>null</value>\n");
                                    writer.write("          </argument>\n");

                                    continue;
                                }

                                String className = infoMessageArguments[j].getClass().getName();

                                // Ampersand needs to be the first, otherwise it would double-encode
                                // other entities.
                                className = className.replaceAll("&", "&amp;");
                                className = className.replaceAll("<", "&lt;");
                                className = className.replaceAll(">", "&gt;");

                                String value = infoMessageArguments[j].toString();

                                // Ampersand needs to be the first, otherwise it would double-encode
                                // other entities.
                                value = value.replaceAll("&", "&amp;");
                                value = value.replaceAll("<", "&lt;");
                                value = value.replaceAll(">", "&gt;");

                                writer.write("          <argument number=\"" + j + "\">\n");
                                writer.write("            <class>" + className + "</class>\n");
                                writer.write("            <value>" + value + "</value>\n");
                                writer.write("          </argument>\n");
                            }

                            writer.write("        </arguments>\n");
                        }

                        Exception exception = infoMessage.getException();

                        if (exception != null)
                        {
                            writer.write("        <exception>\n");

                            String className = exception.getClass().getName();

                            // Ampersand needs to be the first, otherwise it would double-encode
                            // other entities.
                            className = className.replaceAll("&", "&amp;");
                            className = className.replaceAll("<", "&lt;");
                            className = className.replaceAll(">", "&gt;");

                            writer.write("          <class>" + className + "</class>\n");

                            StringWriter stringWriter = new StringWriter();
                            PrintWriter printWriter = new PrintWriter(stringWriter);
                            exception.printStackTrace(printWriter);
                            String stackTrace = stringWriter.toString();

                            // Ampersand needs to be the first, otherwise it would double-encode
                            // other entities.
                            stackTrace = stackTrace.replaceAll("&", "&amp;");
                            stackTrace = stackTrace.replaceAll("<", "&lt;");
                            stackTrace = stackTrace.replaceAll(">", "&gt;");

                            writer.write("          <stack-trace>" + stackTrace + "</stack-trace>\n");
                            writer.write("        </exception>\n");
                        }

                        writer.write("      </info-message>\n");
                    }

                    writer.write("    </info-messages>\n");
                }

                writer.write("  </success>\n");
                writer.write("</hyperdex-1-workflow-result-information>\n");
                writer.flush();
                writer.close();
            }
            catch (FileNotFoundException ex)
            {
                ex.printStackTrace();
                System.exit(-1);
            }
            catch (UnsupportedEncodingException ex)
            {
                ex.printStackTrace();
                System.exit(-1);
            }
            catch (IOException ex)
            {
                ex.printStackTrace();
                System.exit(-1);
            }
        }
    }

    public int Run(String[] args)
    {
        this.outputFile = null;
        this.outputDimgraFile = null;

        if (args.length < 2)
        {
            throw constructTermination("messageArgumentsMissing", null, getI10nString("messageArgumentsMissingUsage") + "\n\thyperdex_1 " + getI10nString("messageParameterList") + "\n");
        }

        File resultInfoFile = new File(args[1]);

        try
        {
            resultInfoFile = resultInfoFile.getCanonicalFile();
        }
        catch (SecurityException ex)
        {
            throw constructTermination("messageResultInfoFileCantGetCanonicalPath", ex, null, resultInfoFile.getAbsolutePath());
        }
        catch (IOException ex)
        {
            throw constructTermination("messageResultInfoFileCantGetCanonicalPath", ex, null, resultInfoFile.getAbsolutePath());
        }

        if (resultInfoFile.exists() == true)
        {
            if (resultInfoFile.isFile() == true)
            {
                if (resultInfoFile.canWrite() != true)
                {
                    throw constructTermination("messageResultInfoFileIsntWritable", null, null, resultInfoFile.getAbsolutePath());
                }
            }
            else
            {
                throw constructTermination("messageResultInfoPathIsntAFile", null, null, resultInfoFile.getAbsolutePath());
            }
        }

        hyperdex_1.resultInfoFile = resultInfoFile;


        String programPath = hyperdex_1.class.getProtectionDomain().getCodeSource().getLocation().getPath();

        try
        {
            programPath = new File(programPath).getCanonicalPath() + File.separator;
            programPath = URLDecoder.decode(programPath, "UTF-8");
        }
        catch (UnsupportedEncodingException ex)
        {
            throw constructTermination("messageCantDetermineProgramPath", ex, null);
        }
        catch (IOException ex)
        {
            throw constructTermination("messageCantDetermineProgramPath", ex, null);
        }


        File jobFile = new File(args[0]);

        try
        {
            jobFile = jobFile.getCanonicalFile();
        }
        catch (SecurityException ex)
        {
            throw constructTermination("messageJobFileCantGetCanonicalPath", ex, null, jobFile.getAbsolutePath());
        }
        catch (IOException ex)
        {
            throw constructTermination("messageJobFileCantGetCanonicalPath", ex, null, jobFile.getAbsolutePath());
        }

        if (jobFile.exists() != true)
        {
            throw constructTermination("messageJobFileDoesntExist", null, null, jobFile.getAbsolutePath());
        }

        if (jobFile.isFile() != true)
        {
            throw constructTermination("messageJobPathIsntAFile", null, null, jobFile.getAbsolutePath());
        }

        if (jobFile.canRead() != true)
        {
            throw constructTermination("messageJobFileIsntReadable", null, null, jobFile.getAbsolutePath());
        }

        System.out.println("hyperdex_1 workflow: " + getI10nStringFormatted("messageCallDetails", jobFile.getAbsolutePath(), resultInfoFile.getAbsolutePath()));


        File outputDirectory = null;
        File inputFile = null;
        File tempDirectory = null;
        String outputDirectorySelectionStartDirectory = null;
        String inputFileSelectionStartDirectory = null;
        Map<String, String> fileExtensions = new LinkedHashMap<String, String>();

        try
        {
            XMLInputFactory inputFactory = XMLInputFactory.newInstance();
            InputStream in = new FileInputStream(jobFile);
            XMLEventReader eventReader = inputFactory.createXMLEventReader(in);

            while (eventReader.hasNext() == true)
            {
                XMLEvent event = eventReader.nextEvent();

                if (event.isStartElement() == true)
                {
                    String elementName = event.asStartElement().getName().getLocalPart();

                    if (elementName.equals("output-directory") == true)
                    {
                        Attribute attributePath = event.asStartElement().getAttributeByName(new QName("path"));

                        if (attributePath == null)
                        {
                            throw constructTermination("messageJobFileEntryIsMissingAnAttribute", null, null, jobFile.getAbsolutePath(), elementName, "path");
                        }

                        if (outputDirectory != null)
                        {
                            throw constructTermination("messageJobFileElementConfiguredMoreThanOnce", null, null, jobFile.getAbsolutePath(), elementName);
                        }

                        outputDirectory = new File(attributePath.getValue());

                        if (outputDirectory.isAbsolute() != true)
                        {
                            outputDirectory = new File(jobFile.getAbsoluteFile().getParent() + File.separator + attributePath.getValue());
                        }

                        try
                        {
                            outputDirectory = outputDirectory.getCanonicalFile();
                        }
                        catch (SecurityException ex)
                        {
                            throw constructTermination("messageJobFileOutputDirectoryCantGetCanonicalPath", ex, null, jobFile.getAbsolutePath(), outputDirectory.getAbsolutePath());
                        }
                        catch (IOException ex)
                        {
                            throw constructTermination("messageJobFileOutputDirectoryCantGetCanonicalPath", ex, null, jobFile.getAbsolutePath(), outputDirectory.getAbsolutePath());
                        }
                    }
                    else if (elementName.equals("output-directory-selection-start-directory") == true)
                    {
                        Attribute pathAttribute = event.asStartElement().getAttributeByName(new QName("path"));

                        if (pathAttribute == null)
                        {
                            throw constructTermination("messageJobFileEntryIsMissingAnAttribute", null, null, jobFile.getAbsolutePath(), elementName, "path");
                        }

                        if (outputDirectorySelectionStartDirectory != null)
                        {
                            throw constructTermination("messageJobFileElementConfiguredMoreThanOnce", null, null, jobFile.getAbsolutePath(), elementName);
                        }

                        File selectionStartDirectory = new File(pathAttribute.getValue());

                        if (selectionStartDirectory.isAbsolute() != true)
                        {
                            selectionStartDirectory = new File(jobFile.getAbsoluteFile().getParent() + File.separator + pathAttribute.getValue());
                        }

                        try
                        {
                            selectionStartDirectory = selectionStartDirectory.getCanonicalFile();
                        }
                        catch (SecurityException ex)
                        {
                            throw constructTermination("messageJobFileStartDirectoryCantGetCanonicalPath", ex, null, jobFile.getAbsolutePath(), selectionStartDirectory.getAbsolutePath());
                        }
                        catch (IOException ex)
                        {
                            throw constructTermination("messageJobFileStartDirectoryCantGetCanonicalPath", ex, null, jobFile.getAbsolutePath(), selectionStartDirectory.getAbsolutePath());
                        }

                        outputDirectorySelectionStartDirectory = selectionStartDirectory.getAbsolutePath();
                    }
                    else if (elementName.equals("input-file") == true)
                    {
                        if (inputFile != null)
                        {
                            throw constructTermination("messageJobFileElementConfiguredMoreThanOnce", null, null, jobFile.getAbsolutePath(), elementName);
                        }

                        Attribute attributePath = event.asStartElement().getAttributeByName(new QName("path"));

                        if (attributePath == null)
                        {
                            throw constructTermination("messageJobFileEntryIsMissingAnAttribute", null, null, jobFile.getAbsolutePath(), elementName, "path");
                        }

                        inputFile = new File(attributePath.getValue());

                        if (inputFile.isAbsolute() != true)
                        {
                            inputFile = new File(jobFile.getAbsoluteFile().getParent() + File.separator + attributePath.getValue());
                        }

                        try
                        {
                            inputFile = inputFile.getCanonicalFile();
                        }
                        catch (SecurityException ex)
                        {
                            throw constructTermination("messageJobFileInputFileCantGetCanonicalPath", ex, null, jobFile.getAbsolutePath(), inputFile.getAbsolutePath());
                        }
                        catch (IOException ex)
                        {
                            throw constructTermination("messageJobFileInputFileCantGetCanonicalPath", ex, null, jobFile.getAbsolutePath(), inputFile.getAbsolutePath());
                        }

                        if (inputFile.exists() != true)
                        {
                            throw constructTermination("messageJobFileInputFileDoesntExist", null, null, jobFile.getAbsolutePath(), inputFile.getAbsolutePath());
                        }

                        if (inputFile.isFile() != true)
                        {
                            throw constructTermination("messageJobFileInputPathIsntAFile", null, null, jobFile.getAbsolutePath(), inputFile.getAbsolutePath());
                        }

                        if (inputFile.canRead() != true)
                        {
                            throw constructTermination("messageJobFileInputFileIsntReadable", null, null, jobFile.getAbsolutePath(), inputFile.getAbsolutePath());
                        }
                    }
                    else if (elementName.equals("input-file-selection-start-directory") == true)
                    {
                        Attribute pathAttribute = event.asStartElement().getAttributeByName(new QName("path"));

                        if (pathAttribute == null)
                        {
                            throw constructTermination("messageJobFileEntryIsMissingAnAttribute", null, null, jobFile.getAbsolutePath(), elementName, "path");
                        }

                        if (inputFileSelectionStartDirectory != null)
                        {
                            throw constructTermination("messageJobFileElementConfiguredMoreThanOnce", null, null, jobFile.getAbsolutePath(), elementName);
                        }

                        File selectionStartDirectory = new File(pathAttribute.getValue());

                        if (selectionStartDirectory.isAbsolute() != true)
                        {
                            selectionStartDirectory = new File(jobFile.getAbsoluteFile().getParent() + File.separator + pathAttribute.getValue());
                        }

                        inputFileSelectionStartDirectory = selectionStartDirectory.getAbsolutePath();
                    }
                    else if (elementName.equals("temp-directory") == true)
                    {
                        if (tempDirectory != null)
                        {
                            throw constructTermination("messageJobFileElementConfiguredMoreThanOnce", null, null, jobFile.getAbsolutePath(), elementName);
                        }

                        Attribute attributePath = event.asStartElement().getAttributeByName(new QName("path"));

                        if (attributePath == null)
                        {
                            throw constructTermination("messageJobFileEntryIsMissingAnAttribute", null, null, jobFile.getAbsolutePath(), elementName, "path");
                        }

                        tempDirectory = new File(attributePath.getValue());

                        if (tempDirectory.isAbsolute() != true)
                        {
                            tempDirectory = new File(jobFile.getAbsoluteFile().getParent() + File.separator + attributePath.getValue());
                        }
                    }
                    else if (elementName.equals("input-file-selection-file-type") == true)
                    {
                        Attribute attributeExtension = event.asStartElement().getAttributeByName(new QName("extension"));

                        if (attributeExtension == null)
                        {
                            throw constructTermination("messageJobFileEntryIsMissingAnAttribute", null, null, jobFile.getAbsolutePath(), elementName, "extension");
                        }

                        String extension = attributeExtension.getValue();
                        String extensionDisplayName = new String();

                        while (eventReader.hasNext() == true)
                        {
                            event = eventReader.nextEvent();

                            if (event.isCharacters() == true)
                            {
                                extensionDisplayName += event.asCharacters();
                            }
                            else if (event.isEndElement() == true)
                            {
                                QName elementEndName = event.asEndElement().getName();
                                String elementEndNameString = elementEndName.getLocalPart();

                                if (elementEndNameString.equalsIgnoreCase("input-file-selection-file-type") == true)
                                {
                                    break;
                                }
                            }
                        }

                        if (fileExtensions.containsKey(extension) != true)
                        {
                            fileExtensions.put(extension, extensionDisplayName);
                        }
                        else
                        {
                            throw constructTermination("messageJobFileInputFileSelectionExtensionSpecifiedMoreThanOnce", null, null, jobFile.getAbsolutePath(), extension);
                        }
                    }
                }
            }
        }
        catch (XMLStreamException ex)
        {
            throw constructTermination("messageJobFileErrorWhileReading", ex, null, jobFile.getAbsolutePath());
        }
        catch (SecurityException ex)
        {
            throw constructTermination("messageJobFileErrorWhileReading", ex, null, jobFile.getAbsolutePath());
        }
        catch (IOException ex)
        {
            throw constructTermination("messageJobFileErrorWhileReading", ex, null, jobFile.getAbsolutePath());
        }


        if (tempDirectory == null)
        {
            tempDirectory = new File(programPath + "temp");
        }

        try
        {
            tempDirectory = tempDirectory.getCanonicalFile();
        }
        catch (SecurityException ex)
        {
            throw constructTermination("messageTempDirectoryCantGetCanonicalPath", ex, null, tempDirectory.getAbsolutePath());
        }
        catch (IOException ex)
        {
            throw constructTermination("messageTempDirectoryCantGetCanonicalPath", ex, null, tempDirectory.getAbsolutePath());
        }

        if (tempDirectory.exists() == true)
        {
            if (tempDirectory.isDirectory() == true)
            {
                if (tempDirectory.canWrite() != true)
                {
                    throw constructTermination("messageTempDirectoryIsntWritable", null, null, tempDirectory.getAbsolutePath());
                }
            }
            else
            {
                throw constructTermination("messageTempPathIsntADirectory", null, null, tempDirectory.getAbsolutePath());
            }
        }
        else
        {
            try
            {
                tempDirectory.mkdirs();
            }
            catch (SecurityException ex)
            {
                throw constructTermination("messageTempDirectoryCantCreate", ex, null, tempDirectory.getAbsolutePath());
            }
        }

        if (outputDirectory != null)
        {
            if (outputDirectory.exists() == true)
            {
                if (outputDirectory.isDirectory() == true)
                {
                    if (outputDirectory.canWrite() != true)
                    {
                        throw constructTermination("messageJobFileOutputDirectoryIsntWritable", null, null, jobFile.getAbsolutePath(), outputDirectory.getAbsolutePath());
                    }
                }
                else
                {
                    throw constructTermination("messageJobFileOutputPathIsntADirectory", null, null, jobFile.getAbsolutePath(), outputDirectory.getAbsolutePath());
                }
            }
            else
            {
                try
                {
                    outputDirectory.mkdirs();
                }
                catch (SecurityException ex)
                {
                    throw constructTermination("messageJobFileOutputDirectoryCantCreate", ex, null, jobFile.getAbsolutePath(), outputDirectory.getAbsolutePath());
                }
            }
        }
        else
        {
            File filePicker1OutputDirectoryJobFile = new File(tempDirectory.getAbsolutePath() + File.separator + "jobfile_file_picker_1_output.xml");

            if (filePicker1OutputDirectoryJobFile.exists() == true)
            {
                if (filePicker1OutputDirectoryJobFile.isFile() == true)
                {
                    boolean deleteSuccessful = false;

                    try
                    {
                        deleteSuccessful = filePicker1OutputDirectoryJobFile.delete();
                    }
                    catch (SecurityException ex)
                    {

                    }

                    if (deleteSuccessful != true)
                    {
                        if (filePicker1OutputDirectoryJobFile.canWrite() != true)
                        {
                            throw constructTermination("messageFilePicker1OutputDirectoryJobFileExistsButIsntWritable", null, null, filePicker1OutputDirectoryJobFile.getAbsolutePath());
                        }
                    }
                }
                else
                {
                    throw constructTermination("messageFilePicker1OutputDirectoryJobPathExistsButIsntAFile", null, null, filePicker1OutputDirectoryJobFile.getAbsolutePath());
                }
            }

            File filePicker1OutputDirectoryResultInfoFile = new File(tempDirectory.getAbsolutePath() + File.separator + "resultinfo_file_picker_1_output.xml");

            if (filePicker1OutputDirectoryResultInfoFile.exists() == true)
            {
                if (filePicker1OutputDirectoryResultInfoFile.isFile() == true)
                {
                    boolean deleteSuccessful = false;

                    try
                    {
                        deleteSuccessful = filePicker1OutputDirectoryResultInfoFile.delete();
                    }
                    catch (SecurityException ex)
                    {

                    }

                    if (deleteSuccessful != true)
                    {
                        if (filePicker1OutputDirectoryResultInfoFile.canWrite() != true)
                        {
                            throw constructTermination("messageFilePicker1OutputDirectoryResultInfoFileExistsButIsntWritable", null, null, filePicker1OutputDirectoryResultInfoFile.getAbsolutePath());
                        }
                    }
                }
                else
                {
                    throw constructTermination("messageFilePicker1OutputDirectoryResultInfoPathExistsButIsntAFile", null, null, filePicker1OutputDirectoryResultInfoFile.getAbsolutePath());
                }
            }

            try
            {
                BufferedWriter writer = new BufferedWriter(
                                        new OutputStreamWriter(
                                        new FileOutputStream(filePicker1OutputDirectoryJobFile),
                                        "UTF-8"));

                writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
                writer.write("<!-- This file was created by hyperdex_1 workflow, which is free software licensed under the GNU Affero General Public License 3 or any later version (see https://gitlab.com/publishing-systems/digital_publishing_workflow_tools/ and https://hypertext-systems.org). -->\n");
                writer.write("<file-picker-1-jobfile>\n");
                writer.write("  <dialog-title>" + getI10nString("windowTitleSelectOutputDirectory") + "</dialog-title>\n");

                if (outputDirectorySelectionStartDirectory != null)
                {
                    writer.write("  <start-directory path=\"" + outputDirectorySelectionStartDirectory + "\"/>\n");
                }

                writer.write("  <directories-only/>\n");
                writer.write("</file-picker-1-jobfile>\n");

                writer.flush();
                writer.close();
            }
            catch (FileNotFoundException ex)
            {
                throw constructTermination("messageFilePicker1OutputDirectoryJobFileWritingError", ex, null, filePicker1OutputDirectoryJobFile.getAbsolutePath());
            }
            catch (UnsupportedEncodingException ex)
            {
                throw constructTermination("messageFilePicker1OutputDirectoryJobFileWritingError", ex, null, filePicker1OutputDirectoryJobFile.getAbsolutePath());
            }
            catch (IOException ex)
            {
                throw constructTermination("messageFilePicker1OutputDirectoryJobFileWritingError", ex, null, filePicker1OutputDirectoryJobFile.getAbsolutePath());
            }

            ProcessBuilder builder = new ProcessBuilder("java", "file_picker_1", filePicker1OutputDirectoryJobFile.getAbsolutePath(), filePicker1OutputDirectoryResultInfoFile.getAbsolutePath());
            builder.directory(new File(programPath + File.separator + ".." + File.separator + ".." + File.separator + ".." + File.separator + ".." + File.separator + "gui" + File.separator + "file_picker" + File.separator + "file_picker_1"));
            builder.redirectErrorStream(true);

            try
            {
                Process process = builder.start();
                Scanner scanner = new Scanner(process.getInputStream()).useDelimiter("\n");

                while (scanner.hasNext() == true)
                {
                    System.out.println(scanner.next());
                }

                scanner.close();
            }
            catch (IOException ex)
            {
                throw constructTermination("messageFilePicker1OutputDirectoryErrorWhileReadingOutput", ex, null);
            }

            if (filePicker1OutputDirectoryResultInfoFile.exists() != true)
            {
                throw constructTermination("messageFilePicker1OutputDirectoryResultInfoFileDoesntExistButShould", null, null, filePicker1OutputDirectoryResultInfoFile.getAbsolutePath());
            }

            if (filePicker1OutputDirectoryResultInfoFile.isFile() != true)
            {
                throw constructTermination("messageFilePicker1OutputDirectoryResultInfoPathExistsButIsntAFile", null, null, filePicker1OutputDirectoryResultInfoFile.getAbsolutePath());
            }

            if (filePicker1OutputDirectoryResultInfoFile.canRead() != true)
            {
                throw constructTermination("messageFilePicker1OutputDirectoryResultInfoFileIsntReadable", null, null, filePicker1OutputDirectoryResultInfoFile.getAbsolutePath());
            }

            boolean wasSuccess = false;

            try
            {
                XMLInputFactory inputFactory = XMLInputFactory.newInstance();
                InputStream in = new FileInputStream(filePicker1OutputDirectoryResultInfoFile);
                XMLEventReader eventReader = inputFactory.createXMLEventReader(in);

                while (eventReader.hasNext() == true)
                {
                    XMLEvent event = eventReader.nextEvent();

                    if (event.isStartElement() == true)
                    {
                        String elementName = event.asStartElement().getName().getLocalPart();

                        if (elementName.equals("success") == true)
                        {
                            wasSuccess = true;
                        }
                        else if (elementName.equals("selected-file") == true)
                        {
                            if (outputDirectory != null)
                            {
                                throw constructTermination("messageFilePicker1OutputDirectoryResultInfoFileElementConfiguredMoreThanOnce", null, null, filePicker1OutputDirectoryResultInfoFile.getAbsolutePath(), elementName);
                            }

                            String outputDirectoryString = new String();

                            while (eventReader.hasNext() == true)
                            {
                                event = eventReader.nextEvent();

                                if (event.isCharacters() == true)
                                {
                                    outputDirectoryString += event.asCharacters();
                                }
                                else if (event.isEndElement() == true)
                                {
                                    if (event.asEndElement().getName().getLocalPart().equals("selected-file") == true)
                                    {
                                        break;
                                    }
                                }
                            }

                            outputDirectory = new File(outputDirectoryString);

                            if (outputDirectory.isAbsolute() != true)
                            {
                                outputDirectory = new File(filePicker1OutputDirectoryResultInfoFile.getAbsoluteFile().getParent() + File.separator + outputDirectoryString);
                            }

                            try
                            {
                                outputDirectory = outputDirectory.getCanonicalFile();
                            }
                            catch (SecurityException ex)
                            {
                                throw constructTermination("messageFilePicker1OutputDirectoryResultInfoFileOutputDirectoryCantGetCanonicalPath", ex, null, filePicker1OutputDirectoryResultInfoFile.getAbsolutePath(), outputDirectory.getAbsolutePath());
                            }
                            catch (IOException ex)
                            {
                                throw constructTermination("messageFilePicker1OutputDirectoryResultInfoFileOutputDirectoryCantGetCanonicalPath", ex, null, filePicker1OutputDirectoryResultInfoFile.getAbsolutePath(), outputDirectory.getAbsolutePath());
                            }

                            if (outputDirectory.exists() == true)
                            {
                                if (outputDirectory.isDirectory() == true)
                                {
                                    if (outputDirectory.canWrite() != true)
                                    {
                                        throw constructTermination("messageFilePicker1OutputDirectoryResultInfoFileOutputDirectoryIsntWritable", null, null, filePicker1OutputDirectoryResultInfoFile.getAbsolutePath(), outputDirectory.getAbsolutePath());
                                    }
                                }
                                else
                                {
                                    throw constructTermination("messageFilePicker1OutputDirectoryResultInfoFileOutputPathIsntADirectory", null, null, filePicker1OutputDirectoryResultInfoFile.getAbsolutePath(), outputDirectory.getAbsolutePath());
                                }
                            }
                            else
                            {
                                try
                                {
                                    outputDirectory.mkdirs();
                                }
                                catch (SecurityException ex)
                                {
                                    throw constructTermination("messageFilePicker1OutputDirectoryResultInfoFileOutputDirectoryCantCreate", ex, null, filePicker1OutputDirectoryResultInfoFile.getAbsolutePath(), outputDirectory.getAbsolutePath());
                                }
                            }
                        }
                    }
                }
            }
            catch (XMLStreamException ex)
            {
                throw constructTermination("messageFilePicker1OutputDirectoryResultInfoFileErrorWhileReading", ex, null, filePicker1OutputDirectoryResultInfoFile.getAbsolutePath());
            }
            catch (SecurityException ex)
            {
                throw constructTermination("messageFilePicker1OutputDirectoryResultInfoFileErrorWhileReading", ex, null, filePicker1OutputDirectoryResultInfoFile.getAbsolutePath());
            }
            catch (IOException ex)
            {
                throw constructTermination("messageFilePicker1OutputDirectoryResultInfoFileErrorWhileReading", ex, null, filePicker1OutputDirectoryResultInfoFile.getAbsolutePath());
            }

            if (wasSuccess != true)
            {
                throw constructTermination("messageFilePicker1OutputDirectoryCallWasntSuccessful", null, null);
            }

            if (outputDirectory == null)
            {
                throw constructTermination("messageFilePicker1OutputDirectoryResultInfoFileSelectedDirectoryIsntConfigured", null, null, filePicker1OutputDirectoryResultInfoFile.getAbsolutePath());
            }
        }

        this.outputFile = new File(outputDirectory.getAbsolutePath() + File.separator + "output.xml");

        if (this.outputFile.exists() == true)
        {
            throw constructTermination("messageOutputDirectoryOutputFilePathAlreadyExists", null, null, outputDirectory.getAbsolutePath(), this.outputFile.getAbsolutePath());
        }

        this.outputDimgraFile = new File(outputDirectory.getAbsolutePath() + File.separator + "output.xhtml");

        if (this.outputDimgraFile.exists() == true)
        {
            throw constructTermination("messageOutputDirectoryOutputDimgraPathAlreadyExists", null, null, outputDirectory.getAbsolutePath(), this.outputDimgraFile.getAbsolutePath());
        }

        if (inputFile == null)
        {
            String localeExtension = new String();

            {
                Locale currentLocale = getLocale();

                if (this.l10nConsole != null)
                {
                    currentLocale = this.l10nConsole.getLocale();
                }

                localeExtension = currentLocale.toString();

                if (localeExtension.length() > 0)
                {
                    localeExtension = "_" + localeExtension;

                    if (new File(programPath + "jobfile_option_picker_1" + localeExtension + ".xml").exists() != true)
                    {
                        localeExtension = new String();
                    }
                }
            }

            File optionPicker1JobFile = new File(programPath + "jobfile_option_picker_1" + localeExtension + ".xml");
            File optionPicker1ResultInfoFile = new File(tempDirectory.getAbsolutePath() + File.separator + "resultinfo_option_picker_1.xml");

            if (optionPicker1ResultInfoFile.exists() == true)
            {
                if (optionPicker1ResultInfoFile.isFile() == true)
                {
                    boolean deleteSuccessful = false;

                    try
                    {
                        deleteSuccessful = optionPicker1ResultInfoFile.delete();
                    }
                    catch (SecurityException ex)
                    {

                    }

                    if (deleteSuccessful != true)
                    {
                        if (optionPicker1ResultInfoFile.canWrite() != true)
                        {
                            throw constructTermination("messageOptionPicker1ResultInfoFileExistsButIsntWritable", null, null, optionPicker1ResultInfoFile.getAbsolutePath());
                        }
                    }
                }
                else
                {
                    throw constructTermination("messageOptionPicker1ResultInfoPathExistsButIsntAFile", null, null, optionPicker1ResultInfoFile.getAbsolutePath());
                }
            }

            ProcessBuilder builder = new ProcessBuilder("java", "option_picker_1", optionPicker1JobFile.getAbsolutePath(), optionPicker1ResultInfoFile.getAbsolutePath());
            builder.directory(new File(programPath + File.separator + ".." + File.separator + ".." + File.separator + ".." + File.separator + ".." + File.separator + "gui" + File.separator + "option_picker" + File.separator + "option_picker_1"));
            builder.redirectErrorStream(true);

            try
            {
                Process process = builder.start();
                Scanner scanner = new Scanner(process.getInputStream()).useDelimiter("\n");

                while (scanner.hasNext() == true)
                {
                    System.out.println(scanner.next());
                }

                scanner.close();
            }
            catch (IOException ex)
            {
                throw constructTermination("messageOptionPicker1ErrorWhileReadingOutput", ex, null);
            }

            if (optionPicker1ResultInfoFile.exists() != true)
            {
                throw constructTermination("messageOptionPicker1ResultInfoFileDoesntExistButShould", null, null, optionPicker1ResultInfoFile.getAbsolutePath());
            }

            if (optionPicker1ResultInfoFile.isFile() != true)
            {
                throw constructTermination("messageOptionPicker1ResultInfoPathExistsButIsntAFile", null, null, optionPicker1ResultInfoFile.getAbsolutePath());
            }

            if (optionPicker1ResultInfoFile.canRead() != true)
            {
                throw constructTermination("messageOptionPicker1ResultInfoFileIsntReadable", null, null, optionPicker1ResultInfoFile.getAbsolutePath());
            }

            String selectedOptionId = null;
            boolean wasSuccess = false;

            try
            {
                XMLInputFactory inputFactory = XMLInputFactory.newInstance();
                InputStream in = new FileInputStream(optionPicker1ResultInfoFile);
                XMLEventReader eventReader = inputFactory.createXMLEventReader(in);

                while (eventReader.hasNext() == true)
                {
                    XMLEvent event = eventReader.nextEvent();

                    if (event.isStartElement() == true)
                    {
                        String elementName = event.asStartElement().getName().getLocalPart();

                        if (elementName.equals("success") == true)
                        {
                            wasSuccess = true;
                        }
                        else if (elementName.equals("selected-option-id") == true)
                        {
                            selectedOptionId = new String();

                            while (eventReader.hasNext() == true)
                            {
                                event = eventReader.nextEvent();

                                if (event.isCharacters() == true)
                                {
                                    selectedOptionId += event.asCharacters();
                                }
                                else if (event.isEndElement() == true)
                                {
                                    if (event.asEndElement().getName().getLocalPart().equals("selected-option-id") == true)
                                    {
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch (XMLStreamException ex)
            {
                throw constructTermination("messageOptionPicker1ResultInfoFileErrorWhileReading", ex, null, optionPicker1ResultInfoFile.getAbsolutePath());
            }
            catch (SecurityException ex)
            {
                throw constructTermination("messageOptionPicker1ResultInfoFileErrorWhileReading", ex, null, optionPicker1ResultInfoFile.getAbsolutePath());
            }
            catch (IOException ex)
            {
                throw constructTermination("messageOptionPicker1ResultInfoFileErrorWhileReading", ex, null, optionPicker1ResultInfoFile.getAbsolutePath());
            }

            if (wasSuccess != true)
            {
                throw constructTermination("messageOptionPicker1CallWasntSuccessful", null, null);
            }

            if (selectedOptionId == null)
            {
                this.infoMessages.add(constructInfoMessage("messageOptionPicker1CallAborted", true, null, null));
                return 1;
            }

            if (selectedOptionId.equals("new-file") == true)
            {
                inputFile = null;
            }
            else if (selectedOptionId.equals("existing-file") == true)
            {
                File filePicker1InputFileJobFile = new File(tempDirectory.getAbsolutePath() + File.separator + "jobfile_file_picker_1_input.xml");

                if (filePicker1InputFileJobFile.exists() == true)
                {
                    if (filePicker1InputFileJobFile.isFile() == true)
                    {
                        boolean deleteSuccessful = false;

                        try
                        {
                            deleteSuccessful = filePicker1InputFileJobFile.delete();
                        }
                        catch (SecurityException ex)
                        {

                        }

                        if (deleteSuccessful != true)
                        {
                            if (filePicker1InputFileJobFile.canWrite() != true)
                            {
                                throw constructTermination("messageFilePicker1InputFileJobFileExistsButIsntWritable", null, null, filePicker1InputFileJobFile.getAbsolutePath());
                            }
                        }
                    }
                    else
                    {
                        throw constructTermination("messageFilePicker1InputFileJobPathExistsButIsntAFile", null, null, filePicker1InputFileJobFile.getAbsolutePath());
                    }
                }

                File filePicker1InputFileResultInfoFile = new File(tempDirectory.getAbsolutePath() + File.separator + "resultinfo_file_picker_1_input.xml");

                if (filePicker1InputFileResultInfoFile.exists() == true)
                {
                    if (filePicker1InputFileResultInfoFile.isFile() == true)
                    {
                        boolean deleteSuccessful = false;

                        try
                        {
                            deleteSuccessful = filePicker1InputFileResultInfoFile.delete();
                        }
                        catch (SecurityException ex)
                        {

                        }

                        if (deleteSuccessful != true)
                        {
                            if (filePicker1InputFileResultInfoFile.canWrite() != true)
                            {
                                throw constructTermination("messageFilePicker1InputFileResultInfoFileExistsButIsntWritable", null, null, filePicker1InputFileResultInfoFile.getAbsolutePath());
                            }
                        }
                    }
                    else
                    {
                        throw constructTermination("messageFilePicker1InputFileResultInfoPathExistsButIsntAFile", null, null, filePicker1InputFileResultInfoFile.getAbsolutePath());
                    }
                }

                try
                {
                    BufferedWriter writer = new BufferedWriter(
                                            new OutputStreamWriter(
                                            new FileOutputStream(filePicker1InputFileJobFile),
                                            "UTF-8"));

                    writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
                    writer.write("<!-- This file was created by hyperdex_1 workflow, which is free software licensed under the GNU Affero General Public License 3 or any later version (see https://gitlab.com/publishing-systems/digital_publishing_workflow_tools/ and https://hypertext-systems.org). -->\n");
                    writer.write("<file-picker-1-jobfile>\n");
                    writer.write("  <dialog-title>" + getI10nString("windowTitleSelectInputFile") + "</dialog-title>\n");

                    if (inputFileSelectionStartDirectory != null)
                    {
                        writer.write("  <start-directory path=\"" + inputFileSelectionStartDirectory + "\"/>\n");
                    }

                    for (Map.Entry<String, String> entry : fileExtensions.entrySet())
                    {
                        writer.write("  <file-type extension=\"" + entry.getKey() + "\">" + entry.getValue() + "</file-type>\n");
                    }

                    writer.write("</file-picker-1-jobfile>\n");

                    writer.flush();
                    writer.close();
                }
                catch (FileNotFoundException ex)
                {
                    throw constructTermination("messageFilePicker1InputFileJobFileWritingError", ex, null, filePicker1InputFileJobFile.getAbsolutePath());
                }
                catch (UnsupportedEncodingException ex)
                {
                    throw constructTermination("messageFilePicker1InputFileJobFileWritingError", ex, null, filePicker1InputFileJobFile.getAbsolutePath());
                }
                catch (IOException ex)
                {
                    throw constructTermination("messageFilePicker1InputFileJobFileWritingError", ex, null, filePicker1InputFileJobFile.getAbsolutePath());
                }

                builder = new ProcessBuilder("java", "file_picker_1", filePicker1InputFileJobFile.getAbsolutePath(), filePicker1InputFileResultInfoFile.getAbsolutePath());
                builder.directory(new File(programPath + File.separator + ".." + File.separator + ".." + File.separator + ".." + File.separator + ".." + File.separator + "gui" + File.separator + "file_picker" + File.separator + "file_picker_1"));
                builder.redirectErrorStream(true);

                try
                {
                    Process process = builder.start();
                    Scanner scanner = new Scanner(process.getInputStream()).useDelimiter("\n");

                    while (scanner.hasNext() == true)
                    {
                        System.out.println(scanner.next());
                    }

                    scanner.close();
                }
                catch (IOException ex)
                {
                    throw constructTermination("messageFilePicker1InputFileErrorWhileReadingOutput", ex, null);
                }

                if (filePicker1InputFileResultInfoFile.exists() != true)
                {
                    throw constructTermination("messageFilePicker1InputFileResultInfoFileDoesntExistButShould", null, null, filePicker1InputFileResultInfoFile.getAbsolutePath());
                }

                if (filePicker1InputFileResultInfoFile.isFile() != true)
                {
                    throw constructTermination("messageFilePicker1InputFileResultInfoPathExistsButIsntAFile", null, null, filePicker1InputFileResultInfoFile.getAbsolutePath());
                }

                if (filePicker1InputFileResultInfoFile.canRead() != true)
                {
                    throw constructTermination("messageFilePicker1InputFileResultInfoFileIsntReadable", null, null, filePicker1InputFileResultInfoFile.getAbsolutePath());
                }

                wasSuccess = false;

                try
                {
                    XMLInputFactory inputFactory = XMLInputFactory.newInstance();
                    InputStream in = new FileInputStream(filePicker1InputFileResultInfoFile);
                    XMLEventReader eventReader = inputFactory.createXMLEventReader(in);

                    while (eventReader.hasNext() == true)
                    {
                        XMLEvent event = eventReader.nextEvent();

                        if (event.isStartElement() == true)
                        {
                            String elementName = event.asStartElement().getName().getLocalPart();

                            if (elementName.equals("success") == true)
                            {
                                wasSuccess = true;
                            }
                            else if (elementName.equals("selected-file") == true)
                            {
                                if (inputFile != null)
                                {
                                    throw constructTermination("messageFilePicker1InputFileResultInfoFileElementConfiguredMoreThanOnce", null, null, filePicker1InputFileResultInfoFile.getAbsolutePath(), elementName);
                                }

                                String inputFileString = new String();

                                while (eventReader.hasNext() == true)
                                {
                                    event = eventReader.nextEvent();

                                    if (event.isCharacters() == true)
                                    {
                                        inputFileString += event.asCharacters();
                                    }
                                    else if (event.isEndElement() == true)
                                    {
                                        if (event.asEndElement().getName().getLocalPart().equals("selected-file") == true)
                                        {
                                            break;
                                        }
                                    }
                                }

                                inputFile = new File(inputFileString);

                                if (inputFile.isAbsolute() != true)
                                {
                                    inputFile = new File(filePicker1InputFileResultInfoFile.getAbsoluteFile().getParent() + File.separator + inputFileString);
                                }

                                try
                                {
                                    inputFile = inputFile.getCanonicalFile();
                                }
                                catch (SecurityException ex)
                                {
                                    throw constructTermination("messageFilePicker1InputFileResultInfoFileCantGetCanonicalPath", ex, null, filePicker1InputFileResultInfoFile.getAbsolutePath(), inputFile.getAbsolutePath());
                                }
                                catch (IOException ex)
                                {
                                    throw constructTermination("messageFilePicker1InputFileResultInfoFileCantGetCanonicalPath", ex, null, filePicker1InputFileResultInfoFile.getAbsolutePath(), inputFile.getAbsolutePath());
                                }

                                if (inputFile.exists() != true)
                                {
                                    throw constructTermination("messageFilePicker1InputFileResultInfoFileSelectedFileDoesntExist", null, null, filePicker1InputFileResultInfoFile.getAbsolutePath(), inputFile.getAbsolutePath());
                                }

                                if (inputFile.isFile() != true)
                                {
                                    throw constructTermination("messageFilePicker1InputFileResultInfoFileSelectedPathIsntAFile", null, null, filePicker1InputFileResultInfoFile.getAbsolutePath(), inputFile.getAbsolutePath());
                                }

                                if (inputFile.canRead() != true)
                                {
                                    throw constructTermination("messageFilePicker1InputFileResultInfoFileSelectedFileIsntReadable", null, null, filePicker1InputFileResultInfoFile.getAbsolutePath(), inputFile.getAbsolutePath());
                                }
                            }
                        }
                    }
                }
                catch (XMLStreamException ex)
                {
                    throw constructTermination("messageFilePicker1InputFileResultInfoFileErrorWhileReading", ex, null, filePicker1InputFileResultInfoFile.getAbsolutePath());
                }
                catch (SecurityException ex)
                {
                    throw constructTermination("messageFilePicker1InputFileResultInfoFileErrorWhileReading", ex, null, filePicker1InputFileResultInfoFile.getAbsolutePath());
                }
                catch (IOException ex)
                {
                    throw constructTermination("messageFilePicker1InputFileResultInfoFileErrorWhileReading", ex, null, filePicker1InputFileResultInfoFile.getAbsolutePath());
                }

                if (wasSuccess != true)
                {
                    throw constructTermination("messageFilePicker1InputFileCallWasntSuccessful", null, null);
                }

                if (inputFile == null)
                {
                    throw constructTermination("messageFilePicker1InputFileResultInfoFileSelectedFileIsntConfigured", null, null, filePicker1InputFileResultInfoFile.getAbsolutePath());
                }

                {
                    boolean inputFileHasGraphML = false;
                    boolean inputFileHasNodeTitle = false;
                    boolean inputFileHasDimension = false;

                    try
                    {
                        XMLInputFactory inputFactory = XMLInputFactory.newInstance();
                        inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
                        inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
                        InputStream in = new FileInputStream(inputFile);
                        XMLEventReader eventReader = inputFactory.createXMLEventReader(in);

                        while (eventReader.hasNext() == true)
                        {
                            XMLEvent event = eventReader.nextEvent();

                            if (event.isStartElement() == true)
                            {
                                if (inputFileHasGraphML == false)
                                {
                                    // http://coding.derkeiler.com/Archive/Java/comp.lang.java.help/2008-12/msg00090.html
                                    @SuppressWarnings("unchecked")
                                    Iterator<Namespace> iterNamespace = (Iterator<Namespace>)event.asStartElement().getNamespaces();

                                    while (iterNamespace.hasNext())
                                    {
                                        if (iterNamespace.next().getNamespaceURI().equals("http://graphml.graphdrawing.org/xmlns") == true)
                                        {
                                            inputFileHasGraphML = true;
                                            inputFileHasNodeTitle = false;
                                            inputFileHasDimension = false;
                                            break;
                                        }
                                    }
                                }
                                else
                                {
                                    String elementName = event.asStartElement().getName().getLocalPart();

                                    if (elementName.equals("key") == true)
                                    {
                                        Attribute attributeId = event.asStartElement().getAttributeByName(new QName("id"));

                                        if (attributeId != null)
                                        {
                                            if (attributeId.getValue().equals("htx-scheme-id://org.hypertext-systems.20180702T071630Z/dimgra.20200601T122500Z/dimgra-1.20200601T122500Z/node-title.20200601T122500Z") == true)
                                            {
                                                inputFileHasNodeTitle = true;
                                            }
                                            else if (attributeId.getValue().equals("htx-scheme-id://org.hypertext-systems.20180702T071630Z/dimgra.20200601T122500Z/dimgra-1.20200601T122500Z/node-on-dimension.20200601T122500Z") == true)
                                            {
                                                inputFileHasDimension = true;
                                            }
                                            //else if (attributeId.getValue().equals("htx-scheme-id://org.hypertext-systems.20180702T071630Z/dimgra.20200601T122500Z/dimgra-1.20200601T122500Z/dimension-target.20200601T122500Z") == true)
                                            {

                                            }
                                            //else if (attributeId.getValue().equals("htx-scheme-id://org.hypertext-systems.20180702T071630Z/dimgra.20200601T122500Z/dimgra-1.20200601T122500Z/dimension-establishing.20200601T122500Z") == true)
                                            {

                                            }
                                        }
                                    }

                                    if (inputFileHasGraphML == true &&
                                        inputFileHasNodeTitle == true &&
                                        inputFileHasDimension == true)
                                    {
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    catch (XMLStreamException ex)
                    {
                        throw constructTermination("messageInputFileAnalyzerErrorWhileReading", ex, null, inputFile.getAbsolutePath());
                    }
                    catch (SecurityException ex)
                    {
                        throw constructTermination("messageInputFileAnalyzerErrorWhileReading", ex, null, inputFile.getAbsolutePath());
                    }
                    catch (IOException ex)
                    {
                        throw constructTermination("messageInputFileAnalyzerErrorWhileReading", ex, null, inputFile.getAbsolutePath());
                    }

                    if (inputFileHasGraphML != true ||
                        inputFileHasNodeTitle != true ||
                        inputFileHasDimension != true)
                    {
                        throw constructTermination("messageInputFileDoesntContainHyperdex1Data", null, null, inputFile.getAbsolutePath());
                    }
                }
            }
            else
            {
                throw constructTermination("messageOptionPicker1CallReturnedSelectionIdNotSupported", null, null, selectedOptionId);
            }
        }


        File hyperdex1JobFile = new File(tempDirectory.getAbsolutePath() + File.separator + "jobfile_hyperdex_1.xml");

        if (hyperdex1JobFile.exists() == true)
        {
            if (hyperdex1JobFile.isFile() == true)
            {
                boolean deleteSuccessful = false;

                try
                {
                    deleteSuccessful = hyperdex1JobFile.delete();
                }
                catch (SecurityException ex)
                {

                }

                if (deleteSuccessful != true)
                {
                    if (hyperdex1JobFile.canWrite() != true)
                    {
                        throw constructTermination("messageHyperdex1JobFileExistsButIsntWritable", null, null, hyperdex1JobFile.getAbsolutePath());
                    }
                }
            }
            else
            {
                throw constructTermination("messageHyperdex1JobPathExistsButIsntAFile", null, null, hyperdex1JobFile.getAbsolutePath());
            }
        }

        File hyperdex1ResultInfoFile = new File(tempDirectory.getAbsolutePath() + File.separator + "resultinfo_hyperdex_1.xml");

        if (hyperdex1ResultInfoFile.exists() == true)
        {
            if (hyperdex1ResultInfoFile.isFile() == true)
            {
                boolean deleteSuccessful = false;

                try
                {
                    deleteSuccessful = hyperdex1ResultInfoFile.delete();
                }
                catch (SecurityException ex)
                {

                }

                if (deleteSuccessful != true)
                {
                    if (hyperdex1ResultInfoFile.canWrite() != true)
                    {
                        throw constructTermination("messageHyperdex1ResultInfoFileExistsButIsntWritable", null, null, hyperdex1ResultInfoFile.getAbsolutePath());
                    }
                }
            }
            else
            {
                throw constructTermination("messageHyperdex1ResultInfoPathExistsButIsntAFile", null, null, hyperdex1ResultInfoFile.getAbsolutePath());
            }
        }

        try
        {
            BufferedWriter writer = new BufferedWriter(
                                    new OutputStreamWriter(
                                    new FileOutputStream(hyperdex1JobFile),
                                    "UTF-8"));

            writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
            writer.write("<!-- This file was created by hyperdex_1 workflow, which is free software licensed under the GNU Affero General Public License 3 or any later version (see https://gitlab.com/publishing-systems/digital_publishing_workflow_tools/ and https://hypertext-systems.org). -->\n");
            writer.write("<hyperdex-1-jobfile>\n");

            if (inputFile != null)
            {
                writer.write("  <input-file path=\"" + inputFile.getAbsolutePath() + "\"/>\n");
            }

            writer.write("  <output-file path=\"" + this.outputFile.getAbsolutePath() + "\"/>\n");
            //writer.write("  <options log-data=\"false\" fullscreen=\"false\" edit-id-on-new-node=\"false\"/>\n");
            writer.write("</hyperdex-1-jobfile>\n");

            writer.flush();
            writer.close();
        }
        catch (FileNotFoundException ex)
        {
            throw constructTermination("messageHyperdex1JobFileWritingError", ex, null, hyperdex1JobFile.getAbsolutePath());
        }
        catch (UnsupportedEncodingException ex)
        {
            throw constructTermination("messageHyperdex1JobFileWritingError", ex, null, hyperdex1JobFile.getAbsolutePath());
        }
        catch (IOException ex)
        {
            throw constructTermination("messageHyperdex1JobFileWritingError", ex, null, hyperdex1JobFile.getAbsolutePath());
        }

        ProcessBuilder builder = new ProcessBuilder("java", "hyperdex_1", hyperdex1JobFile.getAbsolutePath(), hyperdex1ResultInfoFile.getAbsolutePath());
        builder.directory(new File(programPath + File.separator + ".." + File.separator + ".." + File.separator + ".." + File.separator + "gui" + File.separator + "hyperdex" + File.separator + "hyperdex_1"));
        builder.redirectErrorStream(true);

        try
        {
            Process process = builder.start();
            Scanner scanner = new Scanner(process.getInputStream()).useDelimiter("\n");

            while (scanner.hasNext() == true)
            {
                System.out.println(scanner.next());
            }

            scanner.close();
        }
        catch (IOException ex)
        {
            throw constructTermination("messageHyperdex1ErrorWhileReadingOutput", ex, null);
        }

        if (hyperdex1ResultInfoFile.exists() != true)
        {
            throw constructTermination("messageHyperdex1ResultInfoFileDoesntExistButShould", null, null, hyperdex1ResultInfoFile.getAbsolutePath());
        }

        if (hyperdex1ResultInfoFile.isFile() != true)
        {
            throw constructTermination("messageHyperdex1ResultInfoPathExistsButIsntAFile", null, null, hyperdex1ResultInfoFile.getAbsolutePath());
        }

        if (hyperdex1ResultInfoFile.canRead() != true)
        {
            throw constructTermination("messageHyperdex1ResultInfoFileIsntReadable", null, null, hyperdex1ResultInfoFile.getAbsolutePath());
        }

        boolean wasSuccess = false;

        try
        {
            XMLInputFactory inputFactory = XMLInputFactory.newInstance();
            InputStream in = new FileInputStream(hyperdex1ResultInfoFile);
            XMLEventReader eventReader = inputFactory.createXMLEventReader(in);

            while (eventReader.hasNext() == true)
            {
                XMLEvent event = eventReader.nextEvent();

                if (event.isStartElement() == true)
                {
                    String elementName = event.asStartElement().getName().getLocalPart();

                    if (elementName.equals("success") == true)
                    {
                        wasSuccess = true;
                        break;
                    }
                }
            }
        }
        catch (XMLStreamException ex)
        {
            throw constructTermination("messageHyperdex1ResultInfoFileErrorWhileReading", ex, null, hyperdex1ResultInfoFile.getAbsolutePath());
        }
        catch (SecurityException ex)
        {
            throw constructTermination("messageHyperdex1ResultInfoFileErrorWhileReading", ex, null, hyperdex1ResultInfoFile.getAbsolutePath());
        }
        catch (IOException ex)
        {
            throw constructTermination("messageHyperdex1ResultInfoFileErrorWhileReading", ex, null, hyperdex1ResultInfoFile.getAbsolutePath());
        }

        if (wasSuccess != true)
        {
            throw constructTermination("messageHyperdex1CallWasntSuccessful", null, null);
        }


        if (this.outputFile.exists() == true)
        {
            File xmlXsltTransformator1JobFile = new File(tempDirectory.getAbsolutePath() + File.separator + "jobfile_xml_xslt_transformator_1.xml");

            if (xmlXsltTransformator1JobFile.exists() == true)
            {
                if (xmlXsltTransformator1JobFile.isFile() == true)
                {
                    boolean deleteSuccessful = false;

                    try
                    {
                        deleteSuccessful = xmlXsltTransformator1JobFile.delete();
                    }
                    catch (SecurityException ex)
                    {

                    }

                    if (deleteSuccessful != true)
                    {
                        if (xmlXsltTransformator1JobFile.canWrite() != true)
                        {
                            throw constructTermination("messageXmlXsltTransformator1JobFileExistsButIsntWritable", null, null, xmlXsltTransformator1JobFile.getAbsolutePath());
                        }
                    }
                }
                else
                {
                    throw constructTermination("messageXmlXsltTransformator1JobPathExistsButIsntAFile", null, null, xmlXsltTransformator1JobFile.getAbsolutePath());
                }
            }

            File xmlXsltTransformator1ResultInfoFile = new File(tempDirectory.getAbsolutePath() + File.separator + "resultinfo_xml_xslt_transformator_1.xml");

            if (xmlXsltTransformator1ResultInfoFile.exists() == true)
            {
                if (xmlXsltTransformator1ResultInfoFile.isFile() == true)
                {
                    boolean deleteSuccessful = false;

                    try
                    {
                        deleteSuccessful = xmlXsltTransformator1ResultInfoFile.delete();
                    }
                    catch (SecurityException ex)
                    {

                    }

                    if (deleteSuccessful != true)
                    {
                        if (xmlXsltTransformator1ResultInfoFile.canWrite() != true)
                        {
                            throw constructTermination("messageXmlXsltTransformator1ResultInfoFileExistsButIsntWritable", null, null, xmlXsltTransformator1ResultInfoFile.getAbsolutePath());
                        }
                    }
                }
                else
                {
                    throw constructTermination("messageXmlXsltTransformator1ResultInfoPathExistsButIsntAFile", null, null, xmlXsltTransformator1ResultInfoFile.getAbsolutePath());
                }
            }

            try
            {
                BufferedWriter writer = new BufferedWriter(
                                        new OutputStreamWriter(
                                        new FileOutputStream(xmlXsltTransformator1JobFile),
                                        "UTF-8"));

                writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
                writer.write("<!-- This file was created by hyperdex_1 workflow, which is free software licensed under the GNU Affero General Public License 3 or any later version (see https://gitlab.com/publishing-systems/digital_publishing_workflow_tools/ and https://hypertext-systems.org). -->\n");
                writer.write("<xml-xslt-transformator-1-jobfile>\n");
                writer.write("  <job input-file=\"" + this.outputFile.getAbsolutePath() + "\" entities-resolver-config-file=\"" + (new File(programPath + File.separator + ".." + File.separator + ".." + File.separator + ".." + File.separator + ".." + File.separator + "xml_xslt_transformator" + File.separator + "xml_xslt_transformator_1" + File.separator + "entities" + File.separator + "config_empty.xml")).getAbsolutePath() + "\" stylesheet-file=\"" + (new File(programPath + File.separator + "graphml_to_dimgra_xhtml_1.xsl")).getAbsolutePath() + "\" output-file=\"" + this.outputDimgraFile.getAbsolutePath() + "\"/>\n");
                writer.write("</xml-xslt-transformator-1-jobfile>\n");

                writer.flush();
                writer.close();
            }
            catch (FileNotFoundException ex)
            {
                throw constructTermination("messageXmlXsltTransformator1JobFileWritingError", ex, null, xmlXsltTransformator1JobFile.getAbsolutePath());
            }
            catch (UnsupportedEncodingException ex)
            {
                throw constructTermination("messageXmlXsltTransformator1JobFileWritingError", ex, null, xmlXsltTransformator1JobFile.getAbsolutePath());
            }
            catch (IOException ex)
            {
                throw constructTermination("messageXmlXsltTransformator1JobFileWritingError", ex, null, xmlXsltTransformator1JobFile.getAbsolutePath());
            }

            builder = new ProcessBuilder("java", "xml_xslt_transformator_1", xmlXsltTransformator1JobFile.getAbsolutePath(), xmlXsltTransformator1ResultInfoFile.getAbsolutePath());
            builder.directory(new File(programPath + File.separator + ".." + File.separator + ".." + File.separator + ".." + File.separator + ".." + File.separator + "xml_xslt_transformator" + File.separator + "xml_xslt_transformator_1"));
            builder.redirectErrorStream(true);

            try
            {
                Process process = builder.start();
                Scanner scanner = new Scanner(process.getInputStream()).useDelimiter("\n");

                while (scanner.hasNext() == true)
                {
                    System.out.println(scanner.next());
                }

                scanner.close();
            }
            catch (IOException ex)
            {
                throw constructTermination("messageXmlXsltTransformator1ErrorWhileReadingOutput", ex, null);
            }

            if (xmlXsltTransformator1ResultInfoFile.exists() != true)
            {
                throw constructTermination("messageXmlXsltTransformator1ResultInfoFileDoesntExistButShould", null, null, xmlXsltTransformator1ResultInfoFile.getAbsolutePath());
            }

            if (xmlXsltTransformator1ResultInfoFile.isFile() != true)
            {
                throw constructTermination("messageXmlXsltTransformator1ResultInfoPathExistsButIsntAFile", null, null, xmlXsltTransformator1ResultInfoFile.getAbsolutePath());
            }

            if (xmlXsltTransformator1ResultInfoFile.canRead() != true)
            {
                throw constructTermination("messagexmlXsltTransformator1ResultInfoFileIsntReadable", null, null, xmlXsltTransformator1ResultInfoFile.getAbsolutePath());
            }

            wasSuccess = false;

            try
            {
                XMLInputFactory inputFactory = XMLInputFactory.newInstance();
                InputStream in = new FileInputStream(xmlXsltTransformator1ResultInfoFile);
                XMLEventReader eventReader = inputFactory.createXMLEventReader(in);

                while (eventReader.hasNext() == true)
                {
                    XMLEvent event = eventReader.nextEvent();

                    if (event.isStartElement() == true)
                    {
                        String elementName = event.asStartElement().getName().getLocalPart();

                        if (elementName.equals("success") == true)
                        {
                            wasSuccess = true;
                            break;
                        }
                    }
                }
            }
            catch (XMLStreamException ex)
            {
                throw constructTermination("messagexmlXsltTransformator1ResultInfoFileErrorWhileReading", ex, null, xmlXsltTransformator1ResultInfoFile.getAbsolutePath());
            }
            catch (SecurityException ex)
            {
                throw constructTermination("messagexmlXsltTransformator1ResultInfoFileErrorWhileReading", ex, null, xmlXsltTransformator1ResultInfoFile.getAbsolutePath());
            }
            catch (IOException ex)
            {
                throw constructTermination("messagexmlXsltTransformator1ResultInfoFileErrorWhileReading", ex, null, xmlXsltTransformator1ResultInfoFile.getAbsolutePath());
            }

            if (wasSuccess != true)
            {
                throw constructTermination("messagexmlXsltTransformator1CallWasntSuccessful", null, null);
            }
        }
        else
        {
            // Maybe no changes saved.

            this.outputFile = null;
            this.outputDimgraFile = null;
        }

        return 0;
    }

    private InfoMessage constructInfoMessage(String id,
                                             boolean outputToConsole,
                                             Exception exception,
                                             String message,
                                             Object ... arguments)
    {
        if (message == null)
        {
            if (arguments == null)
            {
                message = "hyperdex_1 workflow: " + getI10nString(id);
            }
            else
            {
                message = "hyperdex_1 workflow: " + getI10nStringFormatted(id, arguments);
            }
        }

        if (outputToConsole == true)
        {
            System.out.println(message);

            if (exception != null)
            {
                System.out.println(exception.getMessage());
                exception.printStackTrace();
            }
        }

        return new InfoMessage(id, exception, message, L10N_BUNDLE, arguments);
    }

    public ProgramTerminationException constructTermination(String id, Exception cause, String message, Object ... arguments)
    {
        if (message == null)
        {
            if (arguments == null)
            {
                message = "hyperdex_1 workflow: " + getI10nString(id);
            }
            else
            {
                message = "hyperdex_1 workflow: " + getI10nStringFormatted(id, arguments);
            }
        }

        return new ProgramTerminationException(id, cause, message, L10N_BUNDLE, arguments);
    }

    public int handleTermination(ProgramTerminationException ex)
    {
        String message = ex.getMessage();
        String id = ex.getId();
        String bundle = ex.getBundle();
        Object[] arguments = ex.getArguments();
        boolean normalTermination = ex.isNormalTermination();

        if (message != null)
        {
            System.err.println(message);
        }

        Throwable innerException = ex.getCause();

        if (innerException != null)
        {
            System.out.println(innerException.getMessage());
            innerException.printStackTrace();
        }

        if (hyperdex_1.resultInfoFile != null)
        {
            try
            {
                BufferedWriter writer = new BufferedWriter(
                                        new OutputStreamWriter(
                                        new FileOutputStream(hyperdex_1.resultInfoFile),
                                        "UTF-8"));

                writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
                writer.write("<!-- This file was created by hyperdex_1 workflow, which is free software licensed under the GNU Affero General Public License 3 or any later version (see https://gitlab.com/publishing-systems/digital_publishing_workflow_tools/ and https://hypertext-systems.org). -->\n");
                writer.write("<hyperdex-1-workflow-result-information>\n");

                if (normalTermination == false)
                {
                    writer.write("  <failure>\n");
                }
                else
                {
                    writer.write("  <success>\n");
                }

                writer.write("    <timestamp>" + ex.getTimestamp() + "</timestamp>\n");

                if (bundle != null)
                {
                    // Ampersand needs to be the first, otherwise it would double-encode
                    // other entities.
                    bundle = bundle.replaceAll("&", "&amp;");
                    bundle = bundle.replaceAll("<", "&lt;");
                    bundle = bundle.replaceAll(">", "&gt;");

                    writer.write("    <id-bundle>" + bundle + "</id-bundle>\n");
                }

                if (id != null)
                {
                    // Ampersand needs to be the first, otherwise it would double-encode
                    // other entities.
                    id = id.replaceAll("&", "&amp;");
                    id = id.replaceAll("<", "&lt;");
                    id = id.replaceAll(">", "&gt;");

                    writer.write("    <id>" + id + "</id>\n");
                }

                if (message != null)
                {
                    // Ampersand needs to be the first, otherwise it would double-encode
                    // other entities.
                    message = message.replaceAll("&", "&amp;");
                    message = message.replaceAll("<", "&lt;");
                    message = message.replaceAll(">", "&gt;");

                    writer.write("    <message>" + message + "</message>\n");
                }

                if (arguments != null)
                {
                    writer.write("    <arguments>\n");

                    int argumentCount = arguments.length;

                    for (int i = 0; i < argumentCount; i++)
                    {
                        if (arguments[i] == null)
                        {
                            writer.write("      <argument number=\"" + i + "\">\n");
                            writer.write("        <class></class>\n");
                            writer.write("        <value>null</value>\n");
                            writer.write("      </argument>\n");

                            continue;
                        }

                        String className = arguments[i].getClass().getName();

                        // Ampersand needs to be the first, otherwise it would double-encode
                        // other entities.
                        className = className.replaceAll("&", "&amp;");
                        className = className.replaceAll("<", "&lt;");
                        className = className.replaceAll(">", "&gt;");

                        String value = arguments[i].toString();

                        // Ampersand needs to be the first, otherwise it would double-encode
                        // other entities.
                        value = value.replaceAll("&", "&amp;");
                        value = value.replaceAll("<", "&lt;");
                        value = value.replaceAll(">", "&gt;");

                        writer.write("      <argument number=\"" + i + "\">\n");
                        writer.write("        <class>" + className + "</class>\n");
                        writer.write("        <value>" + value + "</value>\n");
                        writer.write("      </argument>\n");
                    }

                    writer.write("    </arguments>\n");
                }

                if (innerException != null)
                {
                    writer.write("    <exception>\n");

                    String className = innerException.getClass().getName();

                    // Ampersand needs to be the first, otherwise it would double-encode
                    // other entities.
                    className = className.replaceAll("&", "&amp;");
                    className = className.replaceAll("<", "&lt;");
                    className = className.replaceAll(">", "&gt;");

                    writer.write("      <class>" + className + "</class>\n");

                    StringWriter stringWriter = new StringWriter();
                    PrintWriter printWriter = new PrintWriter(stringWriter);
                    innerException.printStackTrace(printWriter);
                    String stackTrace = stringWriter.toString();

                    // Ampersand needs to be the first, otherwise it would double-encode
                    // other entities.
                    stackTrace = stackTrace.replaceAll("&", "&amp;");
                    stackTrace = stackTrace.replaceAll("<", "&lt;");
                    stackTrace = stackTrace.replaceAll(">", "&gt;");

                    writer.write("      <stack-trace>" + stackTrace + "</stack-trace>\n");
                    writer.write("    </exception>\n");
                }

                if (this.getInfoMessages().size() > 0)
                {
                    writer.write("    <info-messages>\n");

                    for (int i = 0, max = this.getInfoMessages().size(); i < max; i++)
                    {
                        InfoMessage infoMessage = this.getInfoMessages().get(i);

                        writer.write("      <info-message>\n");
                        writer.write("        <timestamp>" + infoMessage.getTimestamp() + "</timestamp>\n");

                        String infoMessageText = infoMessage.getMessage();
                        String infoMessageId = ex.getId();
                        String infoMessageBundle = ex.getBundle();
                        Object[] infoMessageArguments = ex.getArguments();

                        if (infoMessageBundle != null)
                        {
                            // Ampersand needs to be the first, otherwise it would double-encode
                            // other entities.
                            infoMessageBundle = infoMessageBundle.replaceAll("&", "&amp;");
                            infoMessageBundle = infoMessageBundle.replaceAll("<", "&lt;");
                            infoMessageBundle = infoMessageBundle.replaceAll(">", "&gt;");

                            writer.write("        <id-bundle>" + infoMessageBundle + "</id-bundle>\n");
                        }

                        if (infoMessageId != null)
                        {
                            // Ampersand needs to be the first, otherwise it would double-encode
                            // other entities.
                            infoMessageId = infoMessageId.replaceAll("&", "&amp;");
                            infoMessageId = infoMessageId.replaceAll("<", "&lt;");
                            infoMessageId = infoMessageId.replaceAll(">", "&gt;");

                            writer.write("        <id>" + infoMessageId + "</id>\n");
                        }

                        if (infoMessageText != null)
                        {
                            // Ampersand needs to be the first, otherwise it would double-encode
                            // other entities.
                            infoMessageText = infoMessageText.replaceAll("&", "&amp;");
                            infoMessageText = infoMessageText.replaceAll("<", "&lt;");
                            infoMessageText = infoMessageText.replaceAll(">", "&gt;");

                            writer.write("        <message>" + infoMessageText + "</message>\n");
                        }

                        if (infoMessageArguments != null)
                        {
                            writer.write("        <arguments>\n");

                            int argumentCount = infoMessageArguments.length;

                            for (int j = 0; j < argumentCount; j++)
                            {
                                if (infoMessageArguments[j] == null)
                                {
                                    writer.write("          <argument number=\"" + j + "\">\n");
                                    writer.write("            <class></class>\n");
                                    writer.write("            <value>null</value>\n");
                                    writer.write("          </argument>\n");

                                    continue;
                                }

                                String className = infoMessageArguments[j].getClass().getName();

                                // Ampersand needs to be the first, otherwise it would double-encode
                                // other entities.
                                className = className.replaceAll("&", "&amp;");
                                className = className.replaceAll("<", "&lt;");
                                className = className.replaceAll(">", "&gt;");

                                String value = infoMessageArguments[j].toString();

                                // Ampersand needs to be the first, otherwise it would double-encode
                                // other entities.
                                value = value.replaceAll("&", "&amp;");
                                value = value.replaceAll("<", "&lt;");
                                value = value.replaceAll(">", "&gt;");

                                writer.write("          <argument number=\"" + j + "\">\n");
                                writer.write("            <class>" + className + "</class>\n");
                                writer.write("            <value>" + value + "</value>\n");
                                writer.write("          </argument>\n");
                            }

                            writer.write("        </arguments>\n");
                        }

                        writer.write("      </info-message>\n");
                    }

                    writer.write("    </info-messages>\n");
                }

                if (normalTermination == false)
                {
                    writer.write("  </failure>\n");
                }
                else
                {
                    writer.write("  </success>\n");
                }

                writer.write("</hyperdex-1-workflow-result-information>\n");
                writer.flush();
                writer.close();
            }
            catch (FileNotFoundException ex2)
            {
                ex2.printStackTrace();
            }
            catch (UnsupportedEncodingException ex2)
            {
                ex2.printStackTrace();
            }
            catch (IOException ex2)
            {
                ex2.printStackTrace();
            }
        }

        hyperdex_1.resultInfoFile = null;

        System.exit(-1);
        return -1;
    }

    public File GetOutputFile()
    {
        return this.outputFile;
    }

    public File GetOutputDimgraFile()
    {
        return this.outputDimgraFile;
    }

    public List<InfoMessage> getInfoMessages()
    {
        return this.infoMessages;
    }

    public Locale getLocale()
    {
        return Locale.getDefault();
    }

    /**
     * @brief This method interprets l10n strings from a .properties file as encoded in UTF-8.
     */
    private String getI10nString(String key)
    {
        if (this.l10nConsole == null)
        {
            this.l10nConsole = ResourceBundle.getBundle(L10N_BUNDLE, this.getLocale());
        }

        try
        {
            return new String(this.l10nConsole.getString(key).getBytes("UTF-8"), "UTF-8");
        }
        catch (UnsupportedEncodingException ex)
        {
            return this.l10nConsole.getString(key);
        }
    }

    private String getI10nStringFormatted(String i10nStringName, Object ... arguments)
    {
        MessageFormat formatter = new MessageFormat("");
        formatter.setLocale(this.getLocale());

        formatter.applyPattern(getI10nString(i10nStringName));
        return formatter.format(arguments);
    }

    protected File outputFile = null;
    protected File outputDimgraFile = null;

    public static File resultInfoFile = null;
    protected List<InfoMessage> infoMessages = new ArrayList<InfoMessage>();

    private static final String L10N_BUNDLE = "l10n.l10nHyperdex1WorkflowConsole";
    private ResourceBundle l10nConsole;
}
