/*
 * Copyright (C) 2016-2021 DiffPlug
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.diffplug.gradle.eclipserunner;


import com.diffplug.common.base.Box;
import com.diffplug.common.base.Errors;
import com.diffplug.common.base.Preconditions;
import com.diffplug.gradle.FileMisc;
import com.diffplug.gradle.eclipserunner.launcher.Main;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import org.eclipse.core.runtime.adaptor.EclipseStarter;
import org.osgi.framework.BundleContext;

/**
 * Given a directory containing osgi jars, this class
 * verifies that the core bundles are available, and
 * provides an API for instantiating the OSGi runtime
 * and accessing its {@link BundleContext}.
 */
public class EclipseIniLauncher {
	final EclipseIni eclipseIni;

	/**
	 * Wraps a directory of jars in the launcher API, and
	 * ensures the the directory contains the plugins required
	 * to run a barebones equinox instance.
	 */
	public EclipseIniLauncher(File installationRoot) throws FileNotFoundException, IOException {
		FileMisc.assertMacApp(installationRoot);
		Objects.requireNonNull(installationRoot);
		// populate the plugins
		eclipseIni = EclipseIni.parseFrom(new File(installationRoot, FileMisc.macContentsEclipse() + "eclipse.ini"));
	}

	/**
	 * Opens the eclipse runtime, and returns an instance of
	 * {@link Running} which allows access to the underlying
	 * {@link BundleContext}.
	 */
	public Running open() throws Exception {
		return new Running();
	}

	/** Runs the equinox launcher (calls {@link #open()} and immediately closes it). */
	public void run() throws Exception {
		try (Running running = open()) {
			running.run();
		}
	}

	/**
	 * Represents a running instance of the equinox
	 * OSGi container.  Shuts down the container when
	 * you call {@link #close()}.
	 */
	public class Running implements AutoCloseable {
		final BundleContext bundleContext;

		private Running() throws Exception {
			Box.Nullable<BundleContext> context = Box.Nullable.ofNull();
			Main main = new Main() {
				@SuppressFBWarnings(value = "DMI_THREAD_PASSED_WHERE_RUNNABLE_EXPECTED", justification = "splashHandler is a thread rather than a runnable.  Almost definitely a small bug, " +
						"but there's a lot of small bugs in the copy-pasted launcher code.  It's battle-tested, FWIW.")
				@Override
				protected void invokeFramework(String[] passThruArgs, URL[] bootPath) throws Exception {
					context.set(EclipseStarter.startup(passThruArgs, splashHandler));
				}
			};
			main.basicRun(eclipseIni.getLinesAsArray());
			this.bundleContext = Objects.requireNonNull(context.get());
		}

		/** The {@link BundleContext} of the running eclipse instance. */
		public BundleContext bundleContext() {
			return bundleContext;
		}

		/** Runs an eclipse application, as specified by the `-application` argument. */
		private void run() throws Exception {
			Object result = EclipseStarter.run(null);
			Preconditions.checkState(Integer.valueOf(0).equals(result), "Unexpected return=0, was: %s", result);
		}

		/** Shutsdown the eclipse instance. */
		@Override
		public void close() throws Exception {
			EclipseStarter.shutdown();
		}
	}

	/** Parses `configuration/org.eclipse.equinox.simpleconfigurator/bundles.info` into a list of files. */
	public static List<File> parseBundlesDotInfo(File eclipseRoot) {
		try {
			List<File> files = new ArrayList<>();
			File bundlesDotInfo = new File(eclipseRoot, FileMisc.macContentsEclipse() + "configuration/org.eclipse.equinox.simpleconfigurator/bundles.info");
			String str = new String(Files.readAllBytes(bundlesDotInfo.toPath()));
			String[] lines = str.split("\n");
			for (String line : lines) {
				String[] pieces = line.split(",");
				if (pieces != null && pieces.length > 2) {
					File file = new File(eclipseRoot, pieces[2]);
					if (file.exists()) {
						files.add(file);
					}
				}
			}
			return files;
		} catch (IOException e) {
			throw Errors.asRuntime(e);
		}
	}
}

@@ -764,16 +764,54 @@
 itions;%0A
+import com.diffplug.common.swt.os.OS;%0A
 import c
@@ -4526,24 +4526,192 @@
 ngth %3E 2) %7B%0A
+%09%09%09%09%09String path = pieces%5B2%5D;%0A%09%09%09%09%09if (OS.getNative().isMac()) %7B%0A%09%09%09%09%09%09if (path.startsWith(%22../../%22)) %7B%0A%09%09%09%09%09%09%09path = path.substring(%22../../%22.length());%0A%09%09%09%09%09%09%7D%0A%09%09%09%09%09%7D%0A
 %09%09%09%09%09File fi
@@ -4738,24 +4738,19 @@
 eRoot, p
-ieces%5B2%5D
+ath
 );%0A%09%09%09%09%09

Fix bundle grabbing on mac.