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);
}
}
}