package fr.emse.gitlab.saref;

import static fr.emse.gitlab.saref.CMDConfigurations.*;

import java.awt.BorderLayout;
import java.awt.Desktop;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.ParseException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.jena.atlas.io.IndentedWriter;
import org.apache.jena.graph.NodeFactory;
import org.apache.jena.query.Dataset;
import org.apache.jena.query.ReadWrite;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ModelFactory;
import org.apache.jena.rdf.model.ResIterator;
import org.apache.jena.sparql.core.Var;
import org.apache.jena.sparql.engine.binding.Binding;
import org.apache.jena.sparql.engine.binding.BindingHashMap;
import org.apache.jena.sparql.util.Context;
import org.apache.jena.tdb.TDBFactory;
import org.apache.jena.vocabulary.RDF;
import org.apache.log4j.Layout;
import org.apache.log4j.PatternLayout;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.CheckoutConflictException;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.InvalidRefNameException;
import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
import org.eclipse.jgit.api.errors.RefNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import fr.emse.ci.sparqlext.SPARQLExt;
import fr.emse.ci.sparqlext.engine.PlanFactory;
import fr.emse.ci.sparqlext.engine.RootPlan;
import fr.emse.ci.sparqlext.stream.LocationMapperAccept;
import fr.emse.ci.sparqlext.stream.LocatorFileAccept;
import fr.emse.ci.sparqlext.stream.LookUpRequest;
import fr.emse.ci.sparqlext.stream.SPARQLExtStreamManager;
import fr.emse.ci.sparqlext.utils.ContextUtils;
import fr.emse.ci.sparqlext.utils.VarUtils;
import fr.emse.gitlab.saref.entities.git.Repositories;
import fr.emse.gitlab.saref.entities.git.Repository;
import fr.emse.gitlab.saref.entities.git.Version;
import fr.emse.gitlab.saref.entities.tests.TestSuites;
import fr.emse.gitlab.saref.jobs.CheckConfig;
import fr.emse.gitlab.saref.jobs.CheckOWLProfile;
import fr.emse.gitlab.saref.jobs.CheckRepositoryStructure;
import fr.emse.gitlab.saref.jobs.CheckoutJob;
import fr.emse.gitlab.saref.jobs.GeneratePortal;
import fr.emse.gitlab.saref.jobs.ReadExamples;
import fr.emse.gitlab.saref.jobs.ReadOntology;
import fr.emse.gitlab.saref.jobs.ReadRepositories;
import fr.emse.gitlab.saref.utils.TestSuitesAppender;
import fr.emse.gitlab.saref.vocabs.EX;

public class Main {

	static final Logger LOG = LoggerFactory.getLogger(Constants.LOGGER_BASE + ".Main");
	public final static String BASE_DOC = Constants.BASE + "documentation/";
	public static final PathMatcher ttlMatcher = FileSystems.getDefault().getPathMatcher("glob:**/*.ttl");

	private static TestSuites testSuites = new TestSuites("SAREF pipeline");
	private static final Map<String, String> testSuiteNames = new HashMap<>();

	private static File directory;
	private static File target;
	private static SPARQLExtStreamManager streamManager;
	private static boolean openBrowser = true;

	private static Dataset dataset;
	private static Var VAR_TEST_SUITES = VarUtils.allocVar("testsuites");

	static boolean remoteOnly;
	static boolean ignoreGit;
	static boolean includeMaster;
	static boolean generateSite;
	static boolean ignoreTerms;
	static boolean ignoreExamples;
	static boolean verbose;

	/* added to handle the GUI */
	static boolean fileSelected = false;

	private static JTextArea txtConsole = new JTextArea("Select a directory to start\n");
	private static JFrame frame = new JFrame();
	private static JPanel functionalitiesPanel = new JPanel(new GridLayout(0, 4));
	private static JPanel infoPanel = new JPanel();
	private static JPanel textAreaPanel = new JPanel();
	public static boolean isTheConsoleActive = true;

