public void ApplyMod( XCMod mod )
		{
			string[] groupsName = mod.group.Split('/');

			PBXGroup[] groups = new PBXGroup[groupsName.Length];

			groups[0] = GetGroup (groupsName[0]);
			for (int i = 1; i < groupsName.Length ; i++ ) {
				groups[i] = this.GetGroup ( groupsName[i], null, groups[i-1] );
			}

			PBXGroup modGroup = groups[groups.Length - 1];
			
			foreach( XCModFile libRef in mod.libs ) {
				string completeLibPath;
				if(libRef.sourceTree.Equals("SDKROOT")) {
					completeLibPath = System.IO.Path.Combine( "usr/lib", libRef.filePath );
                    PBXGroup libraryGroup = GetGroup("Libraries");
                    this.AddFile( completeLibPath, libraryGroup, libRef.sourceTree, true, libRef.isWeak );
				}
				else {
					completeLibPath = System.IO.Path.Combine( mod.path, libRef.filePath );
                    this.AddFile( completeLibPath, modGroup, libRef.sourceTree, true, libRef.isWeak );
				}
			}
			PBXGroup frameworkGroup = this.GetGroup( "Frameworks" );
			foreach( string framework in mod.frameworks ) {
				string[] filename = framework.Split( ':' );
				bool isWeak = ( filename.Length > 1 ) ? true : false;
				string completePath = System.IO.Path.Combine( "System/Library/Frameworks", filename[0] );
				this.AddFile( completePath, frameworkGroup, "SDKROOT", true, isWeak );
			}

			foreach( string file in mod.files ) {
				string[] fileDesc = file.Split(':');
				string[] compilerFlags = null;
				if (fileDesc.Length > 1)
					compilerFlags = fileDesc[1].Split(';');
				string absoluteFilePath = System.IO.Path.Combine( mod.path, fileDesc[0] );
				//string filePath, PBXGroup parent = null, string tree = "SOURCE_ROOT", bool createBuildFiles = true, bool weak = false 
				this.AddFile( absoluteFilePath, modGroup, "SOURCE_ROOT", true, false, compilerFlags );
			}
			
			foreach( string folderPath in mod.folders ) {
				string absoluteFolderPath = System.IO.Path.Combine( mod.path, folderPath );
				absoluteFolderPath = System.IO.Path.GetFullPath(absoluteFolderPath).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
				this.AddFolder( absoluteFolderPath, mod.path, modGroup, mod.excludes.ToArray(), false/*recursive*/);
			}
			
			
			foreach( string headerpath in mod.headerpaths ) {
				string absoluteHeaderPath = AddXcodeQuotes( System.IO.Path.Combine( mod.path, headerpath ) );
				this.AddHeaderSearchPaths( absoluteHeaderPath );
			}
			
			foreach( string librarypath in mod.librarysearchpaths ) {
				string absolutePath = AddXcodeQuotes(System.IO.Path.Combine( mod.path, librarypath ));
				this.AddLibrarySearchPaths( absolutePath );
			}
			
			if(mod.frameworksearchpath != null)
			{
				foreach( string frameworksearchpath in mod.frameworksearchpath ) {
					string absoluteHeaderPath = AddXcodeQuotes(System.IO.Path.Combine( mod.path, frameworksearchpath ));
					this.AddFrameworkSearchPaths( absoluteHeaderPath );
				}
			}

			if (mod.linkers != null)
			{
				foreach( string linker in mod.linkers ) {
					string _linker = linker;
					if( !_linker.StartsWith("-") )
						_linker = "-" + _linker;
					this.AddOtherLDFlags( _linker );
				}
			}
			
			this.Consolidate();

			foreach (string plistMod in mod.plist) {
				PlistUpdater.UpdatePlist(projectRootPath, plistMod);
			}
		}
		public XCProject( string filePath ) : this()
		{
			if( !System.IO.Directory.Exists( filePath ) ) {
				Debug.LogWarning( "Path does not exists." );
				return;
			}
			
			if( filePath.EndsWith( ".xcodeproj" ) ) {
				this.projectRootPath = Path.GetDirectoryName( filePath );
				this.filePath = filePath;
			} else {
				string[] projects = System.IO.Directory.GetDirectories( filePath, "*.xcodeproj" );
				if( projects.Length == 0 ) {
					Debug.LogWarning( "Error: missing xcodeproj file" );
					return;
				}
				
				this.projectRootPath = filePath;
				this.filePath = projects[ 0 ];	
			}
			
			projectFileInfo = new FileInfo( Path.Combine( this.filePath, "project.pbxproj" ) );
			StreamReader streamReader = projectFileInfo.OpenText();
			string contents = streamReader.ReadToEnd();
			streamReader.Close();
			
			PBXParser parser = new PBXParser();
			_datastore = parser.Decode( contents );
			if( _datastore == null ) {
				throw new System.Exception( "Project file not found at file path " + filePath );
			}

			if( !_datastore.ContainsKey( "objects" ) ) {
				Debug.Log( "Errore " + _datastore.Count );
				return;
			}
			
			_objects = (PBXDictionary)_datastore["objects"];
			modified = false;
			
			_rootObjectKey = (string)_datastore["rootObject"];
			if( !string.IsNullOrEmpty( _rootObjectKey ) ) {
				_project = new PBXProject( _rootObjectKey, (PBXDictionary)_objects[ _rootObjectKey ] );
				_rootGroup = new PBXGroup( _rootObjectKey, (PBXDictionary)_objects[ _project.mainGroupID ] );
			}
			else {
				Debug.LogWarning( "Error: project has no root object" );
				_project = null;
				_rootGroup = null;
			}

		}
		public bool AddFolder( string folderPath, string rootModPath, PBXGroup parent = null, string[] exclude = null, bool recursive = true, bool createBuildFile = true )
		{
			if( !Directory.Exists( folderPath ) )
				return false;
			DirectoryInfo sourceDirectoryInfo = new DirectoryInfo( folderPath );
			
			if( exclude == null )
				exclude = new string[] {};
			
			
			if( parent == null )
				parent = rootGroup;

			//Do not create a new group if we are adding the root directory of the current parent
			PBXGroup newGroup = parent;
			if (folderPath != rootModPath) {
				newGroup = GetGroup( sourceDirectoryInfo.Name, null /*relative path*/, parent );
			}
			
			foreach( string directory in Directory.GetDirectories( folderPath ) )
			{
				if( directory.EndsWith( ".bundle" ) ) {
					// Treath it like a file and copy even if not recursive
					Debug.LogWarning( "This is a special folder: " + directory );
					AddFile( directory, newGroup, "SOURCE_ROOT", createBuildFile );
					continue;
				}
				
				if( recursive ) {
					Debug.Log( "recursive" );
					AddFolder( directory, rootModPath, newGroup, exclude, recursive, createBuildFile );
				}
			}
			
			// Adding files.
			string regexExclude = string.Format( @"{0}", string.Join( "|", exclude ) );
			foreach( string file in Directory.GetFiles( folderPath ) ) {
				if( Regex.IsMatch( file, regexExclude ) ) {
					continue;
				}
				AddFile( file, newGroup, "SOURCE_ROOT", createBuildFile );
			}
			
			
			modified = true;
			return modified;
		}
		public PBXGroup GetGroup( string name, string path = null, PBXGroup parent = null )
		{
			if( string.IsNullOrEmpty( name ) )
				return null;
			
			if( parent == null )
				parent = rootGroup;
			
			foreach( KeyValuePair<string, PBXGroup> current in groups ) {
				
				if( string.IsNullOrEmpty( current.Value.name ) ) { 
					if( current.Value.path.CompareTo( name ) == 0 ) {
						return current.Value;
					}
				}
				else if( current.Value.name.CompareTo( name ) == 0 ) {
					return current.Value;
				}
			}
			
			PBXGroup result = new PBXGroup( name, path );
			groups.Add( result );
			parent.AddChild( result );
			
			modified = true;
			return result;
			
		}
		public PBXDictionary AddFile( string filePath, PBXGroup parent = null, string tree = "SOURCE_ROOT", bool createBuildFiles = true, bool weak = false, string[] compilerFlags = null )
		{
			PBXDictionary results = new PBXDictionary();
			string absPath = string.Empty;
			
			if( Path.IsPathRooted( filePath ) ) {
				absPath = filePath;
			}
			else if( tree.CompareTo( "SDKROOT" ) != 0) {
				absPath = Path.Combine( Application.dataPath, filePath );
			}
			
			if( tree.CompareTo( "SOURCE_ROOT" ) == 0 ) {
				System.Uri fileURI = new System.Uri( absPath );
				System.Uri rootURI = new System.Uri( ( projectRootPath + "/." ) );
				filePath = rootURI.MakeRelativeUri( fileURI ).ToString();
			}
			
			if( parent == null ) {
				parent = _rootGroup;
			}
			
			// TODO: Aggiungere controllo se file già presente
			String filename = System.IO.Path.GetFileName (filePath);
			if (filename.Contains("+")) {
				filename = string.Format ("\"{0}\"", filename);
			}

			PBXFileReference fileReference = GetFile(filename); 

			if (fileReference != null) {
				//Weak references always taks precedence over strong reference
                if (weak) {
					PBXBuildFile buildFile = GetBuildFile(fileReference.guid);
					if(buildFile != null) {
						buildFile.SetWeakLink(weak);
					}
				}
				// Dear future me: If they ever invent a time machine, please don't come back in time to hunt me down.
				// From Unity 5, AdSupport is loaded dinamically, meaning that there will be a reference to the
				// file in the project and it won't add it to the linking libraries. And we need that.
				// TODO: The correct solution would be to check inside each phase if that file is already present.
				if (filename.Contains("AdSupport.framework")) {
					if (string.IsNullOrEmpty(fileReference.buildPhase)) {
						fileReference.buildPhase = "PBXFrameworksBuildPhase";
					}
				} else {
					return null;
				}

			}

			if (fileReference == null) {
				fileReference = new PBXFileReference (filePath, (TreeEnum)System.Enum.Parse (typeof(TreeEnum), tree));
				parent.AddChild (fileReference);
				fileReferences.Add (fileReference);
				results.Add (fileReference.guid, fileReference);
			}

			//Create a build file for reference
			if( !string.IsNullOrEmpty( fileReference.buildPhase ) && createBuildFiles ) {
				PBXBuildFile buildFile;
				switch( fileReference.buildPhase ) {
					case "PBXFrameworksBuildPhase":
						foreach( KeyValuePair<string, PBXFrameworksBuildPhase> currentObject in frameworkBuildPhases ) {
							PBXBuildFile newBuildFile = GetBuildFile(fileReference.guid);
							if (newBuildFile == null){
								newBuildFile = new PBXBuildFile( fileReference, weak );
								buildFiles.Add( newBuildFile );
							}

							if (currentObject.Value.HasBuildFile(newBuildFile.guid)) {
								continue;
							}
							currentObject.Value.AddBuildFile( newBuildFile );

						}
						if ( !string.IsNullOrEmpty( absPath ) && ( tree.CompareTo( "SOURCE_ROOT" ) == 0 ) && File.Exists( absPath ) ) {
							string libraryPath = Path.Combine( "$(SRCROOT)", Path.GetDirectoryName( filePath ) );
							this.AddLibrarySearchPaths( new PBXList( libraryPath ) ); 
						}
						break;
					case "PBXResourcesBuildPhase":
						foreach( KeyValuePair<string, PBXResourcesBuildPhase> currentObject in resourcesBuildPhases ) {
							buildFile = new PBXBuildFile( fileReference, weak );
							buildFiles.Add( buildFile );
							currentObject.Value.AddBuildFile( buildFile );
						}
						break;
					case "PBXShellScriptBuildPhase":
						foreach( KeyValuePair<string, PBXShellScriptBuildPhase> currentObject in shellScriptBuildPhases ) {
							buildFile = new PBXBuildFile( fileReference, weak );
							buildFiles.Add( buildFile );
							currentObject.Value.AddBuildFile( buildFile );
						}
						break;
					case "PBXSourcesBuildPhase":
						foreach( KeyValuePair<string, PBXSourcesBuildPhase> currentObject in sourcesBuildPhases ) {
							buildFile = new PBXBuildFile( fileReference, weak );
							foreach (string flag in compilerFlags) {
								buildFile.AddCompilerFlag(flag);
							}
							buildFiles.Add( buildFile );
							currentObject.Value.AddBuildFile( buildFile );
						}
						break;
					case "PBXCopyFilesBuildPhase":
						foreach( KeyValuePair<string, PBXCopyFilesBuildPhase> currentObject in copyBuildPhases ) {
							buildFile = new PBXBuildFile( fileReference, weak );
							buildFiles.Add( buildFile );
							currentObject.Value.AddBuildFile( buildFile );
						}
						break;
					case null:
						Debug.LogWarning( "fase non supportata null" );
						break;
					default:
						Debug.LogWarning( "fase non supportata def" );
						return null;
				}
			}
			
			return results;
			
		}