Index: /AE/installer2/src/net/oni2/aeinstaller/AEInstaller.properties
===================================================================
--- /AE/installer2/src/net/oni2/aeinstaller/AEInstaller.properties	(revision 599)
+++ /AE/installer2/src/net/oni2/aeinstaller/AEInstaller.properties	(revision 600)
@@ -1,4 +1,4 @@
 appname=AE Installer 2
-appversion=0.41
+appversion=0.50
 
 invalidPath.title=Wrong directory
Index: /AE/installer2/src/net/oni2/aeinstaller/AEInstaller2.java
===================================================================
--- /AE/installer2/src/net/oni2/aeinstaller/AEInstaller2.java	(revision 599)
+++ /AE/installer2/src/net/oni2/aeinstaller/AEInstaller2.java	(revision 600)
@@ -8,5 +8,4 @@
 import java.net.URL;
 import java.util.ResourceBundle;
-import java.util.TreeSet;
 
 import javax.imageio.ImageIO;
@@ -20,9 +19,8 @@
 import net.oni2.aeinstaller.backend.Paths;
 import net.oni2.aeinstaller.backend.Settings;
+import net.oni2.aeinstaller.backend.Settings.Platform;
 import net.oni2.aeinstaller.backend.SizeFormatter;
-import net.oni2.aeinstaller.backend.Settings.Platform;
 import net.oni2.aeinstaller.backend.StuffToRefactorLater;
 import net.oni2.aeinstaller.backend.depot.DepotManager;
-import net.oni2.aeinstaller.backend.mods.Mod;
 import net.oni2.aeinstaller.backend.oni.Installer;
 import net.oni2.aeinstaller.backend.oni.OniSplit;
@@ -57,5 +55,4 @@
 			app.setApplicationIconImage(img);
 		} catch (IOException e) {
-			// TODO Auto-generated catch block
 			e.printStackTrace();
 		}
@@ -137,7 +134,12 @@
 		System.out.println("Globalized:" + Installer.isEditionInitialized());
 
