package net.classicube.selfupdater;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;

public class Program {

    static final String MacSuffix = "/Library/Application Support";
    static final String LauncherDirName = "net.classicube.launcher";
    static final String LauncherJarName = "ClassiCubeLauncher.jar";
    static final String UpdatedLauncherJarName = "ClassiCubeLauncher.new.jar";
    static final String LauncherEntryClass = "net.classicube.launcher.EntryPoint";
    static final String LauncherEntryMethod = "main";
    static final String LauncherDownload = "TODO";

    public static void main(String[] args) throws IOException {
        // Find launcher jars
        File userDir = findUserDir();
        File launcherDir = new File(userDir, LauncherDirName);
        File launcherJar = new File(launcherDir, LauncherJarName);
        File updatedJarFile = new File(launcherDir, UpdatedLauncherJarName);

        // Update launcher.jar, if needed
        if (updatedJarFile.exists()) {
            try {
                replaceFile(updatedJarFile, launcherJar);
            } catch (IOException ex) {
                System.err.println("ClassiCubeLauncher: Error updating: " + ex);
            }
        }
        
        if(!launcherJar.exists()){
            downloadLauncherJar(launcherJar);
        }

        // Hand control over to the launcher
        try {
            Class<?> lpClass = loadLauncher(launcherJar);
            Method entryPoint = lpClass.getMethod(LauncherEntryMethod, String[].class);
            entryPoint.invoke(null, (Object)new String[0]);
        } catch (IOException | NoSuchMethodException | ClassNotFoundException |
                IllegalAccessException | InvocationTargetException ex) {
            System.err.println("ClassiCubeLauncher: Error initializing: " + ex);
            System.exit(1);
        }
    }

    // Find OS-specific application data dir
    static File findUserDir() {
        String os = System.getProperty("os.name");
        String path;
        if (os.contains("Windows")) {
            path = System.getenv("AppData");
        } else {
            path = System.getProperty("user.home");
            if (os.contains("MacOS")) {
                path += MacSuffix;
            }
        }
        return new File(path);
    }

    // Replace contents of destFile with sourceFile
    static void replaceFile(File sourceFile, File destFile)
            throws IOException {
        if (!destFile.exists()) {
            destFile.createNewFile();
        }

        FileChannel source = null;
        FileChannel destination = null;

        try {
            source = new FileInputStream(sourceFile).getChannel();
            destination = new FileOutputStream(destFile).getChannel();
            destination.transferFrom(source, 0, source.size());
        } finally {
            if (source != null) {
                source.close();
            }
            if (destination != null) {
                destination.close();
            }
        }

        sourceFile.delete();
    }

    // Load the entry point from
    static Class<?> loadLauncher(File launcherJar)
            throws IOException, ClassNotFoundException {
        URL[] urls = {new URL("jar:file:" + launcherJar + "!/")};
        URLClassLoader loader = URLClassLoader.newInstance(urls);
        return loader.loadClass(LauncherEntryClass);
    }

    private static void downloadLauncherJar(File launcherJar) throws MalformedURLException, IOException {
        URL website = new URL("http://www.website.com/information.asp");
        ReadableByteChannel rbc = Channels.newChannel(website.openStream());
        FileOutputStream fos = new FileOutputStream(launcherJar);
        fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
    }
}
@@ -934,12 +934,72 @@
  = %22
-TODO
+http://www.classicube.net/static/launcher/ClassiCubeLauncher.jar
 %22;%0A%0A
@@ -1639,24 +1639,16 @@
       %7D%0A
-        
 %0A       
@@ -1650,16 +1650,17 @@
       if
+ 
 (!launch
@@ -1674,16 +1674,17 @@
 xists())
+ 
 %7B%0A      
@@ -1983,16 +1983,17 @@
 (Object)
+ 
 new Stri
@@ -2945,32 +2945,37 @@
      %7D%0A%0A        
+try (
 FileChannel sour
@@ -2973,90 +2973,8 @@
 nnel
- source = null;%0A        FileChannel destination = null;%0A%0A        try %7B%0A           
  sou
@@ -3015,33 +3015,35 @@
 le).getChannel()
-;
+) %7B
 %0A            des
@@ -3031,32 +3031,49 @@
 ) %7B%0A            
+try (FileChannel 
 destination = ne
@@ -3113,17 +3113,19 @@
 hannel()
-;
+) %7B
 %0A       
@@ -3121,32 +3121,36 @@
 ) %7B%0A            
+    
 destination.tran
@@ -3189,184 +3189,8 @@
 ));%0A
-        %7D finally %7B%0A            if (source != null) %7B%0A                source.close();%0A            %7D%0A            if (destination != null) %7B%0A                destination.close();%0A
     
@@ -3719,48 +3719,24 @@
 URL(
-%22http://www.website.com/information.asp%22
+LauncherDownload
 );%0A 
@@ -3815,24 +3815,29 @@
 ));%0A        
+try (
 FileOutputSt
@@ -3880,26 +3880,31 @@
 cherJar)
-;%0A
+) %7B%0A   
         
 fos.getC
@@ -3895,16 +3895,17 @@
         
+ 
 fos.getC
@@ -3951,15 +3951,25 @@
 VALUE);%0A
+        %7D%0A
     %7D%0A%7D

Set LauncherDownload URL in the self-updater