package common.init;

import java.awt.Desktop;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.Thread.UncaughtExceptionHandler;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import javax.imageio.ImageIO;

import common.log.NettyLogger;

public abstract class Registry {
	private static boolean crashed;
	
	private static void register() {
		NameRegistry.register();
		BlockRegistry.register();
		FlammabilityRegistry.register();
        SpeciesRegistry.register();
        EntityRegistry.registerEggs();
		ItemRegistry.register();
		TileRegistry.register();
        CraftingRegistry.register();
        SmeltingRegistry.register();
        EntityRegistry.register();
		DispenserRegistry.register();
	}
	
	public static void setup(String thread) {
		Thread.currentThread().setName(thread);
		Locale.setDefault(Locale.ROOT);
		Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
			public void uncaughtException(Thread thread, Throwable e) {
				System.err.println("Fehler in Thread '" + thread.getName() + "'");
				e.printStackTrace(System.err);
				if(crashed)
					System.exit(1);
				if(e instanceof OutOfMemoryError) {
					System.gc();
					System.gc();
				}
				if(!thread.getName().startsWith("Thread-") || e instanceof OutOfMemoryError) {
					System.err.println("Beende!");
					crashed = true;
					if(System.getProperty("crash.nodump") == null) {
						PrintStream ps = null;
						File report = null;
						try {
							Date date = new Date();
							File file = new File("crash-" + new SimpleDateFormat("dd.MM.yyyy_HH.mm.ss").format(date) + ".txt");
							FileOutputStream out = new FileOutputStream(file);
							ps = new PrintStream(out);
							ThreadMXBean bean = ManagementFactory.getThreadMXBean();
							ThreadInfo[] info = bean.dumpAllThreads(true, true);
							StringBuilder sb = new StringBuilder();
							Error error = new Error();
							for(ThreadInfo threadinfo : info) {
								if(threadinfo.getThreadId() == thread.getId())
									error.setStackTrace(threadinfo.getStackTrace());
								sb.append(threadinfo);
							}
							ps.println("************************************************ " + new SimpleDateFormat("dd.MM.yyyy HH:mm:ss").format(date) + " ************************************************");
							ps.println();
							ps.println("\"Wie haste das denn nu wieder geschafft, Bursche?\"");
							ps.println("Unerwarteter Fehler in Thread '" + thread.getName() + "':");
							e.printStackTrace(ps);
							ps.println();
							ps.println("---------------------------------------------- Thread-Dump (" + info.length + " Threads) ---------------------------------------------");
							ps.println();
							ps.print(sb.toString());
							ps.println("*********************************************************************************************************************");
							report = file;
						}
						catch(Throwable t) {
							System.err.println("Konnte Absturzbericht nicht speichern:");
							t.printStackTrace(System.err);
						}
						finally {
							if(ps != null)
								ps.close();
						}
						if(report != null) {
							System.err.println("Absturzbericht gespeichert unter " + report.getPath());
							try {
								Desktop.getDesktop().browse(report.toURI());
							}
							catch(Throwable e1) {
								System.err.println("Konnte " + report + " nicht öffnen: " + e1);
							}
						}
					}
					System.exit(1);
				}
			}
		});
		ImageIO.setUseCache(false);
		Thread timer = new Thread("Timer Hack Thread") {
			public void run() {
				while(true) {
					try {
						Thread.sleep(2147483647L);
					}
					catch(InterruptedException e) {
						;
					}
				}
			}
		};
		timer.setDaemon(true);
		timer.start();
		System.setProperty("java.net.preferIPv4Stack", "true");
		NettyLogger.init();
		register();
	}
	
	public static void addShutdownHook(final Runnable hook) {
		Runtime.getRuntime().addShutdownHook(new Thread("Game Shutdown Thread") {
			public void run() {
				if(!crashed) {
					try {
						hook.run();
					}
					catch(Throwable e) {
						e.printStackTrace();
					}
				}
			}
		});
	}
}
