using System; using System.Collections.Generic; using System.Globalization; namespace ScrewTurn.Wiki { /// /// Implements methods for sorting pages. /// public static class PageSortingTools { /// /// Sorts pages. /// /// The pages list to sort. /// The sorting method. /// true to sort in reverse order. /// The sorted list, divided in relevant groups. public static SortedDictionary> Sort(ExtendedPageInfo[] pages, SortingMethod sortBy, bool reverse) { switch(sortBy) { case SortingMethod.Title: return SortByTitle(pages, reverse); case SortingMethod.Creator: return SortByCreator(pages, reverse); case SortingMethod.User: return SortByUser(pages, reverse); case SortingMethod.DateTime: return SortByDateTime(pages, reverse); case SortingMethod.Creation: return SortByCreation(pages, reverse); default: throw new NotSupportedException("Invalid sorting method"); } } /// /// Sorts pages by title. /// /// The pages. /// true to sort in reverse order. /// The sorted list, divided in relevant groups (#, A, B, etc.). private static SortedDictionary> SortByTitle(ExtendedPageInfo[] pages, bool reverse) { ExtendedPageInfo[] temp = new ExtendedPageInfo[pages.Length]; Array.Copy(pages, temp, pages.Length); Array.Sort(temp, delegate(ExtendedPageInfo p1, ExtendedPageInfo p2) { string t1 = p1.Title, t2 = p2.Title; if(!reverse) return string.Compare(t1, t2, false, CultureInfo.CurrentCulture); else return string.Compare(t2, t1, false, CultureInfo.CurrentCulture); }); SortedDictionary> result = new SortedDictionary>(new CharComparer(reverse)); foreach(ExtendedPageInfo p in temp) { char first = GetFirstChar(p.Title); if(!char.IsLetter(first)) { if(!result.ContainsKey('#')) result.Add('#', new List(20)); result['#'].Add(p); } else { if(!result.ContainsKey(first)) result.Add(first, new List(20)); result[first].Add(p); } } SortedDictionary> finalResult = new SortedDictionary>(new SortingGroupComparer(reverse)); foreach(char key in result.Keys) { finalResult.Add(new SortingGroup(GetLetterNumber(key), key.ToString(), key), result[key]); } return finalResult; } private static char GetFirstChar(string value) { return value.ToUpper(CultureInfo.CurrentCulture)[0]; } /// /// Sorts pages by last author. /// /// The pages. /// true to sort in reverse order. /// The sorted list, divided in relevant groups (#, A, B, etc.). private static SortedDictionary> SortByUser(ExtendedPageInfo[] pages, bool reverse) { ExtendedPageInfo[] temp = new ExtendedPageInfo[pages.Length]; Array.Copy(pages, temp, pages.Length); Array.Sort(temp, delegate(ExtendedPageInfo p1, ExtendedPageInfo p2) { string u1 = p1.LastAuthor, u2 = p2.LastAuthor; if(!reverse) return string.Compare(u1, u2, false, CultureInfo.CurrentCulture); else return string.Compare(u2, u1, false, CultureInfo.CurrentCulture); }); SortedDictionary> result = new SortedDictionary>(new CharComparer(reverse)); foreach(ExtendedPageInfo p in temp) { char first = GetFirstChar(p.LastAuthor); if(!char.IsLetter(first)) { if(!result.ContainsKey('#')) result.Add('#', new List(20)); result['#'].Add(p); } else { if(!result.ContainsKey(first)) result.Add(first, new List(20)); result[first].Add(p); } } SortedDictionary> finalResult = new SortedDictionary>(new SortingGroupComparer(reverse)); foreach(char key in result.Keys) { finalResult.Add(new SortingGroup(GetLetterNumber(key), key.ToString(), key), result[key]); } return finalResult; } /// /// Sorts pages by creator. /// /// The pages. /// true to sort in reverse order. /// The sorted list, divided in relevant groups (#, A, B, etc.). private static SortedDictionary> SortByCreator(ExtendedPageInfo[] pages, bool reverse) { ExtendedPageInfo[] temp = new ExtendedPageInfo[pages.Length]; Array.Copy(pages, temp, pages.Length); Array.Sort(temp, delegate(ExtendedPageInfo p1, ExtendedPageInfo p2) { string u1 = p1.Creator, u2 = p2.Creator; if(!reverse) return string.Compare(u1, u2, false, CultureInfo.CurrentCulture); else return string.Compare(u2, u1, false, CultureInfo.CurrentCulture); }); SortedDictionary> result = new SortedDictionary>(new CharComparer(reverse)); foreach(ExtendedPageInfo p in temp) { char first = GetFirstChar(p.Creator); if(!char.IsLetter(first)) { if(!result.ContainsKey('#')) result.Add('#', new List(20)); result['#'].Add(p); } else { if(!result.ContainsKey(first)) result.Add(first, new List(20)); result[first].Add(p); } } SortedDictionary> finalResult = new SortedDictionary>(new SortingGroupComparer(reverse)); foreach(char key in result.Keys) { finalResult.Add(new SortingGroup(GetLetterNumber(key), key.ToString(), key), result[key]); } return finalResult; } /// /// Sorts pages by modification date/time. /// /// The pages. /// true to sort in reverse order. /// The sorted list, divided in relevant groups. private static SortedDictionary> SortByDateTime(ExtendedPageInfo[] pages, bool reverse) { ExtendedPageInfo[] temp = new ExtendedPageInfo[pages.Length]; Array.Copy(pages, temp, pages.Length); Array.Sort(temp, delegate(ExtendedPageInfo p1, ExtendedPageInfo p2) { if(!reverse) return p1.ModificationDateTime.CompareTo(p2.ModificationDateTime); else return p2.ModificationDateTime.CompareTo(p1.ModificationDateTime); }); SortedDictionary> result = new SortedDictionary>(new DateTimeComparer(reverse)); Dictionary labels = new Dictionary(); foreach(ExtendedPageInfo p in temp) { string label; DateTime marker = GetMarkerDate(p.ModificationDateTime, out label); if(!result.ContainsKey(marker)) { result.Add(marker, new List(20)); labels.Add(marker, label); } result[marker].Add(p); } SortedDictionary> finalResult = new SortedDictionary>(new SortingGroupComparer(reverse)); foreach(DateTime key in result.Keys) { finalResult.Add(new SortingGroup(key.DayOfYear + key.Year * 1000, labels[key], key), result[key]); } return finalResult; } /// /// Sorts pages by creation date/time. /// /// The pages. /// true to sort in reverse order. /// The sorted list, divided in relevant groups. private static SortedDictionary> SortByCreation(ExtendedPageInfo[] pages, bool reverse) { ExtendedPageInfo[] temp = new ExtendedPageInfo[pages.Length]; Array.Copy(pages, temp, pages.Length); Array.Sort(temp, delegate(ExtendedPageInfo p1, ExtendedPageInfo p2) { if(!reverse) return p1.CreationDateTime.CompareTo(p2.CreationDateTime); else return p2.CreationDateTime.CompareTo(p1.CreationDateTime); }); SortedDictionary> result = new SortedDictionary>(new DateTimeComparer(reverse)); Dictionary labels = new Dictionary(); foreach(ExtendedPageInfo p in temp) { string label; DateTime marker = GetMarkerDate(p.CreationDateTime, out label); if(!result.ContainsKey(marker)) { result.Add(marker, new List(20)); labels.Add(marker, label); } result[marker].Add(p); } SortedDictionary> finalResult = new SortedDictionary>(new SortingGroupComparer(reverse)); foreach(DateTime key in result.Keys) { finalResult.Add(new SortingGroup(key.DayOfYear + key.Year * 1000, labels[key], key), result[key]); } return finalResult; } private static int GetLetterNumber(char c) { // Only # and letters allowed c = char.ToUpperInvariant(c); if(c == '#') return 0; else return c - 64; } private static DateTime GetMarkerDate(DateTime dt, out string label) { DateTime now = DateTime.Now; // Today if(dt.Date == now.Date) { label = Properties.Messages.Today; return new DateTime(now.Year, now.Month, now.Day); } // Yesterday DateTime yesterday = now.AddDays(-1); if(dt.Date == yesterday.Date) { label = Properties.Messages.Yesterday; return new DateTime(yesterday.Year, yesterday.Month, yesterday.Day); } // Earlier this week DateTime thisWeek = now; while(thisWeek.DayOfWeek != DayOfWeek.Monday) thisWeek = thisWeek.AddDays(-1); if(dt.Year == thisWeek.Year && dt.Month == thisWeek.Month && dt.Day >= thisWeek.Day) { label = Properties.Messages.EarlierThisWeek; return new DateTime(thisWeek.Year, thisWeek.Month, thisWeek.Day); } // Earlier this month DateTime thisMonth = now; while(thisMonth.Day != 1) thisMonth = thisMonth.AddDays(-1); if(dt.Year == thisMonth.Year && dt.Month == thisMonth.Month) { label = Properties.Messages.EarlierThisMonth + " (" + thisMonth.ToString("MMMM") + ")"; return new DateTime(thisMonth.Year, thisMonth.Month, thisMonth.Day); } // Last month DateTime lastMonth = now.AddMonths(-1); while(lastMonth.Day != 1) lastMonth = lastMonth.AddDays(-1); if(dt.Year == lastMonth.Year && dt.Month == lastMonth.Month) { label = Properties.Messages.LastMonth + " (" + lastMonth.ToString("MMMM") + ")"; return new DateTime(lastMonth.Year, lastMonth.Month, lastMonth.Day); } label = Properties.Messages.Older; return DateTime.MinValue; } } /// /// Lists legal page sorting methods. /// public enum SortingMethod { /// /// Sort by title. /// Title, /// /// Sort by creator. /// Creator, /// /// Sort by last author. /// User, /// /// Sort by creation date/time. /// Creation, /// /// Sort by modification date/time. /// DateTime } /// /// Describes a sorting group. /// public class SortingGroup { private int number; private string label; private object tag; /// /// Initializes a new instance of the SortingGroup class. /// /// The group number. /// The group label. /// The group tag. public SortingGroup(int number, string label, object tag) { this.number = number; this.label = label; this.tag = tag; } /// /// Gets the group number. /// public int Number { get { return number; } } /// /// Gets the group label. /// public string Label { get { return label; } } /// /// Gets the group tag. /// public object Tag { get { return tag; } } } /// /// Implements a Sorting Group comparer. /// public class SortingGroupComparer : IComparer { private bool reverse; /// /// Initializes a new instance of the SortingGroupComparer class. /// /// true to perform the comparison in reverse order. public SortingGroupComparer(bool reverse) { this.reverse = reverse; } /// /// Compares two Sorting Groups. /// /// The first Sorting Group. /// The second Sorting Group. /// The comparison result. public int Compare(SortingGroup x, SortingGroup y) { if(!reverse) return x.Number.CompareTo(y.Number); else return y.Number.CompareTo(x.Number); } } /// /// Implements a char comparer. /// public class CharComparer : IComparer { private bool reverse; /// /// Initializes a new instance of the CharComparer class. /// /// true to perform a reverse comparison. public CharComparer(bool reverse) { this.reverse = reverse; } /// /// Compares two chars. /// /// The first char. /// The second char. /// The comparison result. public int Compare(char x, char y) { if(!reverse) return x.CompareTo(y); else return y.CompareTo(x); } } /// /// Implements a date/time comparer. /// public class DateTimeComparer : IComparer { private bool reverse; /// /// Initializes a new instance of the DateTimeComparer class. /// /// true to perform reverse comparison. public DateTimeComparer(bool reverse) { this.reverse = reverse; } /// /// Compares two date/times. /// /// The first date/time. /// The second date/time. /// The comparison result. public int Compare(DateTime x, DateTime y) { if(!reverse) return x.CompareTo(y); else return y.CompareTo(x); } } }