BuildResult UpdateInfoPlist (IProgressMonitor monitor, IPhoneProject proj, IPhoneProjectConfiguration conf,
		                             IPhoneAppIdentity identity, ProjectFile template, string plistOut)
		{
			return CreateMergedPlist (monitor, conf, template, plistOut, 
				(IPhoneProjectConfiguration config, PlistDocument doc) => 
			{
				var result = new BuildResult ();
				var dict = doc.Root as PlistDictionary;
				if (dict == null)
					doc.Root = dict = new PropertyList.PlistDictionary ();
				
				bool sim = conf.Platform != IPhoneProject.PLAT_IPHONE;
				
				SetIfNotPresent (dict, "CFBundleDevelopmentRegion",
					String.IsNullOrEmpty (proj.BundleDevelopmentRegion)? "English" : proj.BundleDevelopmentRegion);
				
				SetIfNotPresent (dict, "CFBundleDisplayName", proj.BundleDisplayName ?? proj.Name);
				SetIfNotPresent (dict, "CFBundleExecutable", conf.NativeExe.FileName);
				
				//iphone icons
				if ((proj.SupportedDevices & TargetDevice.IPhone) != 0) {
					if (!dict.ContainsKey ("CFBundleIconFile")) {
						var icon = proj.BundleIcon.ToRelative (proj.BaseDirectory);
						if (icon.IsNullOrEmpty || icon.ToString () == ".")
							result.AddWarning ("Application bundle icon has not been set");
						else
							dict ["CFBundleIconFile"] = icon.FileName;
					}
				}
				
				//ipad and universal icons
				if ((proj.SupportedDevices & TargetDevice.IPad) != 0 && !dict.ContainsKey ("CFBundleIconFiles")) {
					var arr = new PlistArray ();
					dict["CFBundleIconFiles"] = arr;
					//universal only
					if ((proj.SupportedDevices & TargetDevice.IPhone) != 0)
						AddRelativeIfNotEmpty (proj, arr, proj.BundleIcon);
					//ipad and universal
					AddRelativeIfNotEmpty (proj, arr, proj.BundleIconSpotlight);
					AddRelativeIfNotEmpty (proj, arr, proj.BundleIconIPadSpotlight);
					if (!AddRelativeIfNotEmpty (proj, arr, proj.BundleIconIPad))
						result.AddWarning ("iPad bundle icon has not been set");
				}
				
				SetIfNotPresent (dict, "CFBundleIdentifier", identity.BundleID);
				SetIfNotPresent (dict, "CFBundleInfoDictionaryVersion", "6.0");
				SetIfNotPresent (dict, "CFBundleName", proj.Name);
				SetIfNotPresent (dict, "CFBundlePackageType", "APPL");
				if (!sim)
					dict["CFBundleResourceSpecification"] = "ResourceRules.plist";
				SetIfNotPresent (dict, "CFBundleSignature", "????");
				SetIfNotPresent (dict,  "CFBundleSupportedPlatforms",
					new PropertyList.PlistArray () { sim? "iPhoneSimulator" : "iPhoneOS" });
				SetIfNotPresent (dict, "CFBundleVersion", proj.BundleVersion ?? "1.0");
				SetIfNotPresent (dict, "DTPlatformName", sim? "iphonesimulator" : "iphoneos");
				SetIfNotPresent (dict, "DTSDKName", (sim? "iphonesimulator" : "iphoneos")  + conf.MtouchSdkVersion);
				SetIfNotPresent (dict,  "LSRequiresIPhoneOS", true);
				if (proj.SupportedDevices != TargetDevice.IPhone)
					SetIfNotPresent (dict,  "UIDeviceFamily", GetSupportedDevices (proj.SupportedDevices));
				SetIfNotPresent (dict, "DTPlatformVersion", conf.MtouchSdkVersion);
				
				SetIfNotPresent (dict, "MinimumOSVersion", conf.MtouchMinimumOSVersion);
				
				SetNibProperty (dict, proj, proj.MainNibFile, "NSMainNibFile");
				if (proj.SupportedDevices == TargetDevice.IPhoneAndIPad)
					SetNibProperty (dict, proj, proj.MainNibFileIPad, "NSMainNibFile~ipad");
				
				return result;
			});
		}
		static BuildResult UpdateDebugSettingsPlist (IProgressMonitor monitor, IPhoneProjectConfiguration conf,
		                                             ProjectFile template, string target)
		{
			if (template != null && template.BuildAction != BuildAction.Content)
				template = null;
			
			//if not in debug mode, make sure that the settings file is either
			//copied cleanly or deleted
			if (!conf.DebugMode) {
				if (template != null) {
					EnsureDirectoryForFile (target);
					File.Copy (template.FilePath, target, true);
				} else if (File.Exists (target)) {
					File.Delete (target);
				}
				return null;
			}
			
			return CreateMergedPlist (monitor, conf, template, target,
				(IPhoneProjectConfiguration config, PlistDocument doc) =>
			{
				var br = new BuildResult ();
				var debuggerIP = System.Net.IPAddress.Any;
				bool sim = config.Platform == IPhoneProject.PLAT_SIM;
				
				try {
					debuggerIP = IPhoneSettings.GetDebuggerHostIP (sim);
				} catch {
					br.AddWarning (GettextCatalog.GetString ("Could not resolve host IP for debugger settings"));
				}
				
				var dict = doc.Root as PlistDictionary;
				if (dict == null)
					doc.Root = dict = new PropertyList.PlistDictionary ();
				
				SetIfNotPresent (dict, "Title", "AppSettings");
				SetIfNotPresent (dict, "StringsTable", "Root");
				
				var arr = dict.TryGetValue ("PreferenceSpecifiers") as PlistArray;
				if (arr == null)
					dict["PreferenceSpecifiers"] = arr = new PlistArray ();
				
				arr.Add (new PlistDictionary (true) {
					{ "Type", "PSGroupSpecifier" },
					{ "Title", "Debug Settings" }
				});
				
				arr.Add (new PlistDictionary (true) {
					{ "Type", "PSToggleSwitchSpecifier" },
					{ "Title", "Enabled" },
					{ "Key", "__monotouch_debug_enabled" },
					{ "DefaultValue", "1" },
					{ "TrueValue", "1" },
					{ "FalseValue", "0" }
				});
				
				arr.Add (new PlistDictionary (true) {
					{ "Type", "PSTextFieldSpecifier" },
					{ "Title", "Debugger Host" },
					{ "Key", "__monotouch_debug_host" },
					{ "AutocapitalizationType", "None" },
					{ "AutocorrectionType", "No" },
					{ "DefaultValue", debuggerIP.ToString () }
				});
					
				arr.Add (new PlistDictionary (true) {
					{ "Type", "PSTextFieldSpecifier" },
					{ "Title", "Debugger Port" },
					{ "Key", "__monotouch_debug_port" },
					{ "AutocapitalizationType", "None" },
					{ "AutocorrectionType", "No" },
					{ "DefaultValue", IPhoneSettings.DebuggerPort.ToString () }
				});
					
				arr.Add (new PlistDictionary (true) {
					{ "Type", "PSTextFieldSpecifier" },
					{ "Title", "Output Port" },
					{ "Key", "__monotouch_output_port" },
					{ "AutocapitalizationType", "None" },
					{ "AutocorrectionType", "No" },
					{ "DefaultValue", IPhoneSettings.DebuggerOutputPort.ToString () }
				});
				
				return br;
			});
		}