	public static void main(String[] args) throws IOException, InterruptedException, URISyntaxException, JAXBException,
			ParseException, RefAlreadyExistsException, RefNotFoundException, InvalidRefNameException,
			CheckoutConflictException, GitAPIException {
		if (isTheConsoleActive == true) {

			openConsole(); // open console

		}

		else {
			CommandLine cl = CMDConfigurations.parseArguments(args);
			if (cl.getOptions().length == 0 || cl.hasOption(ARG_HELP)) {
				CMDConfigurations.displayHelp();
				return;
			}

			String dirName = cl.getOptionValue(ARG_DIRECTORY, ARG_DIRECTORY_DEFAULT);
			directory = new File(dirName).getCanonicalFile();
			if (!directory.isDirectory()) {
				LOG.error("The directory does not exist " + directory);
				System.exit(-1);
			}

			remoteOnly = cl.hasOption(ARG_REMOTE_ONLY);
			ignoreGit = cl.hasOption(ARG_IGNORE_GIT);
			includeMaster = cl.hasOption(ARG_INCLUDE_MASTER);
			generateSite = !cl.hasOption(ARG_NO_SITE);
			ignoreExamples = cl.hasOption(ARG_IGNORE_EXAMPLES);
			ignoreTerms = cl.hasOption(ARG_IGNORE_TERMS);
			verbose = cl.hasOption(ARG_VERBOSE);

			setLogAppenders();
			prepareDirectory();
			streamManager = initializeStreamManager();
			dataset = createFreshDataset();
			LOG.info("Starting pipeline in " + directory);

			Repositories repositories;
			try {
				repositories = new ReadRepositories("Fetching required repositories").readRepositories(directory,
						remoteOnly, ignoreGit, includeMaster);
			} catch (Exception ex) {
				reportAndExit(-1);
				return;
			}

			if (repositories.getDefaultRepository() != null) {
				Repository repository = repositories.getDefaultRepository();
				boolean checkExamples = !ignoreExamples;
				testRepository(repository, checkExamples);
			}
			for (Repository repository : repositories.getNamedRepositories()) {
				boolean checkExamples = !ignoreExamples && remoteOnly;
				testRepository(repository, checkExamples);
			}

			checkOWLProfile();
			new CheckConfig().doJob(dataset, ignoreExamples);

			if (generateSite) {
				new GeneratePortal("Generate static files for the portal", streamManager).doJob(dataset, directory,
						verbose, ignoreExamples, ignoreTerms);
			}

			if (repositories.getDefaultRepository() != null && !ignoreGit) {
				Repository repository = repositories.getDefaultRepository();
				resetCheckout(repository);
			}
			for (Repository repository : repositories.getNamedRepositories()) {
				resetCheckout(repository);
			}

			testSuites.clean();

			reportAndExit((int) -Math.signum(testSuites.getErrors() + testSuites.getFailures()));

		}
	}

	private static void setLogAppenders() throws IOException {
		File logFile = new File(directory, Constants.LOG_FILE_NAME);
		Layout layout = new PatternLayout("%d{mm:ss,SSS} %t %-5p %c:%L - %m%n");
		org.apache.log4j.Logger rootLogger = org.apache.log4j.Logger.getRootLogger();
		rootLogger.addAppender(new org.apache.log4j.RollingFileAppender(layout, logFile.getAbsolutePath(), false));

		org.apache.log4j.Logger loggerBase = org.apache.log4j.Logger.getLogger(Constants.LOGGER_BASE);
		TestSuitesAppender appender = new TestSuitesAppender(testSuites);
		loggerBase.addAppender(appender);
	}

	private static void setGUIAppenders() throws IOException {

		JTextAreaAppender jTextAreaAppender = new JTextAreaAppender(txtConsole);

		org.apache.log4j.Logger appenderRootLogger = org.apache.log4j.Logger.getRootLogger();

		Layout GUIlayout = new PatternLayout("%d{mm:ss,SSS} %t %-5p %c:%L - %m%n");

		jTextAreaAppender.setLayout(GUIlayout);

		appenderRootLogger.addAppender(jTextAreaAppender);

	}

