Index: AE/Installer/trunk/source/installer.cpp
===================================================================
--- AE/Installer/trunk/source/installer.cpp	(revision 502)
+++ AE/Installer/trunk/source/installer.cpp	(revision 504)
@@ -18,4 +18,5 @@
 #include "boost/date_time/date_parsing.hpp"
 #include "boost/date_time/posix_time/posix_time.hpp"
+#include <boost/algorithm/string.hpp>
 #include "installer.h"
 #include "aeinstallerapp.h"
@@ -270,4 +271,5 @@
 		copy((path)"../GameDataFolder/level0_Characters", (path)("VanillaDats/level0_Final"));
 		GDFPaths.push_back( Characters );
+		//concactates level0....
 		for(int i = 0; i < GDFPaths.size(); i++) 
 		{
@@ -284,19 +286,21 @@
 			}
 		}
+		//?: syntax is fun.
+		//condition ? value_if_true : value_if_false 
+		(is_empty(Characters)	? remove( Characters )	: 1);
+		(is_empty(Particles)	? remove( Particles )	: 1);
+		(is_empty(Textures)		? remove( Textures )	: 1);
+		(is_empty(Sounds)		? remove( Sounds )		: 1);
+		(is_empty(TRAC)			? remove( TRAC )		: 1);
+		(is_empty(TRAM)			? remove( TRAM )		: 1);
+		(is_empty(Animations)	? remove( Animations )	: 1);
 
 		create_directory((path)"../GameDataFolder/IGMD");
 		copy((path)"packages/VanillaBSL/IGMD", (path)"../GameDataFolder");
 		setProgressBar( 1000 );
-		
-		if(exists("../../persist.dat"))
-			if(!exists("../persist.dat")) 
-			
-			//TODO: Concatenate level0 Dirs.
-			
-				copy("../../persist.dat","..");
-		if(exists("../../key_config.txt"))
-			if(!exists("../key_config.txt"))
-				copy("../../key_config.txt",".."); 
-		
+
+		if(exists("../../persist.dat") && !exists("../persist.dat")) copy("../../persist.dat","..");
+		if(exists("../../key_config.txt")&& !exists("../key_config.txt")) copy("../../key_config.txt",".."); 
+
 #ifndef WIN32
 		/* On Mac only, set the current GDF to the AE GDF by writing to Oni's global preferences file (thankfully a standard OS X ".plist" XML file).
@@ -304,8 +308,13 @@
 		 run Oni before :-p */
 		string fullAEpath = escapePath(system_complete(".").parent_path().parent_path().string()); // get full path for Edition/ (Oni wants the folder that *contains* the GDF)
-		char prefsCommand[300] = "[ -f ~/Library/Preferences/com.godgames.oni.plist ] && defaults write com.godgames.oni RetailInstallationPath -string '";
+		//bad Iritscen, bad! fixed buffers can cause crashes.
+		/*char prefsCommand[300] = "[ -f ~/Library/Preferences/com.godgames.oni.plist ] && defaults write com.godgames.oni RetailInstallationPath -string '";
 		strcat(prefsCommand, fullAEpath.c_str());
 		strcat(prefsCommand, "'"); // path string is enclosed in single quotes to avoid the need to escape UNIX-unfriendly characters
-		system(prefsCommand);
+		*/
+		string prefsCommand = "[ -f ~/Library/Preferences/com.godgames.oni.plist ] && defaults write com.godgames.oni RetailInstallationPath -string '"
+			+ fullAEpath + "'";
+		system(prefsCommand.c_str());
+
 #endif
 		
@@ -419,5 +428,5 @@
 				package.modStringName = *iter;
 				iter++;
-				package.modStringVersion = atoi((*iter).c_str());
+				package.modStringVersion = atof((*iter).c_str());
 			}
 			else if (!Platform.compare(*iter))
@@ -828,124 +837,177 @@
 			return UPDATE_LOG_READ_ERR;
 	}
-	
+
 	// Is there an update folder, and is it a monthly release or a patch?
