using JetBrains.Annotations;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace Microsoft.Win32.TaskScheduler
{
/// Provides information and control for a collection of folders that contain tasks.
public sealed class TaskFolderCollection : ICollection, IDisposable, INotifyCollectionChanged, INotifyPropertyChanged
{
private const string IndexerName = "Item[]";
private readonly TaskFolder parent;
private readonly TaskFolder[] v1FolderList;
private readonly V2Interop.ITaskFolderCollection v2FolderList;
internal TaskFolderCollection() => v1FolderList = new TaskFolder[0];
internal TaskFolderCollection([NotNull] TaskFolder folder, [NotNull] V2Interop.ITaskFolderCollection iCollection)
{
parent = folder;
v2FolderList = iCollection;
}
/// Occurs when a collection changes.
public event NotifyCollectionChangedEventHandler CollectionChanged;
/// Occurs when a property value changes.
public event PropertyChangedEventHandler PropertyChanged;
/// Gets the number of items in the collection.
public int Count => v2FolderList?.Count ?? v1FolderList.Length;
/// Gets a value indicating whether the is read-only.
bool ICollection.IsReadOnly => false;
/// Gets the specified folder from the collection.
/// The index of the folder to be retrieved.
/// A TaskFolder instance that represents the requested folder.
public TaskFolder this[int index]
{
get
{
if (v2FolderList != null)
return new TaskFolder(parent.TaskService, v2FolderList[++index]);
return v1FolderList[index];
}
}
/// Gets the specified folder from the collection.
/// The path of the folder to be retrieved.
/// A TaskFolder instance that represents the requested folder.
public TaskFolder this[[NotNull] string path]
{
get
{
try
{
if (v2FolderList != null)
return parent.GetFolder(path);
if (v1FolderList != null && v1FolderList.Length > 0 && (path == string.Empty || path == "\\"))
return v1FolderList[0];
}
catch { }
throw new ArgumentException(@"Path not found", nameof(path));
}
}
/// Adds an item to the .
/// The object to add to the .
///
/// This action is technically unfeasible due to limitations of the underlying library. Use the instead.
///
public void Add([NotNull] TaskFolder item) => throw new NotImplementedException();
/// Removes all items from the .
public void Clear()
{
if (v2FolderList != null)
{
for (var i = v2FolderList.Count; i > 0; i--)
parent.DeleteFolder(v2FolderList[i].Name, false);
OnNotifyPropertyChanged(nameof(Count));
OnNotifyPropertyChanged(IndexerName);
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
/// Determines whether the contains a specific value.
/// The object to locate in the .
/// true if is found in the ; otherwise, false.
public bool Contains([NotNull] TaskFolder item)
{
if (v2FolderList != null)
{
for (var i = v2FolderList.Count; i > 0; i--)
if (string.Equals(item.Path, v2FolderList[i].Path, StringComparison.CurrentCultureIgnoreCase))
return true;
}
else
return item.Path == "\\";
return false;
}
/// Copies the elements of the ICollection to an Array, starting at a particular Array index.
///
/// The one-dimensional Array that is the destination of the elements copied from . The Array must have
/// zero-based indexing.
///
/// The zero-based index in array at which copying begins.
public void CopyTo(TaskFolder[] array, int arrayIndex)
{
if (arrayIndex < 0) throw new ArgumentOutOfRangeException(nameof(arrayIndex));
if (array == null) throw new ArgumentNullException(nameof(array));
if (v2FolderList != null)
{
if (arrayIndex + Count > array.Length)
throw new ArgumentException();
foreach (var f in this)
array[arrayIndex++] = f;
}
else
{
if (arrayIndex + v1FolderList.Length > array.Length)
throw new ArgumentException();
v1FolderList.CopyTo(array, arrayIndex);
}
}
/// Releases all resources used by this class.
public void Dispose()
{
if (v1FolderList != null && v1FolderList.Length > 0)
{
v1FolderList[0].Dispose();
v1FolderList[0] = null;
}
if (v2FolderList != null)
System.Runtime.InteropServices.Marshal.ReleaseComObject(v2FolderList);
}
/// Determines whether the specified folder exists.
/// The path of the folder.
/// true if folder exists; otherwise, false.
public bool Exists([NotNull] string path)
{
try
{
parent.GetFolder(path);
return true;
}
catch { }
return false;
}
/// Gets a list of items in a collection.
/// Enumerated list of items in the collection.
public IEnumerator GetEnumerator()
{
if (v2FolderList != null)
return new System.Runtime.InteropServices.ComEnumerator(() => v2FolderList.Count, (object o) => v2FolderList[o], o => new TaskFolder(parent.TaskService, o));
return Array.AsReadOnly(v1FolderList).GetEnumerator();
}
/*
/// Returns the index of the TaskFolder within the collection.
/// TaskFolder to find.
/// Index of the TaskFolder; -1 if not found.
public int IndexOf(TaskFolder item)
{
return IndexOf(item.Path);
}
/// Returns the index of the TaskFolder within the collection.
/// Path to find.
/// Index of the TaskFolder; -1 if not found.
public int IndexOf(string path)
{
if (v2FolderList != null)
{
for (int i = 0; i < v2FolderList.Count; i++)
{
if (v2FolderList[new System.Runtime.InteropServices.VariantWrapper(i)].Path == path)
return i;
}
return -1;
}
else
return (v1FolderList.Length > 0 && (path == string.Empty || path == "\\")) ? 0 : -1;
}
*/
/// Removes the first occurrence of a specific object from the .
/// The object to remove from the .
///
/// true if was successfully removed from the ; otherwise, false. This method
/// also returns false if is not found in the original .
///
public bool Remove([NotNull] TaskFolder item)
{
if (v2FolderList != null)
{
for (var i = v2FolderList.Count; i > 0; i--)
{
if (string.Equals(item.Path, v2FolderList[i].Path, StringComparison.CurrentCultureIgnoreCase))
{
try
{
parent.DeleteFolder(v2FolderList[i].Name);
OnNotifyPropertyChanged(nameof(Count));
OnNotifyPropertyChanged(IndexerName);
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, i));
}
catch
{
return false;
}
return true;
}
}
}
return false;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator();
/// Called when a property has changed to notify any attached elements.
/// Name of the property.
private void OnNotifyPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}