-		System.out.println("Free space on temp: " + SizeFormatter.format(Paths.getTempPath().getUsableSpace(), 3));
-		System.out.println("Free space on Jar:  " + SizeFormatter.format(Paths.getInstallerPath().getUsableSpace(), 3));
-		
+		System.out
+				.println("Free space on temp: "
+						+ SizeFormatter.format(Paths.getTempPath()
+								.getUsableSpace(), 3));
+		System.out.println("Free space on Jar:  "
+				+ SizeFormatter.format(Paths.getInstallerPath()
+						.getUsableSpace(), 3));
+
 		if (!StuffToRefactorLater.verifyRunningDirectory()) {
 			JOptionPane.showMessageDialog(null,
@@ -148,11 +150,7 @@
 				return;
 			}
-		} else {
-			Installer.initializeEdition();
-			Installer.install(new TreeSet<Mod>());
 		}
 
 		SwingUtilities.invokeLater(new Runnable() {
-
 			public void run() {
 				try {
Index: /AE/installer2/src/net/oni2/aeinstaller/Images.properties
===================================================================
--- /AE/installer2/src/net/oni2/aeinstaller/Images.properties	(revision 599)
+++ /AE/installer2/src/net/oni2/aeinstaller/Images.properties	(revision 600)
@@ -25,4 +25,6 @@
 img.redo=/net/oni2/aeinstaller/images/tango/edit-redo.png
 img.refresh=/net/oni2/aeinstaller/images/tango/view-refresh.png
+img.tools=/net/oni2/aeinstaller/images/open_icon_library/tools-hammer_and_nails.png
 
 img.ae=/net/oni2/aeinstaller/images/AElogo.png
+img.install=/net/oni2/aeinstaller/images/open_icon_library/run-build-install-root.png
Index: /AE/installer2/src/net/oni2/aeinstaller/backend/QuickAppExecution.java
===================================================================
--- /AE/installer2/src/net/oni2/aeinstaller/backend/QuickAppExecution.java	(revision 600)
+++ /AE/installer2/src/net/oni2/aeinstaller/backend/QuickAppExecution.java	(revision 600)
@@ -0,0 +1,43 @@
+package net.oni2.aeinstaller.backend;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.List;
+import java.util.Vector;
+
+/**
+ * @author Christian Illy
+ */
+public class QuickAppExecution {
+
+	/**
+	 * Execute a short running application
+	 * 
+	 * @param cmdLine
+	 *            List of command and arguments
+	 * @return List of output lines
+	 * @throws IOException
+	 *             Exc
+	 */
+	public static Vector<String> execute(List<String> cmdLine)
+			throws IOException {
+		ProcessBuilder pb = new ProcessBuilder(cmdLine);
+		pb.redirectErrorStream(true);
+		Process proc = pb.start();
+
+		InputStream is = proc.getInputStream();
+		InputStreamReader isr = new InputStreamReader(is);
+		BufferedReader br = new BufferedReader(isr);
+
+		String line;
+		Vector<String> lines = new Vector<String>();
+
+		while ((line = br.readLine()) != null) {
+			lines.add(line);
+		}
+		return lines;
+	}
+
+}
Index: /AE/installer2/src/net/oni2/aeinstaller/backend/Settings.java
===================================================================
--- /AE/installer2/src/net/oni2/aeinstaller/backend/Settings.java	(revision 599)
+++ /AE/installer2/src/net/oni2/aeinstaller/backend/Settings.java	(revision 600)
@@ -10,5 +10,4 @@
 import java.util.Vector;
 
-import net.oni2.aeinstaller.backend.app_launcher.QuickAppExecution;
 
 import com.thoughtworks.xstream.XStream;
@@ -112,5 +111,4 @@
 					res = QuickAppExecution.execute(cmd);
 				} catch (IOException e) {
-					// TODO Auto-generated catch block
 					e.printStackTrace();
 				}
Index: /AE/installer2/src/net/oni2/aeinstaller/backend/depot/DepotManager.java
===================================================================
--- /AE/installer2/src/net/oni2/aeinstaller/backend/depot/DepotManager.java	(revision 599)
+++ /AE/installer2/src/net/oni2/aeinstaller/backend/depot/DepotManager.java	(revision 600)
@@ -18,4 +18,5 @@
 import net.oni2.aeinstaller.backend.depot.model.TaxonomyTerm;
 import net.oni2.aeinstaller.backend.depot.model.TaxonomyVocabulary;
+import net.oni2.aeinstaller.backend.mods.ECompatiblePlatform;
 import net.oni2.aeinstaller.backend.network.DrupalJSONQuery;
 
@@ -287,20 +288,46 @@
 
 	/**
-	 * @return Mod-Nodes
-	 */
-	public Vector<NodeMod> getModPackageNodes() {
-		Vector<NodeMod> result = new Vector<NodeMod>();
-		TaxonomyTerm tt = getTaxonomyTerm(DepotConfig.getTaxonomyName_InstallType_Package());
-		if (tt == null)
-			return result;
-
-		int packageterm_id = tt.getTid();
-
+	 * Get a node by node id
+	 * 
+	 * @param id
+	 *            Node id
+	 * @return Node
+	 */
+	public Node getNodeById(int id) {
+		return nodes.get(id);
+	}
+
+	/**
+	 * Get a Mod-Node by a given package number
+	 * 
+	 * @param packageNumber
+	 *            Package number to find
+	 * @return The Mod-Node or null
+	 */
+	public NodeMod getNodeByPackageNumber(int packageNumber) {
 		Vector<Node> files = getNodesByType(DepotConfig.getNodeType_Mod());
 		for (Node n : files) {
 			if (n instanceof NodeMod) {
 				NodeMod nm = (NodeMod) n;
-				if (nm.getTaxonomyTerms().get(vocabId_instmethod)
-						.contains(packageterm_id))
+				if (nm.getPackageNumber() == packageNumber)
+					return nm;
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * @return Mod-Nodes
+	 */
+	public Vector<NodeMod> getModPackageNodes() {
+		Vector<NodeMod> result = new Vector<NodeMod>();
+		String instMethName = DepotConfig.getTaxonomyName_InstallType_Package();
+
+		Vector<Node> files = getNodesByType(DepotConfig.getNodeType_Mod());
+		for (Node n : files) {
+			if (n instanceof NodeMod) {
+				NodeMod nm = (NodeMod) n;
+				if (nm.getInstallMethod().getName()
+						.equalsIgnoreCase(instMethName))
 					result.add(nm);
 			}
@@ -317,16 +344,15 @@
 	 */
 	public boolean isModValidOnPlatform(NodeMod node, Settings.Platform platform) {
-		int termId = node.getTaxonomyTerms().get(vocabId_platform).iterator()
-				.next();
-		String validPlatform = getTaxonomyTerm(termId).getName();
-		if (validPlatform.equalsIgnoreCase(DepotConfig.getTaxonomyName_Platform_Both()))
-			return true;
-
-		if ((platform == Platform.WIN) || (platform == Platform.LINUX))
-			return validPlatform.equalsIgnoreCase(DepotConfig.getTaxonomyName_Platform_Win());
-		else if (platform == Platform.MACOS)
-			return validPlatform.equalsIgnoreCase(DepotConfig.getTaxonomyName_Platform_Mac());
-		else
-			return false;
+		ECompatiblePlatform plat = node.getPlatform();
+		switch (plat) {
+			case BOTH:
+				return true;
+			case WIN:
+				return (platform == Platform.WIN)
+						|| (platform == Platform.LINUX);
+			case MACOS:
+				return (platform == Platform.MACOS);
+		}
+		return false;
 	}
 
@@ -344,17 +370,44 @@
 	 */
 	public boolean isModOfType(NodeMod node, HashSet<Integer> type, boolean or) {
-		boolean matching = true;
-		if (or)
-			matching = false;
+		boolean matching = !or;
+		HashSet<TaxonomyTerm> terms = node.getTypes();
 
 		for (int t : type) {
 			if (or)
-				matching |= node.getTaxonomyTerms().get(vocabId_type)
-						.contains(t);
+				matching |= terms.contains(t);
 			else
-				matching &= node.getTaxonomyTerms().get(vocabId_type)
-						.contains(t);
+				matching &= terms.contains(t);
 		}
 		return matching;
+	}
+
+	/**
+	 * @return VocabId of Platform vocabulary
+	 */
+	public int getVocabIdPlatform() {
+		return vocabId_platform;
+	}
+
+	/**
+	 * @return VocabId of Install method vocabulary
+	 */
+	public int getVocabIdInstMethod() {
+		return vocabId_instmethod;
+	}
+
+	/**
+	 * @return VocabId of Type vocabulary
+	 */
+	public int getVocabIdType() {
+		return vocabId_type;
+	}
+
+	/**
+	 * @param id
+	 *            ID of file to get
+	 * @return the file
+	 */
+	public File getFile(int id) {
+		return files.get(id);
 	}
 
Index: /AE/installer2/src/net/oni2/aeinstaller/backend/depot/model/NodeMod.java
===================================================================
--- /AE/installer2/src/net/oni2/aeinstaller/backend/depot/model/NodeMod.java	(revision 599)
+++ /AE/installer2/src/net/oni2/aeinstaller/backend/depot/model/NodeMod.java	(revision 600)
@@ -4,4 +4,8 @@
 import java.util.HashSet;
 import java.util.Vector;
+
+import net.oni2.aeinstaller.backend.depot.DepotConfig;
+import net.oni2.aeinstaller.backend.depot.DepotManager;
+import net.oni2.aeinstaller.backend.mods.ECompatiblePlatform;
 
 import org.json.JSONArray;
@@ -74,15 +78,73 @@
 
 	/**
-	 * @return the taxonomyTerms
+	 * @return Types
 	 */
-	public HashMap<Integer, HashSet<Integer>> getTaxonomyTerms() {
-		return taxonomyTerms;
+	public HashSet<TaxonomyTerm> getTypes() {
+		HashSet<TaxonomyTerm> tt = new HashSet<TaxonomyTerm>();
+		for (int t : taxonomyTerms.get(DepotManager.getInstance()
+				.getVocabIdType())) {
+			tt.add(DepotManager.getInstance().getTaxonomyTerm(t));
+		}
+		return tt;
 	}
 
 	/**
-	 * @return the fields
+	 * @return Install method
 	 */
-	public HashMap<String, String> getFields() {
-		return fields;
+	public TaxonomyTerm getInstallMethod() {
+		return DepotManager.getInstance().getTaxonomyTerm(
+				taxonomyTerms
+						.get(DepotManager.getInstance().getVocabIdInstMethod())
+						.iterator().next());
+	}
+
+	/**
+	 * @return Compatible platform
+	 */
+	public ECompatiblePlatform getPlatform() {
+		TaxonomyTerm term = DepotManager.getInstance().getTaxonomyTerm(
+				taxonomyTerms
+						.get(DepotManager.getInstance().getVocabIdPlatform())
+						.iterator().next());
+
+		String validPlatform = term.getName();
+		if (validPlatform.equalsIgnoreCase(DepotConfig
+				.getTaxonomyName_Platform_Both()))
+			return ECompatiblePlatform.BOTH;
+		if (validPlatform.equalsIgnoreCase(DepotConfig
+				.getTaxonomyName_Platform_Win()))
+			return ECompatiblePlatform.WIN;
+		if (validPlatform.equalsIgnoreCase(DepotConfig
+				.getTaxonomyName_Platform_Mac()))
+			return ECompatiblePlatform.MACOS;
+
+		return null;
+	}
+
+	/**
+	 * @return Creator of mod
+	 */
+	public String getCreator() {
+		if (fields.get("creator") != null)
+			return fields.get("creator");
+		else
+			return "";
+	}
+
+	/**
+	 * @return Version of mod
+	 */
+	public String getVersion() {
+		if (fields.get("version") != null)
+			return fields.get("version");
+		else
+			return "";
+	}
+
+	/**
+	 * @return Package number
+	 */
+	public int getPackageNumber() {
+		return Integer.parseInt(fields.get("package_number"));
 	}
 }
Index: /AE/installer2/src/net/oni2/aeinstaller/backend/mods/EBSLInstallType.java
===================================================================
--- /AE/installer2/src/net/oni2/aeinstaller/backend/mods/EBSLInstallType.java	(revision 600)
+++ /AE/installer2/src/net/oni2/aeinstaller/backend/mods/EBSLInstallType.java	(revision 600)
@@ -0,0 +1,19 @@
+package net.oni2.aeinstaller.backend.mods;
+
+/**
+ * @author Christian Illy
+ */
+public enum EBSLInstallType {
+	/**
+	 * No BSL files
+	 */
+	NONE,
+	/**
+	 * Normal BSL install mode
+	 */
+	NORMAL,
+	/**
+	 * BSL addon install mode
+	 */
+	ADDON
+}
Index: /AE/installer2/src/net/oni2/aeinstaller/backend/mods/ECompatiblePlatform.java
===================================================================
--- /AE/installer2/src/net/oni2/aeinstaller/backend/mods/ECompatiblePlatform.java	(revision 600)
+++ /AE/installer2/src/net/oni2/aeinstaller/backend/mods/ECompatiblePlatform.java	(revision 600)
@@ -0,0 +1,19 @@
+package net.oni2.aeinstaller.backend.mods;
+
+/**
+ * @author Christian Illy
+ */
+public enum ECompatiblePlatform {
+	/**
+	 * Only for Win
+	 */
+	WIN,
+	/**
+	 * Only for MacOS
+	 */
+	MACOS,
+	/**
+	 * Usable with both platforms
+	 */
+	BOTH
+}
Index: /AE/installer2/src/net/oni2/aeinstaller/backend/mods/Mod.java
===================================================================
--- /AE/installer2/src/net/oni2/aeinstaller/backend/mods/Mod.java	(revision 599)
+++ /AE/installer2/src/net/oni2/aeinstaller/backend/mods/Mod.java	(revision 600)
@@ -1,5 +1,19 @@
 package net.oni2.aeinstaller.backend.mods;
 
+import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.HashSet;
+
+import net.oni2.aeinstaller.backend.Paths;
+import net.oni2.aeinstaller.backend.Settings;
+import net.oni2.aeinstaller.backend.Settings.Platform;
+import net.oni2.aeinstaller.backend.depot.DepotManager;
+import net.oni2.aeinstaller.backend.depot.model.NodeMod;
+import net.oni2.aeinstaller.backend.depot.model.TaxonomyTerm;
 
 /**
@@ -7,33 +21,282 @@
  */
 public class Mod implements Comparable<Mod> {
-	private double aeVersion;
-	private int node;
-	private int packageNumber;
-
-	public double getAEVersion() {
-		return aeVersion;
-	}
-
+	// TODO: Dependencies/Conflicts
+	
+	private String name = "";
+	private int packageNumber = 0;
+
+	private HashSet<Type> types = new HashSet<Type>();
+	private ECompatiblePlatform platform = null;
+	private String version = "";
+	private String creator = "";
+	private EBSLInstallType bslInstallType = null;
+	private String description = "";
+	private double aeVersion = 0;
+	private int zipSize = 0;
+	private NodeMod node = null;
+	private net.oni2.aeinstaller.backend.depot.model.File file = null;
+
+	private long localTimestamp = 0;
+
+	/**
+	 * Create a new Mod entry from a given Mod-Node
+	 * 
+	 * @param nm
+	 *            Mod-Node
+	 */
+	public Mod(NodeMod nm) {
+		node = nm;
+		name = nm.getTitle();
+		packageNumber = nm.getPackageNumber();
+		for (TaxonomyTerm tt : nm.getTypes()) {
+			Type t = ModManager.getInstance().getTypeByName(tt.getName());
+			types.add(t);
+			t.addEntry(this);
+		}
+		platform = nm.getPlatform();
+		version = nm.getVersion();
+		creator = nm.getCreator();
+		if (nm.getBody() != null)
+			description = nm.getBody().getSafe_value();
+		file = DepotManager.getInstance().getFile(
+				nm.getUploads().firstElement().getFid());
+		zipSize = file.getFilesize();
+
+		if (isLocalAvailable())
+			updateLocalData();
+	}
+
+	/**
+	 * Update information for local package existence
+	 */
+	public void updateLocalData() {
+		File config = new File(getLocalPath(), "Mod_Info.cfg");
+		File timestamp = new File(getLocalPath(), "aei.cfg");
+		if (config.exists()) {
+			try {
+				FileInputStream fstream = new FileInputStream(config);
+				InputStreamReader isr = new InputStreamReader(fstream);
+				BufferedReader br = new BufferedReader(isr);
+				String strLine;
+				while ((strLine = br.readLine()) != null) {
+					if (strLine.indexOf("->") < 1)
+						continue;
+					if (strLine.indexOf("//") >= 0)
+						strLine = strLine.substring(0, strLine.indexOf("//"));
+					String[] split = strLine.split("->", 2);
+					String sName = split[0].trim();
+					String sVal = split[1].trim();
+					if (sName.equalsIgnoreCase("AEInstallVersion")) {
+						aeVersion = Double.parseDouble(sVal);
+					} else if (sName.equalsIgnoreCase("NameOfMod")) {
+						if (node == null)
+							name = sVal;
+					} else if (sName.equalsIgnoreCase("Creator")) {
+						if (node == null)
+							creator = sVal;
+					} else if (sName.equalsIgnoreCase("HasBsl")) {
+						if (sVal.equalsIgnoreCase("addon"))
+							bslInstallType = EBSLInstallType.ADDON;
+						else if (sVal.equalsIgnoreCase("yes"))
+							bslInstallType = EBSLInstallType.NORMAL;
+						else
+							bslInstallType = EBSLInstallType.NONE;
+					} else if (sName.equalsIgnoreCase("ModVersion")) {
+						if (node == null)
+							version = sVal;
+					} else if (sName.equalsIgnoreCase("Readme")) {
+						if (node == null)
+							description = sVal.replaceAll("\\\\n", "<br>");
+					}
+				}
+				isr.close();
+			} catch (FileNotFoundException e) {
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+		} else {
+			System.err.println("No config found for mod folder: "
+					+ getLocalPath().getPath());
+		}
+		if (timestamp.exists()) {
+			try {
+				FileInputStream fstream = new FileInputStream(timestamp);
+				InputStreamReader isr = new InputStreamReader(fstream);
+				BufferedReader br = new BufferedReader(isr);
+				String ts = br.readLine();
+				localTimestamp = Long.parseLong(ts);
+				isr.close();
+			} catch (FileNotFoundException e) {
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+		}
+	}
+
+	/**
+	 * Create a new Mod entry from the given local mod folder
+	 * 
+	 * @param folder
+	 *            Mod folder with Mod_Info.cfg
+	 */
+	public Mod(File folder) {
+		packageNumber = Integer.parseInt(folder.getName().substring(0, 5));
+		updateLocalData();
+
+		Type t = ModManager.getInstance().getTypeByName("-Local-");
+		types.add(t);
+		t.addEntry(this);
+
+		platform = ECompatiblePlatform.BOTH;
+	}
+
+	/**
+	 * @return has separate paths for win/mac/common or not
+	 */
 	public boolean hasSeparatePlatformDirs() {
 		return aeVersion >= 2;
 	}
 
+	/**
+	 * @return Path to local mod folder
+	 */
 	public File getLocalPath() {
-		// TODO
-		return null;
-	}
-	
-	public boolean newerAvailable() {
-		//TODO
-		return false;
-	}
-	
-	public boolean localAvailable() {
-		//TODO
-		return false;
-	}
-	
+		final String folderStart = String.format("%05d", packageNumber);
+
+		if (Paths.getModsPath().exists()) {
+			for (File f : Paths.getModsPath().listFiles(new FilenameFilter() {
+				@Override
+				public boolean accept(File d, String fn) {
+					return fn.startsWith(folderStart);
+				}
+			})) {
+				return f;
+			}
+		}
+
+		return new File(Paths.getModsPath(), folderStart);
+	}
+
+	/**
+	 * @return Is there a newer version on the depot?
+	 */
+	public boolean isNewerAvailable() {
+		if (node != null)
+			return node.getUploads().firstElement().getTimestamp() > localTimestamp;
+		else
+			return false;
+	}
+
+	/**
+	 * @return Mod exists within mods folder
+	 */
+	public boolean isLocalAvailable() {
+		return getLocalPath().exists();
+	}
+
+	/**
+	 * @return Name of mod
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * @return the package number
+	 */
 	public int getPackageNumber() {
 		return packageNumber;
+	}
+
+	/**
+	 * @return Types of mod
+	 */
+	public HashSet<Type> getTypes() {
+		return types;
+	}
+
+	/**
+	 * @return Compatible platforms
+	 */
+	public ECompatiblePlatform getPlatform() {
+		return platform;
+	}
+
+	/**
+	 * @return Version of mod
+	 */
+	public String getVersion() {
+		return version;
+	}
+
+	/**
+	 * @return Creator of mod
+	 */
+	public String getCreator() {
+		return creator;
+	}
+
+	/**
+	 * @return Installation type of BSL files
+	 */
+	public EBSLInstallType getBSLInstallType() {
+		return bslInstallType;
+	}
+
+	/**
+	 * @return Description of mod
+	 */
+	public String getDescription() {
+		return description;
+	}
+
+	/**
+	 * @return Size of Zip file on Depot
+	 */
+	public int getZipSize() {
+		return zipSize;
+	}
+
+	/**
+	 * @return Depot Mod-Node
+	 */
+	public NodeMod getNode() {
+		return node;
+	}
+
+	/**
+	 * @return Is a mod that is always installed?
+	 */
+	public boolean isDefaultMod() {
+		return packageNumber < 10000;
+	}
+
+	/**
+	 * @return Get the depot file entry
+	 */
+	public net.oni2.aeinstaller.backend.depot.model.File getFile() {
+		return file;
+	}
+
+	@Override
+	public String toString() {
+		return name;
+	}
+
+	/**
+	 * @return Is this mod valid on the running platform?
+	 */
+	public boolean validOnPlatform() {
+		ECompatiblePlatform plat = platform;
+		switch (plat) {
+			case BOTH:
+				return true;
+			case MACOS:
+				return (Settings.getPlatform() == Platform.MACOS);
+			case WIN:
+				return (Settings.getPlatform() == Platform.WIN)
+						|| (Settings.getPlatform() == Platform.LINUX);
+		}
+		return false;
 	}
 
Index: /AE/installer2/src/net/oni2/aeinstaller/backend/mods/ModManager.java
===================================================================
--- /AE/installer2/src/net/oni2/aeinstaller/backend/mods/ModManager.java	(revision 600)
+++ /AE/installer2/src/net/oni2/aeinstaller/backend/mods/ModManager.java	(revision 600)
@@ -0,0 +1,112 @@
+package net.oni2.aeinstaller.backend.mods;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Vector;
+
+import net.oni2.aeinstaller.backend.Paths;
+import net.oni2.aeinstaller.backend.depot.DepotManager;
+import net.oni2.aeinstaller.backend.depot.model.NodeMod;
+import net.oni2.aeinstaller.backend.depot.model.TaxonomyTerm;
+
+/**
+ * @author Christian Illy
+ */
+public class ModManager {
+	// Download mods
+	// Update mods
+
+	private static ModManager instance = new ModManager();
+
+	private HashMap<String, Type> types = new HashMap<String, Type>();
+	private HashMap<Integer, Mod> mods = new HashMap<Integer, Mod>();
+
+	/**
+	 * First initialization of ModManager
+	 */
+	public void init() {
+		types = new HashMap<String, Type>();
+		mods = new HashMap<Integer, Mod>();
+
+		types.put("-Local-", new Type("-Local-", null));
+
+		for (TaxonomyTerm tt : DepotManager.getInstance()
+				.getTaxonomyTermsByVocabulary(
+						DepotManager.getInstance().getVocabIdType())) {
+			types.put(tt.getName(), new Type(tt.getName(), tt));
+		}
+
+		HashMap<Integer, Mod> modFolders = new HashMap<Integer, Mod>();
+		if (Paths.getModsPath().exists()) {
+			for (File f : Paths.getModsPath().listFiles(new FileFilter() {
+				@Override
+				public boolean accept(File pathname) {
+					return pathname.isDirectory();
+				}
+			})) {
+				Mod m = new Mod(f);
+				modFolders.put(m.getPackageNumber(), m);
+			}
+		}
+
+		for (NodeMod nm : DepotManager.getInstance().getModPackageNodes()) {
+			if (nm.getUploads().size() == 1) {
+				Mod m = new Mod(nm);
+				mods.put(m.getPackageNumber(), m);
+				modFolders.remove(m.getPackageNumber());
+			}
+		}
+
+		for (Mod m : modFolders.values()) {
+			mods.put(m.getPackageNumber(), m);
+		}
+	}
+
+	public void refreshLocalMods() {
+		// TODO: evtl nur private e.g. als listener für downloads?
+	}
+
+	/**
+	 * @return Singleton instance
+	 */
+	public static ModManager getInstance() {
+		return instance;
+	}
+
+	Type getTypeByName(String name) {
+		return types.get(name);
+	}
+
+	/**
+	 * @return Collection of types which do have mods associated
+	 */
+	public Collection<Type> getTypesWithContent() {
+		Vector<Type> res = new Vector<Type>();
+		for (Type t : types.values()) {
+			if (t.getEntries().size() > 0)
+				res.add(t);
+		}
+		return res;
+	}
+
+	/**
+	 * @return Collection of mods
+	 */
+	public Collection<Mod> getMods() {
+		return mods.values();
+	}
+
+	/**
+	 * @return Mods which are always installed
+	 */
+	public Collection<Mod> getDefaultMods() {
+		Vector<Mod> res = new Vector<Mod>();
+		for (Mod m : mods.values()) {
+			if (m.isDefaultMod())
+				res.add(m);
+		}
+		return res;
+	}
+}
Index: /AE/installer2/src/net/oni2/aeinstaller/backend/mods/Type.java
===================================================================
--- /AE/installer2/src/net/oni2/aeinstaller/backend/mods/Type.java	(revision 600)
+++ /AE/installer2/src/net/oni2/aeinstaller/backend/mods/Type.java	(revision 600)
@@ -0,0 +1,51 @@
+package net.oni2.aeinstaller.backend.mods;
+
+import java.util.HashSet;
+
+import net.oni2.aeinstaller.backend.depot.model.TaxonomyTerm;
+
+/**
+ * @author Christian Illy
+ */
+public class Type {
+	String name;
+	TaxonomyTerm depotTerm;
+
+	HashSet<Mod> entries = new HashSet<Mod>();
+
+	/**
+	 * Create a new local type declaration
+	 * 
+	 * @param name
+	 *            Name of type
+	 * @param tt
+	 *            Optional TaxTerm link
+	 */
+	public Type(String name, TaxonomyTerm tt) {
+		this.name = name;
+		this.depotTerm = tt;
+	}
+
+	void addEntry(Mod m) {
+		entries.add(m);
+	}
+
+	/**
+	 * @return Name of type
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * @return Entries for type
+	 */
+	public HashSet<Mod> getEntries() {
+		return entries;
+	}
+
+	@Override
+	public String toString() {
+		return String.format("%s (%d)", name, entries.size());
+	}
+}
Index: /AE/installer2/src/net/oni2/aeinstaller/backend/network/DrupalJSONQuery.java
===================================================================
--- /AE/installer2/src/net/oni2/aeinstaller/backend/network/DrupalJSONQuery.java	(revision 599)
+++ /AE/installer2/src/net/oni2/aeinstaller/backend/network/DrupalJSONQuery.java	(revision 600)
@@ -59,5 +59,4 @@
 					+ ".json", data);
 		} catch (UnsupportedEncodingException e) {
-			// TODO Auto-generated catch block
 			e.printStackTrace();
 		}
@@ -170,11 +169,8 @@
 			return jA;
 		} catch (JSONException e) {
-			// TODO Auto-generated catch block
 			e.printStackTrace();
 		} catch (UnsupportedEncodingException e) {
-			// TODO Auto-generated catch block
 			e.printStackTrace();
 		} catch (IOException e) {
-			// TODO Auto-generated catch block
 			e.printStackTrace();
 		} finally {
@@ -185,5 +181,4 @@
 					input.close();
 				} catch (IOException e) {
-					// TODO Auto-generated catch block
 					e.printStackTrace();
 				}
Index: /AE/installer2/src/net/oni2/aeinstaller/backend/oni/InstallProgressListener.java
===================================================================
--- /AE/installer2/src/net/oni2/aeinstaller/backend/oni/InstallProgressListener.java	(revision 600)
+++ /AE/installer2/src/net/oni2/aeinstaller/backend/oni/InstallProgressListener.java	(revision 600)
@@ -0,0 +1,18 @@
+package net.oni2.aeinstaller.backend.oni;
+
+/**
+ * @author Christian Illy
+ */
+public interface InstallProgressListener {
+	/**
+	 * Called when installation process advances
+	 * 
+	 * @param done
+	 *            Steps done
+	 * @param total
+	 *            Steps in total
+	 * @param step
+	 *            Name of step
+	 */
+	public void installProgressUpdate(int done, int total, String step);
+}
Index: /AE/installer2/src/net/oni2/aeinstaller/backend/oni/Installer.java
===================================================================
--- /AE/installer2/src/net/oni2/aeinstaller/backend/oni/Installer.java	(revision 599)
+++ /AE/installer2/src/net/oni2/aeinstaller/backend/oni/Installer.java	(revision 600)
@@ -3,6 +3,10 @@
 import java.io.File;
 import java.io.FileFilter;
+import java.io.FileNotFoundException;
 import java.io.FilenameFilter;
 import java.io.IOException;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
@@ -35,5 +39,7 @@
 	}
 
-	public static void install(TreeSet<Mod> mods) {
+	public static void install(TreeSet<Mod> mods,
+			InstallProgressListener listener) {
+
 		Vector<File> folders = new Vector<File>();
 		folders.add(Paths.getVanillaOnisPath());
@@ -59,40 +65,85 @@
 		}
 
-		for (File f : Paths.getModsPath().listFiles()) {
-			File oni = new File(f, "oni");
-			if (oni.exists())
-				folders.add(oni);
-		}
-		combineBinaryFiles(folders);
+		// for (File f : Paths.getModsPath().listFiles()) {
+		// File oni = new File(f, "oni");
+		// if (oni.exists())
+		// folders.add(oni);
+		// }
+		combineBinaryFiles(folders, listener);
 
 		// TODO: bsl()
 	}
 
-	private static void combineBinaryFiles(List<File> srcFolders) {
+	private static void combineBinaryFiles(List<File> srcFoldersFiles,
+			InstallProgressListener listener) {
 		try {
+			HashMap<String, Vector<File>> levels = new HashMap<String, Vector<File>>();
+
+			for (File path : srcFoldersFiles) {
+				for (File levelF : path.listFiles()) {
+					String fn = levelF.getName().toLowerCase();
+					String levelN = null;
+					if (levelF.isDirectory()) {
+						levelN = fn;
+					} else if (fn.endsWith(".dat")) {
+						levelN = fn.substring(0, fn.lastIndexOf('.'));
+					}
+					if (levelN != null) {
+						if (!levels.containsKey(levelN))
+							levels.put(levelN, new Vector<File>());
+						levels.get(levelN).add(levelF);
+					}
+				}
+			}
+
+			int totalSteps = 0;
+			int stepsDone = 0;
+
+			for (@SuppressWarnings("unused")
+			String s : levels.keySet())
+				totalSteps++;
+
+			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+			File logFile = new File(Paths.getInstallerPath(),
+					"Installation.log");
+			PrintWriter log = null;
+			try {
+				log = new PrintWriter(logFile);
+			} catch (FileNotFoundException e) {
+				e.printStackTrace();
+			}
+
+			Date start = new Date();
+			log.println("Installation of mods started at " + sdf.format(start));
+
+			log.println("Cleaning directories");
+			listener.installProgressUpdate(stepsDone, totalSteps,
+					"Cleaning up directories");
+
 			createEmptyPath(Paths.getEditionGDF());
-			HashMap<String, Vector<File>> levels = new HashMap<String, Vector<File>>();
-
-			for (File path : srcFolders) {
-				for (File levelF : path.listFiles()) {
-					if (!levels.containsKey(levelF.getName().toLowerCase()))
-						levels.put(levelF.getName().toLowerCase(),
-								new Vector<File>());
-					levels.get(levelF.getName().toLowerCase()).add(levelF);
-				}
-			}
-
+
+			log.println("Importing levels");
 			for (String l : levels.keySet()) {
-				System.out.println("Level " + l);
+				log.println("\tLevel " + l);
 				for (File f : levels.get(l)) {
-					System.out.println("    " + f.getPath());
-
-				}
-
-				OniSplit.importLevel(levels.get(l),
+					log.println("\t\t\t" + f.getPath());
+				}
+
+				Vector<String> res = OniSplit.packLevel(levels.get(l),
 						new File(Paths.getEditionGDF(), l + ".dat"));
-
-				System.out.println();
-			}
+				if (res != null && res.size() > 0) {
+					for (String s : res)
+						log.println("\t\t" + s);
+				}
+
+				log.println();
+			}
+			
+			Date end = new Date();
+			log.println("Initialization ended at " + sdf.format(end));
+			log.println("Process took "
+					+ ((end.getTime() - start.getTime()) / 1000) + " seconds");
+			log.close();
 		} catch (IOException e) {
 			// TODO Auto-generated catch block
@@ -103,16 +154,47 @@
 	/**
 	 * Initializes the Edition core
+	 * 
+	 * @param listener
+	 *            Listener for status updates
 	 */
-	public static void initializeEdition() {
+	public static void initializeEdition(InstallProgressListener listener) {
 		File init = new File(Paths.getTempPath(), "init");
+
+		int totalSteps = 0;
+		int stepsDone = 0;
+
+		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+		for (@SuppressWarnings("unused")
+		File f : Paths.getVanillaGDF().listFiles(new FilenameFilter() {
+			@Override
+			public boolean accept(File dir, String name) {
+				return name.endsWith(".dat");
+			}
+		})) {
+			totalSteps++;
+		}
+		totalSteps = totalSteps * 2 + 2;
+
 		try {
+			File logFile = new File(Paths.getInstallerPath(),
+					"Initialization.log");
+			PrintWriter log = new PrintWriter(logFile);
+
+			Date start = new Date();
+			log.println("Initialization of Edition core started at "
+					+ sdf.format(start));
+			log.println("Cleaning directories");
+
+			listener.installProgressUpdate(stepsDone, totalSteps,
+					"Cleaning up directories");
 			createEmptyPath(Paths.getVanillaOnisPath());
 			createEmptyPath(init);
 			File level0Folder = new File(init, "level0_Final");
 			createEmptyPath(level0Folder);
-			File level0FolderVanilla = new File(Paths.getVanillaOnisPath(),
-					"level0_Final");
-			createEmptyPath(level0FolderVanilla);
-			createEmptyPath(new File(level0FolderVanilla, "characters"));
+
+			stepsDone++;
+
+			log.println("Exporting levels and moving files to level0");
 
 			for (File f : Paths.getVanillaGDF().listFiles(new FilenameFilter() {
@@ -127,29 +209,51 @@
 				int levelNumber = Integer.parseInt(fi.findInLine("[0-9]+"));
 
+				log.println("\t" + levelName + ":");
+				log.println("\t\tExporting");
+				listener.installProgressUpdate(stepsDone, totalSteps,
+						"Exporting vanilla level " + levelNumber);
+
 				// Edition/GameDataFolder/level*_Final/
 				File tempLevelFolder = new File(init, levelName);
 
 				// Export Vanilla-Level-Dat -> Temp/Level
-				OniSplit.export(tempLevelFolder, f);
-
+				Vector<String> res = OniSplit.export(tempLevelFolder, f);
+				if (res != null && res.size() > 0) {
+					for (String s : res)
+						log.println("\t\t\t" + s);
+				}
+
+				log.println("\t\tMoving files");
 				handleFileGlobalisation(tempLevelFolder, level0Folder,
-						level0FolderVanilla, levelNumber);
-			}
+						levelNumber);
+				stepsDone++;
+				log.println();
+			}
+
+			log.println("Reimporting levels");
 
 			for (File f : init.listFiles()) {
 				String levelName = f.getName();
 
-				// Edition/AEInstaller/vanilla/level*_Final/
-				File vanillaFolder = new File(Paths.getVanillaOnisPath(),
-						levelName);
-				vanillaFolder.mkdirs();
+				log.println("\t" + levelName);
+				listener.installProgressUpdate(stepsDone, totalSteps,
+						"Creating globalized " + levelName);
 
 				Vector<File> folders = new Vector<File>();
 				folders.add(f);
 
-				OniSplit.importLevel(folders, new File(vanillaFolder, levelName
-						+ ".oni"));
-			}
-
+				Vector<String> res = OniSplit.importLevel(folders, new File(
+						Paths.getVanillaOnisPath(), levelName + ".dat"));
+				if (res != null && res.size() > 0) {
+					for (String s : res)
+						log.println("\t\t" + s);
+				}
+
+				log.println();
+				stepsDone++;
+			}
+
+			listener.installProgressUpdate(stepsDone, totalSteps,
+					"Copying basic files");
 			// Copy Oni-configs
 			File persistVanilla = new File(Paths.getOniBasePath(),
@@ -167,4 +271,9 @@
 
 			// TODO: FileUtils.deleteDirectory(init);
+			Date end = new Date();
+			log.println("Initialization ended at " + sdf.format(end));
+			log.println("Process took "
+					+ ((end.getTime() - start.getTime()) / 1000) + " seconds");
+			log.close();
 		} catch (IOException e) {
 			e.printStackTrace();
@@ -185,5 +294,5 @@
 
 	private static void handleFileGlobalisation(File tempFolder,
-			File level0Folder, File level0FolderVanilla, int levelNumber) {
+			File level0Folder, int levelNumber) {
 		// Move AKEV and related files to subfolder so they're not globalized:
 		if (levelNumber != 0) {
Index: /AE/installer2/src/net/oni2/aeinstaller/backend/oni/OniSplit.java
===================================================================
--- /AE/installer2/src/net/oni2/aeinstaller/backend/oni/OniSplit.java	(revision 599)
+++ /AE/installer2/src/net/oni2/aeinstaller/backend/oni/OniSplit.java	(revision 600)
@@ -8,9 +8,9 @@
 
 import net.oni2.aeinstaller.backend.Paths;
+import net.oni2.aeinstaller.backend.QuickAppExecution;
 import net.oni2.aeinstaller.backend.Settings;
 import net.oni2.aeinstaller.backend.Settings.Architecture;
 import net.oni2.aeinstaller.backend.Settings.Platform;
 import net.oni2.aeinstaller.backend.WinRegistry;
-import net.oni2.aeinstaller.backend.app_launcher.QuickAppExecution;
 
 /**
@@ -83,6 +83,7 @@
 	 * @param input
 	 *            Dat file
-	 */
-	public static void export(File targetFolder, File input) {
+	 * @return OniSplit output
+	 */
+	public static Vector<String> export(File targetFolder, File input) {
 		if (!targetFolder.exists())
 			targetFolder.mkdir();
@@ -92,16 +93,12 @@
 		cmdLine.add(targetFolder.getPath());
 		cmdLine.add(input.getPath());
-		// System.out.println(cmdLine.toString());
-		Vector<String> res = null;
-		try {
-			res = QuickAppExecution.execute(cmdLine);
-		} catch (IOException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-		}
-		if (res != null) {
-			// check for errors
-			System.out.println(res.toString());
-		}
+		Vector<String> res = null;
+		try {
+			res = QuickAppExecution.execute(cmdLine);
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		return res;
 	}
 
@@ -113,6 +110,7 @@
 	 * @param targetFile
 	 *            Target .dat-file
-	 */
-	public static void importLevel(Vector<File> sourceFolders, File targetFile) {
+	 * @return OniSplit output
+	 */
+	public static Vector<String> importLevel(Vector<File> sourceFolders, File targetFile) {
 		Vector<String> cmdLine = getProgramInvocation();
 		cmdLine.add(getImportParam());
@@ -120,16 +118,42 @@
 			cmdLine.add(f.getPath());
 		cmdLine.add(targetFile.getPath());
-		// System.out.println(cmdLine.toString());
-		Vector<String> res = null;
-		try {
-			res = QuickAppExecution.execute(cmdLine);
-		} catch (IOException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-		}
-		if (res != null) {
-			// check for errors
-			System.out.println(res.toString());
-		}
+		Vector<String> res = null;
+		try {
+			res = QuickAppExecution.execute(cmdLine);
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		return res;
+	}
+
+	/**
+	 * Pack a level to a .dat-file. More powerful variant which allows
+	 * specifying single .oni/.dat files
+	 * 
+	 * @param sourceFoldersFiles
+	 *            Folders (for recursive .oni import) or files (.dat and single
+	 *            .oni) to import
+	 * @param targetFile
+	 *            Target .dat-file
+	 * @return OniSplit output
+	 */
+	public static Vector<String> packLevel(Vector<File> sourceFoldersFiles,
+			File targetFile) {
+		Vector<String> cmdLine = getProgramInvocation();
+		cmdLine.add(getPackParam());
+		cmdLine.add(getPackTypeParam());
+		cmdLine.add("-out");
+		cmdLine.add(targetFile.getPath());
+		for (File f : sourceFoldersFiles)
+			cmdLine.add(f.getPath());
+		Vector<String> res = null;
+		try {
+			res = QuickAppExecution.execute(cmdLine);
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		return res;
 	}
 
@@ -144,6 +168,7 @@
 	 * @param moveParameter
 	 *            e.g. overwrite, delete
-	 */
-	public static void move(File targetFolder, String input,
+	 * @return OniSplit output
+	 */
+	public static Vector<String> move(File targetFolder, String input,
 			String moveParameter) {
 		if (!targetFolder.exists())
@@ -162,8 +187,5 @@
 			e.printStackTrace();
 		}
-		if (res != null && res.size() > 0) {
-			// TODO: errors
-			System.out.println(res.toString());
-		}
+		return res;
 	}
 
@@ -175,9 +197,21 @@
 	}
 
+	private static String getPackParam() {
+		return "pack";
+	}
+
+	private static String getPackTypeParam() {
+		if (Settings.getPlatform() == Platform.MACOS)
+			return "-type:macintel";
+		else
+			return "-type:pc";
+	}
+
 	private static Vector<String> getProgramInvocation() {
 		Vector<String> res = new Vector<String>();
 		if (Settings.getPlatform() != Platform.WIN)
 			res.add("mono");
-		res.add(new File(Paths.getInstallerPath(), "Onisplit.exe").getPath());
+		res.add(new File(new File(Paths.getEditionBasePath(), "Tools"),
+				"Onisplit.exe").getPath());
 		return res;
 	}
Index: /AE/installer2/src/net/oni2/aeinstaller/gui/HTMLLinkLabel.java
===================================================================
--- /AE/installer2/src/net/oni2/aeinstaller/gui/HTMLLinkLabel.java	(revision 599)
+++ /AE/installer2/src/net/oni2/aeinstaller/gui/HTMLLinkLabel.java	(revision 600)
@@ -55,8 +55,6 @@
 						Desktop.getDesktop().browse(e.getURL().toURI());
 					} catch (IOException e1) {
-						// TODO Auto-generated catch block
 						e1.printStackTrace();
 					} catch (URISyntaxException e1) {
-						// TODO Auto-generated catch block
 						e1.printStackTrace();
 					}
Index: /AE/installer2/src/net/oni2/aeinstaller/gui/MainWin.java
===================================================================
--- /AE/installer2/src/net/oni2/aeinstaller/gui/MainWin.java	(revision 599)
+++ /AE/installer2/src/net/oni2/aeinstaller/gui/MainWin.java	(revision 600)
@@ -1,11 +1,11 @@
 package net.oni2.aeinstaller.gui;
 
-import java.awt.Frame;
 import java.util.ArrayList;
-import java.util.Comparator;
 import java.util.List;
 import java.util.ResourceBundle;
 import java.util.TreeMap;
-
+import java.util.TreeSet;
+
+import javax.swing.JButton;
 import javax.swing.JComboBox;
 import javax.swing.JComponent;
@@ -26,11 +26,14 @@
 import net.oni2.aeinstaller.backend.Settings;
 import net.oni2.aeinstaller.backend.Settings.Platform;
+import net.oni2.aeinstaller.backend.SizeFormatter;
 import net.oni2.aeinstaller.backend.depot.DepotCacheUpdateProgressListener;
-import net.oni2.aeinstaller.backend.depot.DepotConfig;
 import net.oni2.aeinstaller.backend.depot.DepotManager;
-import net.oni2.aeinstaller.backend.depot.model.NodeMod;
-import net.oni2.aeinstaller.backend.depot.model.TaxonomyTerm;
-import net.oni2.aeinstaller.backend.depot.model.TaxonomyVocabulary;
+import net.oni2.aeinstaller.backend.mods.Mod;
+import net.oni2.aeinstaller.backend.mods.ModManager;
+import net.oni2.aeinstaller.backend.mods.Type;
+import net.oni2.aeinstaller.backend.oni.InstallProgressListener;
+import net.oni2.aeinstaller.backend.oni.Installer;
 import net.oni2.aeinstaller.gui.about.AboutDialog;
+import net.oni2.aeinstaller.gui.modtable.DownloadSizeListener;
 import net.oni2.aeinstaller.gui.modtable.ModTableFilter;
 import net.oni2.aeinstaller.gui.modtable.ModTableModel;
@@ -47,5 +50,6 @@
  * @author Christian Illy
  */
-public class MainWin extends JFrame implements ApplicationListener {
+public class MainWin extends JFrame implements ApplicationListener,
+		DownloadSizeListener {
 	private static final long serialVersionUID = -4027395051382659650L;
 
@@ -63,10 +67,12 @@
 	private ModTableModel model;
 	private TableRowSorter<ModTableModel> sorter;
+	private JLabel lblDownloadSizeVal;
 
 	private JLabel lblSubmitterVal;
 	private JLabel lblCreatorVal;
 	private JLabel lblFilesVal;
-	private JLabel lblIdVal;
 	private HTMLLinkLabel lblDescriptionVal;
+
+	private JButton btnInstall;
 
 	/**
@@ -79,10 +85,10 @@
 
 		contents.setDividerLocation(400);
-		initTable();
-		initModTypeBox();
 
 		if (Settings.getPlatform() == Platform.MACOS) {
 			mainMenu.setVisible(false);
 		}
+
+		getRootPane().setDefaultButton(btnInstall);
 	}
 
@@ -90,17 +96,9 @@
 		cmbModTypes.removeAllItems();
 
-		TaxonomyVocabulary tv = DepotManager.getInstance().getVocabulary(
-				DepotConfig.getVocabularyName_ModType());
-		if (tv == null)
-			return;
-
-		int vid = tv.getVid();
-		TreeMap<String, TaxonomyTerm> terms = new TreeMap<String, TaxonomyTerm>();
-		terms.put(" ", new TaxonomyTerm(-1, vid, "-All-"));
-		for (TaxonomyTerm t : DepotManager.getInstance()
-				.getTaxonomyTermsByVocabulary(vid)) {
-			terms.put(t.getName(), t);
-		}
-		for (TaxonomyTerm t : terms.values()) {
+		TreeMap<String, Type> types = new TreeMap<String, Type>();
+		for (Type t : ModManager.getInstance().getTypesWithContent()) {
+			types.put(t.getName(), t);
+		}
+		for (Type t : types.values()) {
 			cmbModTypes.addItem(t);
 		}
@@ -121,6 +119,5 @@
 							int modelRow = tblMods
 									.convertRowIndexToModel(viewRow);
-							NodeMod mod = (NodeMod) model.getValueAt(modelRow,
-									-1);
+							Mod mod = (Mod) model.getValueAt(modelRow, -1);
 							modSelection(mod);
 						}
@@ -133,4 +130,5 @@
 
 		model = new ModTableModel();
+		model.addDownloadSizeListener(this);
 
 		tblMods.setModel(model);
@@ -139,16 +137,7 @@
 		tblMods.setRowSorter(sorter);
 
-		sorter.setRowFilter(new ModTableFilter(-1));
+		sorter.setRowFilter(new ModTableFilter(null));
 
 		sorter.setSortable(2, false);
-		sorter.setComparator(1, new Comparator<String>() {
-
-			@Override
-			public int compare(String o1, String o2) {
-				int i1 = Integer.parseInt(o1);
-				int i2 = Integer.parseInt(o2);
-				return i1 - i2;
-			}
-		});
 
 		List<RowSorter.SortKey> sortKeys = new ArrayList<RowSorter.SortKey>();
@@ -171,13 +160,4 @@
 				JOptionPane.QUESTION_MESSAGE);
 		return res == JOptionPane.YES_OPTION;
-	}
-
-	private boolean closeFrames() {
-		System.gc();
-		for (Frame f : Frame.getFrames()) {
-			if (f != this)
-				f.dispose();
-		}
-		return true;
 	}
 
@@ -206,6 +186,8 @@
 						}
 					});
-			model.reloadData();
+			ModManager.getInstance().init();
+			initTable();
 			initModTypeBox();
+
 			tblMods.setVisible(true);
 			DepotManager.getInstance().printStats();
@@ -244,5 +226,5 @@
 	@SuppressWarnings("unused")
 	private void loadConfig() {
-		// TODO Auto-generated method stub
+		// TODO method stub
 		JOptionPane.showMessageDialog(this, "loadConfig", "todo",
 				JOptionPane.INFORMATION_MESSAGE);
@@ -251,13 +233,25 @@
 	@SuppressWarnings("unused")
 	private void saveConfig() {
-		// TODO Auto-generated method stub
+		// TODO method stub
 		JOptionPane.showMessageDialog(this, "saveConfig", "todo",
 				JOptionPane.INFORMATION_MESSAGE);
 	}
 
-	@SuppressWarnings("unused")
-	private void reglobalize() {
-		// TODO Auto-generated method stub
-		JOptionPane.showMessageDialog(this, "reglobalize", "todo",
+	@DoInBackground(progressMessage = "initializingEdition.title", cancelable = false, indeterminateProgress = false)
+	private void reglobalize(final BackgroundEvent evt) {
+		Installer.initializeEdition(new InstallProgressListener() {
+			@Override
+			public void installProgressUpdate(int done, int total, String step) {
+				evt.setProgressEnd(total);
+				evt.setProgressValue(done);
+				evt.setProgressMessage(step);
+			}
+		});
+	}
+
+	@SuppressWarnings("unused")
+	private void tools() {
+		// TODO method stub
+		JOptionPane.showMessageDialog(this, "tools", "todo",
 				JOptionPane.INFORMATION_MESSAGE);
 	}
@@ -265,22 +259,48 @@
 	@SuppressWarnings("unused")
 	private void revertSelection() {
-		// TODO Auto-generated method stub
+		// TODO method stub
 		JOptionPane.showMessageDialog(this, "revertSelection", "todo",
 				JOptionPane.INFORMATION_MESSAGE);
 	}
 
-	private void modSelection(NodeMod n) {
+	@DoInBackground(progressMessage = "installing.title", cancelable = false, indeterminateProgress = false)
+	private void install(final BackgroundEvent evt) {
+		TreeSet<Mod> mods = new TreeSet<Mod>();
+		mods.addAll(ModManager.getInstance().getDefaultMods());
+		mods.addAll(model.getSelectedMods());
+
+		System.out.println("Install mods:");
+		for (Mod m : mods) {
+			System.out
+					.println("  " + m.getPackageNumber() + ": " + m.getName());
+		}
+
+		Installer.install(mods, new InstallProgressListener() {
+			@Override
+			public void installProgressUpdate(int done, int total, String step) {
+				evt.setProgressEnd(total);
+				evt.setProgressValue(done);
+				evt.setProgressMessage(step);
+			}
+		});
+
+		// TODO method stub
+		JOptionPane.showMessageDialog(this, "install", "todo",
+				JOptionPane.INFORMATION_MESSAGE);
+	}
+
+	private void modSelection(Mod m) {
 		lblSubmitterVal.setText("");
 		lblCreatorVal.setText("");
-		lblIdVal.setText("");
 		lblFilesVal.setText("");
 		lblDescriptionVal.setText("");
-		if (n != null) {
-			lblSubmitterVal.setText(n.getName());
-			lblCreatorVal.setText(n.getFields().get("creator"));
-			lblIdVal.setText(Integer.toString(n.getNid()));
-			lblFilesVal.setText(Integer.toString(n.getUploads().size()));
-			if (n.getBody() != null)
-				lblDescriptionVal.setText(n.getBody().getSafe_value());
+		if (m != null) {
+			lblSubmitterVal.setText(m.getName());
+			lblCreatorVal.setText(m.getCreator());
+			if (m.getNode() != null) {
+				lblFilesVal.setText(Integer.toString(m.getNode().getUploads()
+						.size()));
+			}
+			lblDescriptionVal.setText(m.getDescription());
 		}
 		// TODO
@@ -289,9 +309,37 @@
 	@SuppressWarnings("unused")
 	private void modTypeSelection() {
-		TaxonomyTerm t = (TaxonomyTerm) cmbModTypes.getSelectedItem();
+		Type t = (Type) cmbModTypes.getSelectedItem();
 		if (t != null)
-			sorter.setRowFilter(new ModTableFilter(t.getTid()));
+			sorter.setRowFilter(new ModTableFilter(t));
 		else
-			sorter.setRowFilter(new ModTableFilter(-1));
+			sorter.setRowFilter(new ModTableFilter(null));
+	}
+
+	@Override
+	public void downloadSizeChanged(int newSize) {
+		lblDownloadSizeVal.setText(SizeFormatter.format(newSize, 2));
+	}
+
+	@DoInBackground(progressMessage = "initializingEdition.title", cancelable = false, indeterminateProgress = false)
+	private void initialize(final BackgroundEvent evt) {
+		if (!Installer.isEditionInitialized()) {
+			int res = JOptionPane.showConfirmDialog(this,
+					bundle.getString("askInitialize.text"),
+					bundle.getString("askInitialize.title"),
+					JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
+			if (res == JOptionPane.NO_OPTION) {
+				exit();
+			} else {
+				Installer.initializeEdition(new InstallProgressListener() {
+					@Override
+					public void installProgressUpdate(int done, int total,
+							String step) {
+						evt.setProgressEnd(total);
+						evt.setProgressValue(done);
+						evt.setProgressMessage(step);
+					}
+				});
+			}
+		}
 	}
 
@@ -323,5 +371,4 @@
 		if (askClose()) {
 			event.setHandled(true);
-			closeFrames();
 			saveLocalData();
 			exit();
@@ -334,3 +381,4 @@
 	public void handleReOpenApplication(ApplicationEvent event) {
 	}
+
 }
Index: /AE/installer2/src/net/oni2/aeinstaller/gui/MainWin.properties
===================================================================
--- /AE/installer2/src/net/oni2/aeinstaller/gui/MainWin.properties	(revision 599)
+++ /AE/installer2/src/net/oni2/aeinstaller/gui/MainWin.properties	(revision 600)
@@ -18,12 +18,16 @@
 menu.reglobalize=&Rebuild Core Data
 menu.reglobalizeTooltip=Rebuild Core Data
+menu.tools=&Manage Tools
+menu.toolsTooltip=Install/Remove Tools
 
 btnRevertSelection.text=Revert selection
 btnRevertSelection.tooltip=Select mods which are currently installed
+btnInstall.text=&Install
+btnInstall.tooltip=Install selected mods
 lblModTypes.text=Mod type: 
+lblDownloadSize.text=Size of files to download: 
 
 lblSubmitter.text=Submitter:
 lblCreator.text=Creator:
-lblId.text=NodeID:
 lblFiles.text=Number of files:
 lblDescription.text=Description:
@@ -36,2 +40,8 @@
 askClose.title=Confirm close request
 askClose.text=Are you sure you want to close the program?
+
+askInitialize.title=Initialize Edition
+askInitialize.text=The Edition is not yet initialized.\nIf you do not initialize now the installer will exit.\nInitialize Edition core now?
+
+initializingEdition.title=Initializing Edition core
+installing.title=Installing mods
Index: /AE/installer2/src/net/oni2/aeinstaller/gui/MainWin.yml
===================================================================
--- /AE/installer2/src/net/oni2/aeinstaller/gui/MainWin.yml	(revision 599)
+++ /AE/installer2/src/net/oni2/aeinstaller/gui/MainWin.yml	(revision 600)
@@ -6,9 +6,9 @@
   locationRelativeTo: null
   defaultCloseOperation: doNothingOnClose
-  onWindowOpened: [execDepotUpdate,checkUpdates,focus]
-  onWindowClosing: [askClose,closeFrames,saveLocalData,exit]
+  onWindowOpened: [execDepotUpdate,checkUpdates,initialize,focus]
+  onWindowClosing: [askClose,saveLocalData,exit]
   iconImage: img.ae
   content:
-    - Action(name=exitAction, text=menu.exit, toolTipText=menu.exitTooltip, icon=img.exit, onAction=[askClose,closeFrames,saveLocalData,exit])
+    - Action(name=exitAction, text=menu.exit, toolTipText=menu.exitTooltip, icon=img.exit, onAction=[askClose,saveLocalData,exit])
     - Action(name=settings, text=menu.settings, toolTipText=menu.settingsTooltip, icon=img.settings, onAction=[showSettings])
     - Action(name=about, text=menu.about, toolTipText=menu.aboutTooltip, icon=img.about, onAction=[showAbout])
@@ -16,4 +16,5 @@
     - Action(name=saveConfig, text=menu.saveConfig, toolTipText=menu.saveConfigTooltip, icon=img.saveFile, onAction=[saveConfig])
     - Action(name=reglobalize, text=menu.reglobalize, toolTipText=menu.reglobalizeTooltip, icon=img.refresh, onAction=[reglobalize])
+    - Action(name=tools, text=menu.tools, toolTipText=menu.toolsTooltip, icon=img.tools, onAction=[tools])
     - JMenuBar:
         - JMenu(name=mainMenu, text=menu.main):
@@ -26,5 +27,7 @@
             - JSeparator()
             - JMenuItem(action=reglobalize)
-    - JToolBar(name=tools, floatable=false, orientation=0):
+            - JSeparator()
+            - JMenuItem(action=tools)
+    - JToolBar(name=toolbar, floatable=false, orientation=0):
         - JButton(action=exitAction, hideActionText=true)
         - JToolBarSeparator()
@@ -33,14 +36,18 @@
     - JSplitPane(name=contents, orientation=horizontalSplit, continuousLayout=true):
         - JPanel(name=panMods):
-            - JButton(name=btnRevertSelection, icon=img.undo16, text=btnRevertSelection.text, toolTipText=btnRevertSelection.tooltip, onAction=[revertSelection])
             - JLabel(name=lblModTypes, text=lblModTypes.text)
             - JComboBox(name=cmbModTypes, onAction=modTypeSelection)
             - JScrollPane(name=scrollMods, vScrollBar=always, hScrollBar=never):
                 JTable(name=tblMods, visible=false)
+            - JButton(name=btnRevertSelection, icon=img.undo16, text=btnRevertSelection.text, toolTipText=btnRevertSelection.tooltip, onAction=[revertSelection])
+            - JButton(name=btnInstall, icon=img.install, text=btnInstall.text, toolTipText=btnInstall.tooltip, onAction=[install])
+            - JLabel(name=lblDownloadSize, text=lblDownloadSize.text)
+            - JLabel(name=lblDownloadSizeVal)
             - MigLayout: |
                  [grow]
-                 btnRevertSelection                 [min]
                  lblModTypes<,cmbModTypes           [min]
                  scrollMods                         [grow]
+                 >btnRevertSelection,btnInstall     [min]
+                 lblDownloadSize,lblDownloadSizeVal [min]
         - JPanel(name=panInfo):
             - JLabel(name=lblSubmitter, text=lblSubmitter.text)
@@ -48,6 +55,4 @@
             - JLabel(name=lblCreator, text=lblCreator.text)
             - JLabel(name=lblCreatorVal)
-            - JLabel(name=lblId, text=lblId.text)
-            - JLabel(name=lblIdVal)
             - JLabel(name=lblFiles, text=lblFiles.text)
             - JLabel(name=lblFilesVal)
@@ -59,5 +64,4 @@
                  >lblSubmitter     lblSubmitterVal    [min]
                  >lblCreator       lblCreatorVal      [min]
-                 >lblId            lblIdVal           [min]
                  >lblFiles         lblFilesVal        [min]
                  >^lblDescription  scrollDescription  [grow]
Index: /AE/installer2/src/net/oni2/aeinstaller/gui/modtable/DownloadSizeListener.java
===================================================================
--- /AE/installer2/src/net/oni2/aeinstaller/gui/modtable/DownloadSizeListener.java	(revision 600)
+++ /AE/installer2/src/net/oni2/aeinstaller/gui/modtable/DownloadSizeListener.java	(revision 600)
@@ -0,0 +1,12 @@
+package net.oni2.aeinstaller.gui.modtable;
+
+/**
+ * @author Christian Illy
+ */
+public interface DownloadSizeListener {
+	/**
+	 * @param newSize
+	 *            New size of files to download
+	 */
+	public void downloadSizeChanged(int newSize);
+}
Index: /AE/installer2/src/net/oni2/aeinstaller/gui/modtable/ModTableFilter.java
===================================================================
--- /AE/installer2/src/net/oni2/aeinstaller/gui/modtable/ModTableFilter.java	(revision 599)
+++ /AE/installer2/src/net/oni2/aeinstaller/gui/modtable/ModTableFilter.java	(revision 600)
@@ -1,11 +1,8 @@
 package net.oni2.aeinstaller.gui.modtable;
-
-import java.util.HashSet;
 
 import javax.swing.RowFilter;
 
-import net.oni2.aeinstaller.backend.Settings;
-import net.oni2.aeinstaller.backend.depot.DepotManager;
-import net.oni2.aeinstaller.backend.depot.model.NodeMod;
+import net.oni2.aeinstaller.backend.mods.Mod;
+import net.oni2.aeinstaller.backend.mods.Type;
 
 /**
@@ -13,11 +10,11 @@
  */
 public class ModTableFilter extends RowFilter<ModTableModel, Integer> {
-	int type = -1;
+	Type type = null;
 
 	/**
 	 * @param type
-	 *            Type of mods to show (-1 for all)
+	 *            Type of mods to show (null for all)
 	 */
-	public ModTableFilter(int type) {
+	public ModTableFilter(Type type) {
 		super();
 		this.type = type;
@@ -26,18 +23,17 @@
 	@Override
 	public boolean include(
-			javax.swing.RowFilter.Entry<? extends ModTableModel, ? extends Integer> entry) {
-		NodeMod mod = (NodeMod) entry.getModel().getValueAt(
-				entry.getIdentifier(), -1);
+			RowFilter.Entry<? extends ModTableModel, ? extends Integer> entry) {
+		Mod mod = (Mod) entry.getModel().getValueAt(entry.getIdentifier(), -1);
 
-		if (!DepotManager.getInstance().isModValidOnPlatform(mod,
-				Settings.getPlatform()))
+		if (mod.isDefaultMod())
 			return false;
 
-		if (type < 0)
+		if (!mod.validOnPlatform())
+			return false;
+
+		if (type == null)
 			return true;
 
-		HashSet<Integer> types = new HashSet<Integer>();
-		types.add(type);
-		return DepotManager.getInstance().isModOfType(mod, types, false);
+		return mod.getTypes().contains(type);
 	}
 }
Index: /AE/installer2/src/net/oni2/aeinstaller/gui/modtable/ModTableModel.java
===================================================================
--- /AE/installer2/src/net/oni2/aeinstaller/gui/modtable/ModTableModel.java	(revision 599)
+++ /AE/installer2/src/net/oni2/aeinstaller/gui/modtable/ModTableModel.java	(revision 600)
@@ -1,5 +1,7 @@
 package net.oni2.aeinstaller.gui.modtable;
 
+import java.util.HashSet;
 import java.util.ResourceBundle;
+import java.util.TreeSet;
 import java.util.Vector;
 
@@ -7,7 +9,7 @@
 import javax.swing.table.TableColumn;
 
-import net.oni2.aeinstaller.backend.depot.DepotConfig;
-import net.oni2.aeinstaller.backend.depot.DepotManager;
-import net.oni2.aeinstaller.backend.depot.model.NodeMod;
+import net.oni2.aeinstaller.backend.mods.Mod;
+import net.oni2.aeinstaller.backend.mods.ModManager;
+import net.oni2.aeinstaller.backend.mods.Type;
 
 /**
@@ -21,8 +23,8 @@
 			.getName());
 
-	private Vector<NodeMod> items;
-	private Vector<Boolean> install;
-	private int vocabModTypeID = -1;
-	private int vocabPlatformID = -1;
+	private Vector<Mod> items = new Vector<Mod>();
+	private Vector<Boolean> install = new Vector<Boolean>();
+
+	private HashSet<DownloadSizeListener> listeners = new HashSet<DownloadSizeListener>();
 
 	/**
@@ -35,40 +37,22 @@
 	@Override
 	public Object getValueAt(int row, int col) {
-		NodeMod node = items.get(row);
+		Mod mod = items.get(row);
 		switch (col) {
 			case -1:
-				return node;
-			case 0:
-				return node.getTitle();
-			case 1:
-				return node.getFields().get("package_number");
+				return mod;
+			case 0:
+				return mod.getName();
+			case 1:
+				return mod.getPackageNumber();
 			case 2:
 				String type = "";
-				if (vocabModTypeID < 0) {
-					vocabModTypeID = DepotManager
-							.getInstance()
-							.getVocabulary(
-									DepotConfig.getVocabularyName_ModType())
-							.getVid();
-				}
-				for (int tid : node.getTaxonomyTerms().get(vocabModTypeID)) {
+				for (Type t : mod.getTypes()) {
 					if (type.length() > 0)
 						type += ", ";
-					type += DepotManager.getInstance().getTaxonomyTerm(tid)
-							.getName();
+					type += t.getName();
 				}
 				return type;
 			case 3:
-				if (vocabPlatformID < 0) {
-					vocabPlatformID = DepotManager
-							.getInstance()
-							.getVocabulary(
-									DepotConfig.getVocabularyName_Platform())
-							.getVid();
-				}
-				int tid = node.getTaxonomyTerms().get(vocabPlatformID)
-						.iterator().next();
-				return DepotManager.getInstance().getTaxonomyTerm(tid)
-						.getName();
+				return mod.getPlatform().toString();
 			case 4:
 				return install.get(row);
@@ -163,6 +147,7 @@
 	 */
 	public void reloadData() {
-		items = DepotManager.getInstance().getModPackageNodes();
-		install = new Vector<Boolean>();
+		items.clear();
+		items.addAll(ModManager.getInstance().getMods());
+		install.clear();
 		// TODO check installed
 		for (int i = 0; i < items.size(); i++) {
@@ -176,6 +161,18 @@
 	 * @return Items
 	 */
-	public Vector<NodeMod> getItems() {
+	public Vector<Mod> getItems() {
 		return items;
+	}
+
+	/**
+	 * @return Mods selected for installation
+	 */
+	public TreeSet<Mod> getSelectedMods() {
+		TreeSet<Mod> res = new TreeSet<Mod>();
+		for (int i = 0; i < items.size(); i++) {
+			if (install.get(i))
+				res.add(items.get(i));
+		}
+		return res;
 	}
 
@@ -190,5 +187,32 @@
 		if (columnIndex == 4) {
 			install.set(rowIndex, (Boolean) aValue);
-		}
+
+			int size = 0;
+			for (int i = 0; i < items.size(); i++) {
+				if (install.get(i)) {
+					Mod m = items.get(i);
+					if (!m.isLocalAvailable() || m.isNewerAvailable())
+						size += m.getZipSize();
+				}
+			}
+			for (DownloadSizeListener dsl : listeners)
+				dsl.downloadSizeChanged(size);
+		}
+	}
+
+	/**
+	 * @param lis
+	 *            Listener to receive download size changed events
+	 */
+	public void addDownloadSizeListener(DownloadSizeListener lis) {
+		listeners.add(lis);
+	}
+
+	/**
+	 * @param lis
+	 *            Listener to no longer receive download size changed events
+	 */
+	public void removeDownloadSizeListener(DownloadSizeListener lis) {
+		listeners.remove(lis);
 	}
 