	private static boolean openConsole() throws IOException, InterruptedException, URISyntaxException, JAXBException,
			ParseException, RefAlreadyExistsException, RefNotFoundException, InvalidRefNameException,
			CheckoutConflictException, GitAPIException {

		setGUIAppenders();

//		JFrame.setDefaultLookAndFeelDecorated(true);

		frame = new JFrame("Saref-Pipeline tests");
		frame.setBounds(100, 100, 800, 400);
		SwingUtilities.updateComponentTreeUI(frame);

		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		JLabel lblWelcomeToSarefpipeline = new JLabel("SAREF ontologies pipeline tests");
		infoPanel.add(lblWelcomeToSarefpipeline);

		frame.getContentPane().add(functionalitiesPanel, BorderLayout.SOUTH);

		JLabel lbl = new JLabel("The list of arguments:");
		functionalitiesPanel.add(lbl);

		JLabel emptylbl1 = new JLabel();
		functionalitiesPanel.add(emptylbl1);

		JLabel emptylbl2 = new JLabel();
		functionalitiesPanel.add(emptylbl2);

		JLabel emptylbl3 = new JLabel();
		functionalitiesPanel.add(emptylbl3);

		JCheckBox remoteOnly_checkBox = new JCheckBox("Remote-only");
		remoteOnly_checkBox.setToolTipText("Do not check the directory itself.\n"
				+ " Only consider the repositories listed in the `.saref-repositories.yml` document.\n"
				+ " Used to generate the website for several extensions.");
		functionalitiesPanel.add(remoteOnly_checkBox);

		JCheckBox ignoreGit_checkBox = new JCheckBox("No-git");
		ignoreGit_checkBox.setToolTipText("Only check the current state of the repository");
		functionalitiesPanel.add(ignoreGit_checkBox);

		JCheckBox includeMaster_checkBox = new JCheckBox("Include master");
		includeMaster_checkBox.setToolTipText(
				"Check the master branches of the remote repositories listed in the `.saref-repositories.yml` document");
		functionalitiesPanel.add(includeMaster_checkBox);

		JCheckBox generateSite_checkBox = new JCheckBox("Don't generate site");
		generateSite_checkBox.setToolTipText("Do not generate the static website");
		functionalitiesPanel.add(generateSite_checkBox);

		JCheckBox ignoreExamples_checkBox = new JCheckBox("Ignore examples");
		ignoreExamples_checkBox.setToolTipText("Only check the SAREF extension ontology. Ignore the examples");
		functionalitiesPanel.add(ignoreExamples_checkBox);

		JCheckBox verbose_checkBox = new JCheckBox("Verbose");
		verbose_checkBox.setToolTipText("Use verbose mode.\n"
				+ "(For example, use SPARQL-Generate in --debug-template mode when generating the documentation)");
		functionalitiesPanel.add(verbose_checkBox);

		JCheckBox ignoreTerms_checkBox = new JCheckBox("Ignore terms");
		ignoreTerms_checkBox.setToolTipText("Do not generate the website for terms");
		functionalitiesPanel.add(ignoreTerms_checkBox);

		JLabel emptylbl4 = new JLabel();
		functionalitiesPanel.add(emptylbl4);

		JLabel emptylbl5 = new JLabel();
		functionalitiesPanel.add(emptylbl5);

//		JButton startBtn = new JButton("Start the pipeline");

//		JProgressBar bar = new JProgressBar();
//		bar.setIndeterminate(true);
//		bar.setStringPainted(true);
//		bar.setString("Please wait");
//		bar.setVisible(false);
//		functionalitiesPanel.add(bar);

		JButton startBtn = new JButton("Start the pipeline");

		JButton fileChooserBtn = new JButton("Choose a directory");
		fileChooserBtn.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				JFileChooser fileChooser = new JFileChooser();
				fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
				int option = fileChooser.showOpenDialog(frame);
				if (option == JFileChooser.APPROVE_OPTION) {
					directory = fileChooser.getSelectedFile();
					fileSelected = true;
					startBtn.setEnabled(true);
				} else {
					LOG.info("Open command canceled");
				}

			}

		});
		functionalitiesPanel.add(fileChooserBtn);

		startBtn.setEnabled(false);
		startBtn.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {

				if (fileSelected == true) {

					startBtn.setEnabled(true);

					if (!remoteOnly_checkBox.isSelected() && !ignoreGit_checkBox.isSelected()
							&& !includeMaster_checkBox.isSelected() && !generateSite_checkBox.isSelected()
							&& !ignoreExamples_checkBox.isSelected() && !verbose_checkBox.isSelected()
							&& !ignoreTerms_checkBox.isSelected()) {

						LOG.error("Please choose among the different options");
						return;
					}

					remoteOnly = remoteOnly_checkBox.isSelected();
					ignoreGit = ignoreGit_checkBox.isSelected();
					includeMaster = includeMaster_checkBox.isSelected();
					generateSite = !generateSite_checkBox.isSelected();
					ignoreExamples = ignoreExamples_checkBox.isSelected();
					ignoreTerms = ignoreTerms_checkBox.isSelected();
					verbose = verbose_checkBox.isSelected();
					try {

						setLogAppenders();
						prepareDirectory();
						streamManager = initializeStreamManager();
						dataset = createFreshDataset();
					} catch (Exception e) {
						// TODO: handle exception
					}

					LOG.info("Starting pipeline in " + directory);

					Repositories repositories;
					try {
						repositories = new ReadRepositories("Fetching required repositories")
								.readRepositories(directory, remoteOnly, ignoreGit, includeMaster);
					} catch (Exception ex) {
						reportAndExit(-1);
						return;
					}

					if (repositories.getDefaultRepository() != null) {
						Repository repository = repositories.getDefaultRepository();
						boolean checkExamples = !ignoreExamples;
						testRepository(repository, checkExamples);
					}
					for (Repository repository : repositories.getNamedRepositories()) {
						boolean checkExamples = !ignoreExamples && remoteOnly;
						testRepository(repository, checkExamples);
					}

					checkOWLProfile();
					new CheckConfig().doJob(dataset, ignoreExamples);

					if (generateSite) {
						try {
							new GeneratePortal("Generate static files for the portal", streamManager).doJob(dataset,
									directory, verbose, ignoreExamples, ignoreTerms);
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}

					if (repositories.getDefaultRepository() != null && !ignoreGit) {
						Repository repository = repositories.getDefaultRepository();
						resetCheckout(repository);
					}
					for (Repository repository : repositories.getNamedRepositories()) {
						resetCheckout(repository);
					}

					testSuites.clean();

					reportAndExit((int) -Math.signum(testSuites.getErrors() + testSuites.getFailures()));

					int n = JOptionPane.showConfirmDialog(frame,
							"The pipeline is finished\n" + "The report file is available at:\n" + directory
									+ "/target/report_output.xml\n"
									+ "Would you like to open it, erase the console and start the pipeline again?",
							"Report results", JOptionPane.YES_NO_OPTION);
					if (n == 0) {
						try {
							txtConsole.setText("");
							Desktop.getDesktop().open(new File(directory + "/target/report_output.xml"));

						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}

				}

			}
		});
		functionalitiesPanel.add(startBtn);

		FlowLayout flowLayout_1 = (FlowLayout) infoPanel.getLayout();
		flowLayout_1.setVgap(20);
		flowLayout_1.setHgap(20);
		frame.getContentPane().add(infoPanel, BorderLayout.NORTH);

		frame.getContentPane().add(textAreaPanel, BorderLayout.CENTER);
		txtConsole.setColumns(70);
		txtConsole.setRows(15);
		textAreaPanel.add(txtConsole);

		JScrollPane scroll = new JScrollPane(txtConsole, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
				JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
		frame.add(scroll);

		frame.pack();
		frame.setResizable(true);
		frame.setVisible(true);
		frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

		return true;
	}

	private static void prepareDirectory() throws IOException {
		target = new File(directory, Constants.TARGET_DIR);
		FileUtils.forceMkdir(target);
		if (generateSite) {
			File staticTargetDir = new File(directory, Constants.STATIC_TARGET_DIR);
			File staticTargetZip = new File(directory, Constants.STATIC_TARGET_DIR + ".zip");
			URL url = Main.class.getClassLoader().getResource("static.zip");
			FileUtils.copyURLToFile(url, staticTargetZip);
			UnzipFile.unzip(staticTargetZip, staticTargetDir);
			FileUtils.deleteQuietly(staticTargetZip);
		}
	}

	private static Dataset createFreshDataset() throws IOException {
		File datasetDir = new File(directory, Constants.DATASET_DIR);
		FileUtils.forceMkdir(datasetDir);
		dataset = TDBFactory.createDataset(datasetDir.getAbsolutePath());
		dataset.begin(ReadWrite.WRITE);
		dataset.getDefaultModel().removeAll();
		List<String> toRemove = new ArrayList<>();
		Iterator<String> it = dataset.listNames();
		while (it.hasNext()) {
			toRemove.add(it.next());
		}
		for (String name : toRemove) {
			dataset.removeNamedModel(name);
		}
		dataset.addNamedModel(Constants.CONFIG, ModelFactory.createDefaultModel());
		dataset.commit();
		return dataset;
	}

	private static void testRepository(Repository repository, boolean checkExamples) {
		for (Version version : repository.getVersions()) {
			try {
				String versionTestSuiteName = version.toString() + " - testing repository structure";
				new CheckoutJob(versionTestSuiteName).checkoutVersion(version);
				new CheckRepositoryStructure(versionTestSuiteName).check(version);
			} catch (SAREFPipelineException ex) {
				LOG.error("Error while testing repository structure " + version, ex);
				continue;
			}

			try {
				String ontologyTestSuiteName = version.toString() + " - testing ontology file";
				testSuiteNames.put(version.getUri(), ontologyTestSuiteName);
				new ReadOntology(ontologyTestSuiteName).doJob(dataset, version);
			} catch (SAREFPipelineException ex) {
				LOG.error(version.toString() + " Found errors for " + version.toString()
						+ ". This version and all the examples will be ignored.", ex);
				continue;
			}

			if (!checkExamples) {
				continue;
			}
			File examplesDir = new File(version.getRepository().getDirectory(), "examples");
			try {
				for (Iterator<Path> it = Files.walk(examplesDir.toPath()).filter(p -> {
					return ttlMatcher.matches(p);
				}).iterator();it.hasNext();) {
					Path p = it.next();
					Path rel = examplesDir.toPath().relativize(p);
					String iri = version.getResource().getURI() + "example/"
							+ rel.toString().substring(0, rel.toString().length() - 4);
					String exampleTestSuiteName = version.toString() + " testing example " + rel;
					testSuiteNames.put(iri, exampleTestSuiteName);
					File exampleFile = p.toFile();
					try {
						new ReadExamples(exampleTestSuiteName).doJob(dataset, version, iri, exampleFile);
					} catch (SAREFPipelineException ex) {
						LOG.error(version.toString() + " Found errors for example  " + rel
								+ ". This example will be ignored.");
					}
				}
			} catch (Exception ex) {
				LOG.error(version.toString() + " Error while walking through the examples. They will be ignored.", ex);
				continue;
			}
		}
	}

	private static void checkOWLProfile() {
		dataset.begin(ReadWrite.READ);
		Model config = dataset.getNamedModel(Constants.CONFIG);
		for (ResIterator it = config.listResourcesWithProperty(RDF.type, EX.OntologyVersion); it.hasNext();) {
			String ontology = it.next().getURI();
			String testSuiteName = testSuiteNames.get(ontology);
			try {
				new CheckOWLProfile(testSuiteName).doJob(dataset, ontology);
			} catch (SAREFPipelineException ex) {
				LOG.warn("Found errors for ontology " + ontology, ex);
			}
		}
		for (ResIterator it = config.listResourcesWithProperty(RDF.type, EX.Example); it.hasNext();) {
			String ontology = it.next().getURI();
			String testSuiteName = testSuiteNames.get(ontology);
			try {
				new CheckOWLProfile(testSuiteName).doJob(dataset, ontology);
			} catch (SAREFPipelineException ex) {
				LOG.warn("Found errors for example " + ontology, ex);
			}
		}
		dataset.end();
	}

	private static SPARQLExtStreamManager initializeStreamManager() throws IOException, URISyntaxException {
		URI uri = Main.class.getClassLoader().getResource("documentation").toURI();
		Path dirPath;
		if (uri.getScheme().equals("jar")) {
			FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.<String, Object>emptyMap());
			dirPath = fileSystem.getPath("/documentation");
		} else {
			dirPath = Paths.get(uri);
		}
		LocatorFileAccept locator = new LocatorFileAccept(uri.getPath());
		LocationMapperAccept mapper = new LocationMapperAccept();
		SPARQLExtStreamManager sm = SPARQLExtStreamManager.makeStreamManager(locator);
		sm.setLocationMapper(mapper);
		Files.walk(dirPath).forEach((p) -> {
			String relativePath = dirPath.relativize(p).toString().replace("\\", "/");
			String fileurl = BASE_DOC + relativePath;
			if (uri.getScheme().equals("jar")) {
				mapper.addAltEntry(fileurl, p.toString().substring(1));
			} else {
				mapper.addAltEntry(fileurl, p.toString());
			}
		});
		return sm;
	}

	private static void resetCheckout(Repository repository) {
		try (Git git = Git.open(repository.getDirectory())) {
			String currentBranch = repository.getCurrentBranch();
			if (currentBranch != null) {
				git.checkout().setName(currentBranch).call();
			}
		} catch (IOException | GitAPIException ex) {
			LOG.warn("Error while reseting repository " + repository, ex);
		}
	}

	private static void reportAndExit(int code) {
		try {
			File report = new File(target, "report_output.xml");
			JAXBContext jaxbContext = JAXBContext.newInstance(TestSuites.class);

			Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
			jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
			jaxbMarshaller.marshal(testSuites, report);
			final StringWriter sw = new StringWriter();
			jaxbMarshaller.marshal(testSuites, sw);

			if (generateSite) {
				// generate the report.html
				File reportHTML = new File(directory, Constants.SITE_DIR + File.separator + "report.html");
				try (IndentedWriter writer = new IndentedWriter(new FileOutputStream(reportHTML));) {
					Context context = ContextUtils.build(writer).setBase(Constants.BASE).setDebugTemplate(verbose)
							.setStreamManager(streamManager).build();
					BindingHashMap binding = new BindingHashMap();
					binding.add(VAR_TEST_SUITES, NodeFactory.createLiteral(sw.toString()));
					List<Binding> bindings = new ArrayList<>();
					bindings.add(binding);
					String query = IOUtils.toString(
							streamManager
									.open(new LookUpRequest("documentation/report/main.rqg", SPARQLExt.MEDIA_TYPE)),
							StandardCharsets.UTF_8);
					RootPlan reportPlan = PlanFactory.create(query, BASE_DOC);
					reportPlan.execTemplateStream(bindings, context);
				}

				if (openBrowser) {
					if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
						Desktop.getDesktop().browse(reportHTML.toURI());
					} else {
						System.out.println("\n\n\nURL to the SAREF pipeline report:\n" + reportHTML.toURI());
					}
				}
			}
		} catch (JAXBException | IOException ex) {
			LOG.error("Exception:", ex);
			ex.printStackTrace();
		}

		if (!isTheConsoleActive) {
			System.exit(code);
		}
	}
}
