/*
 * Copyright 2016 FabricMC
 *
 * 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
 *
 *     http://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 net.fabricmc.loader.impl.launch.server;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Properties;

import net.fabricmc.loader.impl.launch.knot.KnotServer;
import net.fabricmc.loader.impl.util.SystemProperties;
import net.fabricmc.loader.impl.util.UrlUtil;

public class FabricServerLauncher {
	private static final ClassLoader parentLoader = FabricServerLauncher.class.getClassLoader();
	private static String mainClass = KnotServer.class.getName();

	public static void main(String[] args) {
		URL propUrl = parentLoader.getResource("fabric-server-launch.properties");

		if (propUrl != null) {
			Properties properties = new Properties();

			try (InputStream is = propUrl.openStream()) {
				properties.load(is);
			} catch (IOException e) {
				e.printStackTrace();
			}

			if (properties.containsKey("launch.mainClass")) {
				mainClass = properties.getProperty("launch.mainClass");
			}
		}

		boolean dev = Boolean.parseBoolean(System.getProperty(SystemProperties.DEVELOPMENT, "false"));

		if (!dev) {
			try {
				setup(args);
			} catch (Exception e) {
				throw new RuntimeException("Failed to setup Fabric server environment!", e);
			}
		} else {
			launch(mainClass, FabricServerLauncher.class.getClassLoader(), args);
		}
	}

	private static void launch(String mainClass, ClassLoader loader, String[] args) {
		try {
			Class<?> c = loader.loadClass(mainClass);
			c.getMethod("main", String[].class).invoke(null, (Object) args);
		} catch (Exception e) {
			throw new RuntimeException("An exception occurred when launching the server!", e);
		}
	}

	private static void setup(String... runArguments) throws IOException {
		if (System.getProperty(SystemProperties.GAME_JAR_PATH) == null) {
			System.setProperty(SystemProperties.GAME_JAR_PATH, getServerJarPath());
		}

		File serverJar = new File(System.getProperty(SystemProperties.GAME_JAR_PATH));

		if (!serverJar.exists()) {
			System.err.println("Could not find Minecraft server .JAR (" + serverJar.getName() + ")!");
			System.err.println();
			System.err.println("Fabric's server-side launcher expects the server .JAR to be provided.");
			System.err.println("You can edit its location in fabric-server-launcher.properties.");
			System.err.println();
			System.err.println("Without the official Minecraft server .JAR, Fabric Loader cannot launch.");
			throw new RuntimeException("Searched for '" + serverJar.getName() + "' but could not find it.");
		}

		try {
			URLClassLoader newClassLoader = new InjectingURLClassLoader(new URL[] { FabricServerLauncher.class.getProtectionDomain().getCodeSource().getLocation(), UrlUtil.asUrl(serverJar) }, parentLoader, "com.google.common.jimfs.");
			Thread.currentThread().setContextClassLoader(newClassLoader);
			launch(mainClass, newClassLoader, runArguments);
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}

	private static String getServerJarPath() throws IOException {
		// Pre-load "fabric-server-launcher.properties"
		File propertiesFile = new File("fabric-server-launcher.properties");
		Properties properties = new Properties();

		if (propertiesFile.exists()) {
			try (FileInputStream stream = new FileInputStream(propertiesFile)) {
				properties.load(stream);
			}
		}

		// Most popular Minecraft server hosting platforms do not allow
		// passing arbitrary arguments to the server .JAR. Meanwhile,
		// Mojang's default server filename is "server.jar" as of
		// a few versions... let's use this.
		if (!properties.containsKey("serverJar")) {
			properties.put("serverJar", "server.jar");

			try (FileOutputStream stream = new FileOutputStream(propertiesFile)) {
				properties.store(stream, null);
			}
		}

		return (String) properties.get("serverJar");
	}
}

@@ -671,31 +671,27 @@
 java.io.
-FileInputStream
+IOException
 ;%0Aimport
@@ -699,23 +699,18 @@
 java.io.
-FileOut
+In
 putStrea
@@ -702,32 +702,38 @@
 a.io.InputStream
+Reader
 ;%0Aimport java.io
@@ -729,35 +729,30 @@
 ort java.io.
-IOException
+Reader
 ;%0Aimport jav
@@ -756,27 +756,22 @@
 java.io.
-InputStream
+Writer
 ;%0Aimport
@@ -813,24 +813,149 @@
 lassLoader;%0A
+import java.nio.charset.StandardCharsets;%0Aimport java.nio.file.Files;%0Aimport java.nio.file.Path;%0Aimport java.nio.file.Paths;%0A
 import java.
@@ -1538,33 +1538,90 @@
 ream
- is = propUrl.openStream(
+Reader reader = new InputStreamReader(propUrl.openStream(), StandardCharsets.UTF_8
 )) %7B
@@ -1641,18 +1641,22 @@
 es.load(
-is
+reader
 );%0A%09%09%09%7D 
@@ -3901,20 +3901,20 @@
 ties%22%0A%09%09
-File
+Path
  propert
@@ -3923,24 +3923,25 @@
 sFile = 
-new File
+Paths.get
 (%22fabric
@@ -4017,24 +4017,37 @@
 es();%0A%0A%09%09if 
+(Files.exists
 (propertiesF
@@ -4049,24 +4049,16 @@
 tiesFile
-.exists(
 )) %7B%0A%09%09%09
@@ -4066,52 +4066,47 @@
 ry (
-FileInputStream stream = new FileInputStream
+Reader reader = Files.newBufferedReader
 (pro
@@ -4141,22 +4141,22 @@
 es.load(
-st
 rea
-m
+der
 );%0A%09%09%09%7D%0A
@@ -4494,54 +4494,47 @@
 ry (
-FileOutputStream stream = new FileOutputStream
+Writer writer = Files.newBufferedWriter
 (pro
@@ -4574,14 +4574,14 @@
 ore(
-stream
+writer
 , nu

Fix FabricServerLauncher using the system charset instead of UTF-8