using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using Iesi.Collections.Generic; using Portoa.Persistence; namespace VideoGameQuotes.Api { public class Quote : Entity, IDtoMappable { private readonly Iesi.Collections.Generic.ISet votes = new HashedSet(); private readonly Iesi.Collections.Generic.ISet flags = new HashedSet(); private readonly Iesi.Collections.Generic.ISet categories = new HashedSet(); public Quote() { Created = DateTime.UtcNow; } public virtual User Creator { get; set; } public virtual DateTime Created { get; set; } public virtual DateTime? Modified { get; set; } public virtual string Text { get; set; } public virtual Game Game { get; set; } public virtual IEnumerable Votes { get { return votes; } } public virtual IEnumerable Flags { get { return flags; } } public virtual IEnumerable Categories { get { return categories; } } #region adding and removing stuff public virtual Quote AddCategory(Category category) { categories.Add(category); return this; } public virtual void ClearCategories() { categories.Clear(); } public virtual Quote AddFlag(string comment, QuoteFlagType type, User user) { flags.Add(new QuoteFlag { Comment = comment, Type = type, User = user, Quote = this }); return this; } public virtual void ClearFlags() { flags.Clear(); } #endregion public virtual Quote VoteFor(User user, VoteDirection direction) { var currentVote = votes.SingleOrDefault(vote => vote.Voter == user); if (currentVote != null) { if (currentVote.Direction == direction) { throw new CannotVoteTwiceException(); } votes.Remove(currentVote); currentVote.Direction = direction; currentVote.Created = DateTime.UtcNow; votes.Add(currentVote); } else { votes.Add(new Vote { Direction = direction, Quote = this, Voter = user }); } return this; } public virtual VoteDirection? VotedFor(User user) { var vote = Votes.Where(v => v.Voter == user).SingleOrDefault(); if (vote == null) { return null; } return vote.Direction; } public virtual int UpVotes { get { return Votes.Count(vote => vote.Direction == VoteDirection.Up); } } public virtual int DownVotes { get { return Votes.Count(vote => vote.Direction == VoteDirection.Down); } } public virtual int Score { get { return Votes.Sum(vote => (int)vote); } } public virtual QuoteDto ToDto() { return new QuoteDto { Id = Id, Text = Text, Game = Game.ToDto(), Created = Created, Categories = Categories.Select(category => category.ToDto()), TotalVotes = Votes.Count(), UpVotes = UpVotes, DownVotes = DownVotes, Score = Score }; } #region nested types public class GameCriterionHandler : CriterionHandler { protected override Func HandleInteger(int value) { return quote => quote.Game.Id == value; } } #endregion } public class QuoteDto { public int Id { get; set; } public string Text { get; set; } public GameDto Game { get; set; } public DateTime Created { get; set; } public IEnumerable Categories { get; set; } public int TotalVotes { get; set; } public int UpVotes { get; set; } public int DownVotes { get; set; } public int Score { get; set; } } public static class QuoteExtensions { private static readonly Regex urlFriendlyRegex = new Regex(@"[^A-Za-z0-9_-]"); public static string GetUrlFriendlyText(this Quote quote) { var text = urlFriendlyRegex.Replace(quote.Text.Replace(" ", "_").Replace("\n", ""), ""); return text.Substring(0, Math.Min(text.Length, 50)); } public static string GetHumanReadableTimeSinceCreated(this Quote quote) { var timespan = DateTime.UtcNow.Subtract(quote.Created); if (timespan.TotalDays >= 365) { var years = (int)Math.Round(timespan.TotalDays / 365); return years == 1 ? "1 year ago" : years + " years ago"; } if (timespan.TotalDays >= 50) { var months = (int)Math.Round(timespan.TotalDays / 30); return months == 1 ? "1 month ago" : months + " months ago"; } if (timespan.TotalDays >= 10) { var weeks = (int)Math.Round(timespan.TotalDays / 7); return weeks == 1 ? "1 week ago" : weeks + " weeks ago"; } if (timespan.TotalDays >= 1) { return (int)timespan.TotalDays == 1 ? "1 day ago" : (int)timespan.TotalDays + " days ago"; } if (timespan.TotalMinutes >= 90) { return (int)timespan.TotalHours == 1 ? "1 hour ago" : (int)timespan.TotalHours + " hours ago"; } if (timespan.TotalSeconds >= 90) { return (int)timespan.TotalMinutes == 1 ? "1 minute ago" : (int)timespan.TotalMinutes + " minutes ago"; } return (int)timespan.TotalSeconds == 1 ? "1 second ago" : (int)timespan.TotalSeconds + " seconds ago"; } } }