using System; using System.IO; using System.Text.RegularExpressions; using System.Collections.Generic; namespace codehunt.datarelease { /// <summary> /// A single code submission for a level. /// </summary> public class Attempt : IExplorable { //Format: attemptNNN-YYYYMMDD-HHMMSS[-winningR].(java|cs) private static readonly Regex attemptFilenameRegex = new Regex(@"attempt(?<attemptNum>[0-9]{3})-" + "(?<year>[0-9]{4})(?<month>[0-9]{2})(?<day>[0-9]{2})-" + "(?<hour>[0-9]{2})(?<minute>[0-9]{2})(?<second>[0-9]{2})" + "(-winning(?<rating>[1-3]))?.(?<ext>java|cs)", RegexOptions.Compiled | RegexOptions.IgnoreCase); private readonly User user; private readonly Level level; private readonly FileInfo attemptFile; private readonly int attemptNum; private readonly DateTime timestamp; private readonly int? rating; private readonly Language language; private string text; public Attempt(User user, Level level, FileInfo attemptFile) { this.user = user; this.level = level; this.attemptFile = attemptFile; Match match = attemptFilenameRegex.Match(Path.GetFileName(attemptFile.FullName)); this.attemptNum = int.Parse(match.Groups["attemptNum"].Value); int year = int.Parse(match.Groups["year"].Value); int month = int.Parse(match.Groups["month"].Value); int day = int.Parse(match.Groups["day"].Value); int hour = int.Parse(match.Groups["hour"].Value); int minute = int.Parse(match.Groups["minute"].Value); int second = int.Parse(match.Groups["second"].Value); this.timestamp = new DateTime(year: year, month: month, day: day, hour: hour, minute: minute, second: second, kind: DateTimeKind.Utc); if (match.Groups["rating"].Success) { this.rating = int.Parse(match.Groups["rating"].Value); } else { this.rating = null; } this.language = LanguageUtil.FromExtension(match.Groups["ext"].Value); } /// <summary> /// Gets the code for this attempt. See the Language property for /// whether this code is in Java or C#. /// </summary> /// <value>The code.</value> public string Text { get { if (this.text == null) { this.text = File.ReadAllText(this.attemptFile.FullName); } return this.text; } } /// <summary> /// Language this submission is in. Java or CSharp. /// </summary> /// <value>The language.</value> public Language Language { get { return this.language; } } /// <summary> /// Time this attempt was submitted. /// </summary> /// <value>The timestamp.</value> public DateTime Timestamp { get { return this.timestamp; } } /// <summary> /// User that submitted this attempt. /// </summary> /// <value>The user.</value> public User User { get { return this.user; } } /// <summary> /// Level this attempt was submitted for. /// </summary> /// <value>The level.</value> public Level Level { get { return this.level; } } public string ChallengeId { get { return this.Level.ChallengeId; } } /// <summary> /// File storing the code for this attempt. /// </summary> /// <value>The attempt file.</value> public FileInfo AttemptFile { get { return this.attemptFile; } } /// <summary> /// Gets the attempt number where 1 is the first attempt. /// </summary> /// <value>The attempt number.</value> public int AttemptNum { get { return this.attemptNum; } } /// <summary> /// Gets a value indicating whether this attempt won the level. /// </summary> /// <value><c>true</c> if won; otherwise, <c>false</c>.</value> public bool Won { get { return this.rating.HasValue; } } /// <summary> /// Gets the rating (1-3) of a winning attempt or null if not a winning attempt. /// </summary> /// <value>The rating.</value> public int? Rating { get { return this.rating; } } public override bool Equals(object obj) { if (obj == this) { return true; } else if (obj is Attempt) { return ((Attempt)obj).AttemptFile.Equals(AttemptFile); } else { return false; } } public override int GetHashCode() { return AttemptFile.GetHashCode(); } public override string ToString() { return string.Format("[Attempt {0} {1} {2}]", User, Level, Path.GetFileName(AttemptFile.FullName)); } } }