-	if (!exists("../updates/Edition"))
-	{
+	bool firstParty = 0;
+	if (exists("../updates/Edition"))
+	{
+		firstParty = 1;
+	}
+	else {
 		strEUFN = "Edition-patch";
-		if (!exists("../updates/Edition-patch"))
-			return UPDATE_NO_UPD_AVAIL;
-	}
-	
-	// Unlike the current AE's version info, we *need* to find the update's version info or we won't continue
-	string updateCfgPath = ("../updates/" + strEUFN + "/install/packages/Globalize/Install_Info.cfg");
-	updateAECfg.open(updateCfgPath.c_str());
-	if (!updateAECfg.fail())
-	{
-		if (!ReadInstallInfoCfg(&updateAECfg, updateAE))
-			return UPDATE_LOG_READ_ERR;
-		
-		updateAECfg.close();
-		updateAECfg.clear();
-	}
-	else
-		return UPDATE_LOG_READ_ERR;
-
-	// Now we check for an Installer update in progress
-	if (exists("Update.log"))
-	{
-		updateLog.open("Update.log");
-		if (!updateLog.fail())
-		{
-			vector<string> lines; 
-			string line;
-			int num_lines = 0;
-			bool readingInstallerVersion = false, doneReadingFile = false;
-			
-			while (!updateLog.eof() && !doneReadingFile)
-			{
-				getline(updateLog, line);
-				lines.push_back(line);
-				num_lines++;
-				vector<string> tokens;
-				vector<string>::iterator iter;
-				tokenize(line, tokens);
-				iter = tokens.begin();
-				if (!readingInstallerVersion && tokens.capacity() >= 4)
-				{
-					if (!strInstaller.compare(*iter))
-					{
-						if (!strBeing.compare(*++iter))
-							readingInstallerVersion = true;
-						else if (!strWas.compare(*iter))
-							*installerJustUpdated = true; // our third indirect return value after currentAE and updateAE
-					}
-				}
-				else if (readingInstallerVersion && tokens.capacity() >= 3)
-				{
-					readingInstallerVersion = false;
-					string installerVersion = INSTALLER_VERSION;
-					if (installerVersion.compare(*iter)) // then the shell script-powered replacement failed
-						return UPDATE_INST_REPL_ERR;
-					else
-					{
-						updateLog.close();
-						updateLog.clear();
-						Sleep(1000);
-						remove("Update.log");
-						ofstream newUpdateLog("Update.log");
-						if (!newUpdateLog.fail())
-						{
-							// Write over old log with updated information
-							ptime startTime(second_clock::local_time());
-							string strStartTime = to_simple_string(startTime);
-							string newUpdateLine = installerVersion + " on " + strStartTime;
-							for (int a = 0; a < lines.capacity() - 2; a++) // if there were even lines in the log before this at all
-							{
-								newUpdateLog << lines[a].c_str();
-								newUpdateLog << "\n";
-							}
-							newUpdateLog << "Installer was updated to:\n";
-							newUpdateLog << newUpdateLine.c_str();
-							*installerJustUpdated = true; // this value is indirectly returned to AEInstallerAp::OnInit()
-							doneReadingFile = true;
-							newUpdateLog.close();
-							newUpdateLog.clear();
-							//return UPDATE_CONT_UPD; // as noted above, we are not using this return value; in fact, we want...
-							//							 ...the code to continue running down through the Edition version check
-						}
-						else
-							return UPDATE_LOG_READ_ERR;
-					}
-				}
-			}
-			updateLog.close();
-			updateLog.clear();
+		if (exists("../updates/Edition-patch")) {
+			firstParty = 1;
+		}
+
+	}
+
+	if(firstParty) {
+		// Unlike the current AE's version info, we *need* to find the update's version info or we won't continue
+		string updateCfgPath = ("../updates/" + strEUFN + "/install/packages/Globalize/Install_Info.cfg");
+		updateAECfg.open(updateCfgPath.c_str());
+		if (!updateAECfg.fail())
+		{
+			if (!ReadInstallInfoCfg(&updateAECfg, updateAE))
+				return UPDATE_LOG_READ_ERR;
+
+			updateAECfg.close();
+			updateAECfg.clear();
 		}
 		else
 			return UPDATE_LOG_READ_ERR;
-	}
-	
-	if (updateAE->AEVersion.compare(currentAE->AEVersion) >= 1) // is the release update newer than what's installed?
-	{
-		if (!strEUFN.compare("Edition-patch")) // if update is a patch...
-		{
-			if (currentAE->AEVersion.compare(updateAE->AEVersion.substr(0, updateAE->AEVersion.length() - 1))) // ...is it for a different month?
-				return UPDATE_MNTH_REQD_ERR;
-		}
-		string strNewInstallerPath = "../updates/" + strEUFN + "/install/" + strInstallerName;
-		string installerVersion = INSTALLER_VERSION;
-		if (updateAE->InstallerVersion.compare(installerVersion) >= 1)
-		{
-			if (exists(strNewInstallerPath))
-				return UPDATE_INST_AVAIL;
-		}
-		else if (updateAE->globalizationRequired)
-			return UPDATE_GLOB_AVAIL;
-		else
-			return UPDATE_SIMP_AVAIL;
-	}
-	else
-		return UPDATE_NO_UPD_AVAIL;
-	
+
+		// Now we check for an Installer update in progress
+		if (exists("Update.log"))
+		{
+			updateLog.open("Update.log");
+			if (!updateLog.fail())
+			{
+				vector<string> lines; 
+				string line;
+				int num_lines = 0;
+				bool readingInstallerVersion = false, doneReadingFile = false;
+
+				while (!updateLog.eof() && !doneReadingFile)
+				{
+					getline(updateLog, line);
+					lines.push_back(line);
+					num_lines++;
+					vector<string> tokens;
+					vector<string>::iterator iter;
+					tokenize(line, tokens);
+					iter = tokens.begin();
+					if (!readingInstallerVersion && tokens.capacity() >= 4)
+					{
+						if (!strInstaller.compare(*iter))
+						{
+							if (!strBeing.compare(*++iter))
+								readingInstallerVersion = true;
+							else if (!strWas.compare(*iter))
+								*installerJustUpdated = true; // our third indirect return value after currentAE and updateAE
+						}
+					}
+					else if (readingInstallerVersion && tokens.capacity() >= 3)
+					{
+						readingInstallerVersion = false;
+						string installerVersion = INSTALLER_VERSION;
+						if (installerVersion.compare(*iter)) // then the shell script-powered replacement failed
+							return UPDATE_INST_REPL_ERR;
+						else
+						{
+							updateLog.close();
+							updateLog.clear();
+							Sleep(1000);
+							remove("Update.log");
+							ofstream newUpdateLog("Update.log");
+							if (!newUpdateLog.fail())
+							{
+								// Write over old log with updated information
+								ptime startTime(second_clock::local_time());
+								string strStartTime = to_simple_string(startTime);
+								string newUpdateLine = installerVersion + " on " + strStartTime;
+								for (int a = 0; a < lines.capacity() - 2; a++) // if there were even lines in the log before this at all
+								{
+									newUpdateLog << lines[a].c_str();
+									newUpdateLog << "\n";
+								}
+								newUpdateLog << "Installer was updated to:\n";
+								newUpdateLog << newUpdateLine.c_str();
+								*installerJustUpdated = true; // this value is indirectly returned to AEInstallerAp::OnInit()
+								doneReadingFile = true;
+								newUpdateLog.close();
+								newUpdateLog.clear();
+								//return UPDATE_CONT_UPD; // as noted above, we are not using this return value; in fact, we want...
+								//							 ...the code to continue running down through the Edition version check
+							}
+							else
+								return UPDATE_LOG_READ_ERR;
+						}
+					}
+				}
+				updateLog.close();
+				updateLog.clear();
+			}
+			else
+				return UPDATE_LOG_READ_ERR;
+		}
+
+		if (updateAE->AEVersion.compare(currentAE->AEVersion) >= 1) // is the release update newer than what's installed?
+		{
+			if (!strEUFN.compare("Edition-patch")) // if update is a patch...
+			{
+				if (currentAE->AEVersion.compare(updateAE->AEVersion.substr(0, updateAE->AEVersion.length() - 1))) // ...is it for a different month?
+					return UPDATE_MNTH_REQD_ERR;
+			}
+			string strNewInstallerPath = "../updates/" + strEUFN + "/install/" + strInstallerName;
+			string installerVersion = INSTALLER_VERSION;
+			if (updateAE->InstallerVersion.compare(installerVersion) >= 1)
+			{
+				if (exists(strNewInstallerPath))
+					return UPDATE_INST_AVAIL;
+			}
+			else if (updateAE->globalizationRequired)
+				return UPDATE_GLOB_AVAIL;
+			else
+				return UPDATE_SIMP_AVAIL;
+		}
+	}
+	try {
+	directory_iterator end;
+	if(exists("../updates")){
+	for ( directory_iterator install_iter( "../updates" );
+		 install_iter != end;
+		 ++install_iter )
+	{
+
+		ModPackage installedPackage, updatePackage;
+		if ( is_directory( install_iter->path() ) && exists( install_iter->path().string() + "/Mod_Info.cfg" ) ) {
+			fstream file;
+			file.open( (install_iter->path().string() + "/Mod_Info.cfg").c_str());	
+			if (!file.fail())
+			{
+				ModPackage updatePackage = fileToModPackage(file);
+			}
+			else 
+			{
+				file.close();
+				continue;
+			}
+			if(!exists("packages" + install_iter->path().filename() + "/Mod_Info.cfg"));
+			file.close();
+			file.open( ("packages" + install_iter->path().filename() + "/Mod_Info.cfg").c_str());
+			if (!file.fail())
+			{
+				ModPackage installedPackage = fileToModPackage(file);
+			}
+			else
+			{
+				file.close();
+				return UPDATE_THIRD_PARTY;
+			}
+			file.close();
+			if(updatePackage.modStringVersion > installedPackage.modStringVersion) {
+				return UPDATE_THIRD_PARTY;
+			}
+			
+		}
+		}
+		
+	}
+	}
+	catch (exception & ex) {
+	//	setStatusArea("Warning, handled exception: " + (string)ex.what());
+	}
+	
+
 	return UPDATE_NO_UPD_AVAIL;
 }
