示例#1
0
        /// <summary>
        /// Given a group of votes (grouped by task), create and return
        /// a list of VoteNodes that collapse together votes that are 
        /// sub-votes of each other.
        /// </summary>
        /// <param name="taskGroup">A set of votes with the same task value.</param>
        /// <returns>Returns a list of VoteNodes that collapse similar votes.</returns>
        public static IEnumerable<VoteNode> GetVoteNodes(IGrouping<string, KeyValuePair<string, HashSet<string>>> taskGroup)
        {
            var groupByFirstLine = taskGroup.GroupBy(v => v.Key.GetFirstLine(), Agnostic.StringComparer);

            List<VoteNode> nodeList = new List<VoteNode>();
            VoteNode parent;

            foreach (var voteGroup in groupByFirstLine)
            {
                parent = null;

                if (voteGroup.Count() == 1)
                {
                    string planname = VoteString.GetPlanName(voteGroup.Key);
                    if (planname != null && VoteCounter.Instance.HasPlan(planname))
                    {
                        var vote = voteGroup.First();
                        parent = new VoteNode(vote.Key, vote.Value);
                        nodeList.Add(parent);
                        continue;
                    }
                }

                foreach (var vote in voteGroup)
                {
                    var lines = vote.Key.GetStringLines();

                    if (parent == null)
                    {
                        var voters = lines.Count == 1 ? vote.Value : null;
                        parent = new VoteNode(lines[0], voters);
                    }

                    if (lines.Count == 1)
                    {
                        parent.AddVoters(vote.Value);
                    }
                    else if (lines.Count == 2 && !string.IsNullOrEmpty(VoteString.GetVotePrefix(lines[1])))
                    {
                        parent.AddChild(lines[1], vote.Value);
                    }
                    else
                    {
                        parent.AddChild(vote.Key, vote.Value);
                    }
                }

                if (parent != null)
                {
                    nodeList.Add(parent);
                }
            }

            return nodeList.OrderByDescending(v => v.VoterCount);
        }
示例#2
0
        /// <summary>
        /// Add the provided vote to the output in compact format.
        /// </summary>
        /// <param name="vote">The vote to add.</param>
        private void AddCompactVote(KeyValuePair <string, HashSet <string> > vote)
        {
            List <string> voteLines = vote.Key.GetStringLines();

            if (voteLines.Count == 0)
            {
                return;
            }

            int    userCount       = VoteInfo.CountVote(vote);
            string userCountMarker = userCount.ToString();

            // Single-line votes are always shown.
            if (voteLines.Count == 1)
            {
                sb.AppendLine(VoteString.ModifyVoteLine(voteLines.First(), marker: userCountMarker));
                return;
            }

            // Two-line votes can be shown if the second line is a sub-vote.
            if (voteLines.Count == 2 && !string.IsNullOrEmpty(VoteString.GetVotePrefix(voteLines.Last())))
            {
                sb.AppendLine(VoteString.ModifyVoteLine(voteLines.First(), marker: userCountMarker));
                sb.AppendLine(VoteString.ModifyVoteLine(voteLines.Last(), marker: userCountMarker));
                return;
            }


            // Longer votes get condensed down to a link to the original post (and named after the first voter)
            string firstVoter = VoteInfo.GetFirstVoter(vote.Value);

            string task = VoteString.GetVoteTask(vote.Key);

            sb.Append($"[{userCountMarker}]");
            if (!string.IsNullOrEmpty(task))
            {
                sb.Append($"[{task}]");
            }

            string link;

            if (firstVoter.StartsWith(StringUtility.PlanNameMarker, StringComparison.Ordinal))
            {
                link = VoteInfo.GetVoterUrl(firstVoter, VoteType.Plan);
            }
            else
            {
                link = VoteInfo.GetVoterUrl(firstVoter, VoteType.Vote);
            }

            sb.Append($" Plan: {firstVoter} — {link}\r\n");
        }
示例#3
0
        public void GetVotePrefixTest()
        {
            string line1 = "[x] Vote for stuff";
            string line2 = "-[x] Vote for stuff";
            string line3 = "---[x] Vote for stuff";
            string line4 = "- [x] Vote for stuff";
            string line5 = "- - -[x] Vote for stuff";

            Assert.AreEqual("", VoteString.GetVotePrefix(line1));
            Assert.AreEqual("-", VoteString.GetVotePrefix(line2));
            Assert.AreEqual("---", VoteString.GetVotePrefix(line3));
            Assert.AreEqual("-", VoteString.GetVotePrefix(line4));
            Assert.AreEqual("---", VoteString.GetVotePrefix(line5));
        }
