/// <summary>
		/// Scan a path for files and synchronize its content with our collection
		/// </summary>
		/// <param name="path">The path to scan</param>
		/// <param name="tree">The tree that is either the path itself or the parent</param>
		/// <param name="removeIgnored">Whether or not we should remove any paths that we find which is set to ignore</param>
		/// <param name="callback">The callback which will be sent along with the SourceModified event</param>
		private static void ScanPath(String path, SourceTree tree, bool removeIgnored = true, ScannerCallback callback = null, object callbackParams = null)
		{
			List<KeyValuePair<ScannerCallback, object>> callbacks = new List<KeyValuePair<ScannerCallback, object>>();
			if (callback != null)
				callbacks.Add(new KeyValuePair<ScannerCallback,object>(callback, callbackParams));
			ScanPath(path, tree, removeIgnored, callbacks);
		}
		/// <summary>
		/// Scan a path for files and synchronize its content with our collection
		/// </summary>
		/// <param name="path">The path to scan</param>
		/// <param name="tree">The tree that is either the path itself or the parent</param>
		/// <param name="removeIgnored">Whether or not we should remove any paths that we find which is set to ignore</param>
		/// <param name="callbacks">A list of callbacks and their respective parameters which will be sent along with the SourceModified event</param>
		private static void ScanPath(String path, SourceTree tree, bool removeIgnored, List<KeyValuePair<ScannerCallback, object>> callbacks)
		{
			// ignore the recycle bin
			if (path.Substring(1).ToUpper().StartsWith(@":\$RECYCLE.BIN")) return;

			// break if program is closing
			if (U.IsClosing) return;

			WaitForInitialization();

			// path is a file
			if (File.Exists(path))
			{
				if (tree.Include) AddFile(path, false, callbacks);
				else if (removeIgnored) RemoveFile(path, callbacks);
			}

			// path is a folder
			else if (Directory.Exists(path))
			{
				string[] files = Directory.GetFiles(path);
				string[] folders = Directory.GetDirectories(path);

				// calculate the amount of progress to increase each file/folder with
				//double progressIncrease = deltaProgress / (files.Count() + folders.Count());

				// scan all toplevel files
				string[] ext = MediaManager.SupportedFormatsExtensions.Split(';');
				try
				{
					for (int i=0; i<files.Count(); i++)
					{
						// break if program is closing
						if (U.IsClosing) return;

						string file = files[i];

						//int progressPos = (int)(progressPosition + (i * progressIncrease));
						//DispatchProgressChanged(progressPos, "progress");

						if (!ext.Contains("*" + Path.GetExtension(file)))
						    continue;

						bool include = tree.Include;
						SourceTree st = GetSourceTree(file, tree.Children);
						if (st != null)
							include = st.Include;

						foreach (SourceTree childTree in tree.Children)
						{
							if (childTree.Data == file)
							{
								include = childTree.Include;
								break;
							}
						}
						if (include) AddFile(file, false, callbacks);
						else if (removeIgnored) RemoveFile(file, callbacks);
					}

					// dive inside subfolders
					for (int i=0; i<folders.Count(); i++)
					{
						// break if program is closing
						if (U.IsClosing) return;

						string subfolder = folders[i];

						//int progressPos = (int)(progressPosition + ((files.Count() + i) * progressIncrease));
						//DispatchProgressChanged(progressPos, "progress");

						SourceTree subtree = GetSourceTree(subfolder, tree.Children);
						if (subtree == null) subtree = tree;
						ScanPath(subfolder, subtree, removeIgnored, callbacks);
					}
				}
				catch (Exception e)
				{
					// break if program is closing
					if (U.IsClosing) return;

					U.L(LogLevel.Warning, "FILESYSTEM", "Could not scan " + path + ": " + e.Message);
				}
			}
		}
		/// <summary>
		/// Insert a source tree into a forest. The tree will be inserted into the forest so that
		/// the parent will be a folder which contains the folder that the tree describes.
		/// </summary>
		/// <param name="tree">The tree to insert</param>
		/// <param name="forest">The forest to insert the tree into</param>
		private static void InsertSourceTree(SourceTree tree, List<SourceTree> forest)
		{
			for (int i=0; i<forest.Count; i++)
			{
				SourceTree t = forest[i];

				if (tree.Data == t.Data)
					return;

				// insert tree into t
				else if (tree.Data.StartsWith(t.Data))
				{
					InsertSourceTree(tree, t.Children);
					return;
				}

				// swap t for tree and make t a child of tree
				else if (t.Data.StartsWith(tree.Data))
				{
					tree.Children.Add(t);
					forest.RemoveAt(i);
					forest.Insert(i, tree);

					// continue through the forest and find any additional children for tree
					for (int j = i + 1; j < forest.Count; j++)
					{
						t = forest[j];
						if (t.Data.StartsWith(tree.Data))
						{
							tree.Children.Add(t);
							forest.RemoveAt(j--);
						}
					}
					return;
				}
			}
			// insert tree into forest as top tree
			forest.Add(tree);
		}