@@ -1203,4 +1265,74 @@
 	return true; // returning 'true' tells the Installer to quit itself ASAP so it can be replaced by the process that is now running
 }
+//strPathToEUFNPackages
+
+void CrawlPackages(string pathToUpdate, string strPathToPackages) {
+	try{
+		directory_iterator end;
+		for ( directory_iterator install_iter( pathToUpdate );
+			install_iter != end;
+			++install_iter )
+		{
+
+			ModPackage installedPackage, updatePackage;
+			string updateStr = install_iter->path().string() + "/Mod_Info.cfg";
+			if ( !boost::iequals(install_iter->path().filename(),"Edition")
+				&& !boost::iequals(install_iter->path().filename(),"Edition-patch")
+				&& is_directory( install_iter->path() ) 
+				&& exists( install_iter->path().string() + "/Mod_Info.cfg" ) ) 
+			{
+				bool update = 0;
+				fstream file;
+				file.open( (install_iter->path().string() + "/Mod_Info.cfg").c_str());	
+				if (!file.fail())
+				{
+					updatePackage = fileToModPackage(file);
+				}
+				else 
+				{
+					file.close();
+					continue;
+				}
+				if(!exists(strPathToPackages + "/" + install_iter->path().filename() + "/Mod_Info.cfg"));
+				file.close();
+				file.clear();
+				file.open((strPathToPackages + "/" + install_iter->path().filename() + "/Mod_Info.cfg").c_str());
+				if (!file.fail())
+				{
+					installedPackage = fileToModPackage(file);
+					file.close();
+					if(updatePackage.modStringVersion > installedPackage.modStringVersion) {
+						remove_all((path)(strPathToPackages +  "/" + installedPackage.modStringName));			
+						update = 1;
+					}
+				}
+				else
+				{
+					file.close();
+					update = 1;
+				}
+				file.close();
+
+				if(update) {
+					rename((path)(pathToUpdate + "/" + updatePackage.modStringName), (path)(strPathToPackages + "/" + updatePackage.modStringName));
+
+				}
+			}
+		}
+	}
+	catch (exception & ex) {
+		//	ex.what();
+		setStatusArea("Warning, handled exception: " + (string)ex.what());
+	}
+}
+
+
+bool ProcessThirdPartyUpdates() {
+CrawlPackages( "../updates",  "./packages");
+return true;
+	//	globalPackages = getPackages(); 
+//	refreshMods(globalInstalledMods);
+}
+
 
 bool ProcessAEUpdate(Install_info_cfg *currentAE, Install_info_cfg *updateAE, bool *installerJustUpdated)