示例#4
0
        private bool HasChildLines(string vote)
        {
            if (string.IsNullOrEmpty(vote))
            {
                return(false);
            }

            var voteLines = vote.GetStringLines();

            if (voteLines.Count < 2)
            {
                return(false);
            }

            var topIndent = VoteString.GetVotePrefix(voteLines.First()).Length;

            var voteLinesPlus = voteLines.Skip(1);

            return(voteLinesPlus.All(a => VoteString.GetVotePrefix(a).Length > topIndent));
        }
示例#5
0
        /// <summary>
        /// Takes the full vote string list of the vote and breaks it
        /// into base plans, regular vote lines, and ranked vote lines.
        /// Store in the local object properties.
        /// </summary>
        /// <param name="voteStrings">The list of all the lines in the vote post.</param>
        private void SeparateVoteStrings(List <string> voteStrings)
        {
            BasePlans = new List <IGrouping <string, string> >();
            List <string> consolidatedLines = new List <string>();

            // Group blocks based on parent vote lines (no prefix).
            // Key for each block is the parent vote line.
            var voteBlocks = voteStrings.GroupAdjacentToPreviousKey(
                (s) => string.IsNullOrEmpty(VoteString.GetVotePrefix(s)),
                (s) => s,
                (s) => s);

            bool addBasePlans = true;

            foreach (var block in voteBlocks)
            {
                if (addBasePlans)
                {
                    if (block.Count() > 1)
                    {
                        string planName = VoteString.GetPlanName(block.Key, basePlan: true);

                        if (planName != null && !VoteCounter.Instance.ReferenceVoters.Contains(planName, Agnostic.StringComparer))
                        {
                            BasePlans.Add(block);
                            continue;
                        }
                    }
                }
                addBasePlans = false;

                consolidatedLines.AddRange(block.ToList());
            }

            RankLines = new List <string>();
            VoteLines = new List <string>();

            foreach (var line in consolidatedLines)
            {
                if (VoteString.IsRankedVote(line))
                {
                    RankLines.Add(line);
                }
                else
                {
                    VoteLines.Add(line);
                }
            }

            // If we have ranked vote options, make sure we don't have duplicate entries,
            // or the same option voted on different ranks.
            if (RankLines.Count > 0)
            {
                var groupRankLinesMulti = RankLines.GroupBy(line => VoteString.GetVoteContent(line), Agnostic.StringComparer)
                                          .Where(group => group.Count() > 1);

                // If there are any, remove all but the top ranked option.
                foreach (var lineGroup in groupRankLinesMulti)
                {
                    var topOption    = lineGroup.MinObject(a => VoteString.GetVoteMarker(a));
                    var otherOptions = lineGroup.Where(a => a != topOption).ToList();

                    foreach (string otherOption in otherOptions)
                    {
                        RankLines.Remove(otherOption);
                    }
                }
            }
        }
示例#6
0
        /// <summary>
        /// Partitions the child components of a vote into separate vote entries, passing
        /// the voters into those child entries and removing the original.
        /// </summary>
        /// <param name="vote">The vote to partition.</param>
        /// <param name="voteType">The type of vote.</param>
        /// <returns>Returns true if the process was completed, or false otherwise.</returns>
        public bool PartitionChildren(string vote, VoteType voteType)
        {
            if (string.IsNullOrEmpty(vote))
            {
                return(false);
            }

            // No point in partitioning rank votes
            if (voteType == VoteType.Rank)
            {
                return(false);
            }

            // Make sure the provided vote exists
            string voteKey = GetVoteKey(vote, voteType);
            var    votes   = GetVotesCollection(voteType);

            if (votes.ContainsKey(voteKey) == false)
            {
                return(false);
            }

            // Construct the new votes that the vote is being partitioned into.
            var voteLines = vote.GetStringLines();

            if (voteLines.Count < 2)
            {
                return(false);
            }

            var afterVoteLines = voteLines.Skip(1);

            int indentCount = afterVoteLines.Min(a => VoteString.GetVotePrefix(a).Length);

            var promotedVoteLines = afterVoteLines.Select(a => a.Substring(indentCount)).ToList();

            var partitionedVotes = VoteConstructor.PartitionVoteStrings(promotedVoteLines, Quest, PartitionMode.ByBlock);

            HashSet <string> addedVotes = new HashSet <string>();

            var  voters       = votes[voteKey];
            bool votesChanged = false;

            foreach (var v in partitionedVotes)
            {
                var key = GetVoteKey(v, voteType);

                if (!votes.ContainsKey(key))
                {
                    votes[key]   = new HashSet <string>(StringComparer.OrdinalIgnoreCase);
                    votesChanged = true;
                }

                votes[key].UnionWith(voters);

                addedVotes.Add(key);
            }

            UndoBuffer.Push(new UndoAction(UndoActionType.PartitionChildren, voteType, GetVotersCollection(voteType), addedVotes, voteKey, voters));

            Delete(vote, voteType, true);

            if (votesChanged)
            {
                OnPropertyChanged("Votes");
            }

            OnPropertyChanged("VoteCounter");

            return(true);
        }