@@ -1368,35 +1500,5 @@
 	}
 	
-	// Now we crawl the update's package folders for newer versions and move them over, trashing ones that are already present
-	vector<ModPackage> updatePackages, currentPackages;
-	bool matchFound;
-	updatePackages.reserve(256);
-	currentPackages.reserve(256);
-	
-	currentPackages = getPackages();
-	updatePackages = getPackages(strPathToEUFNPackages);
-
-	for (vector<ModPackage>::iterator iter1 = updatePackages.begin(); iter1 != updatePackages.end(); iter1++)
-	{
-		matchFound = false;
-		for (vector<ModPackage>::iterator iter2 = currentPackages.begin(); iter2 != currentPackages.end(); iter2++)
-		{
-			if (!iter1->modStringName.compare(iter2->modStringName))
-			{
-				matchFound = true;
-				if (iter1->modStringVersion > iter2->modStringVersion)
-				{
-#ifndef WIN32
-					rename((path)(strPathToPackages + iter2->modStringName), (path)(strTrashDir + iter2->modStringName));
-#else
-					remove((path)(strPathToPackages + iter2->modStringName));
-#endif
-					rename((path)(strPathToEUFNPackages + iter1->modStringName), (path)(strPathToPackages + iter1->modStringName));
-				}
-			}
-		}
-		if (!matchFound) // then there's no old package in the way, so just move in the one from the update
-			rename((path)(strPathToEUFNPackages + iter1->modStringName), (path)(strPathToPackages + iter1->modStringName));
-	}
+	CrawlPackages( strPathToEUFNPackages,  strPathToPackages);
 	
 	// Next, we get a list of which files and folders in the update's Globalize folder to move over; all files not starting with '.' will be moved...
@@ -1455,5 +1557,4 @@
 	
 	globalPackages = getPackages(); // refresh the list in memory
-	
 	// TODO: Refresh the packages list in the window
 
