Beispiel #1
0
        /// <summary>
        /// Partition a vote by line, but carry any task on parent lines down
        /// to child lines.
        /// </summary>
        /// <param name="lines">The lines of the vote.</param>
        /// <param name="author">The author of the vote, for use in determining
        /// valid referrals.</param>
        /// <returns>Returns a list of partitioned vote lines.</returns>
        private List <string> PartitionByLineTask(IEnumerable <string> lines, string author)
        {
            List <string> partitions    = new List <string>();
            List <string> referralVotes = new List <string>();
            string        parentTask    = string.Empty;

            foreach (string line in lines)
            {
                // If someone copy/pasted a vote with a referral at the top (eg: self-named plan),
                // skip the copy/pasted section.
                if (referralVotes.Any())
                {
                    if (Agnostic.StringComparer.Equals(line, referralVotes.First()))
                    {
                        referralVotes = referralVotes.Skip(1).ToList();
                        continue;
                    }

                    referralVotes.Clear();
                }

                referralVotes = VoteCounter.GetVotesFromReference(line, author);

                if (referralVotes.Any())
                {
                    partitions.AddRange(referralVotes);

                    if (Agnostic.StringComparer.Equals(line, referralVotes.First()))
                    {
                        referralVotes = referralVotes.Skip(1).ToList();
                        continue;
                    }
                }
                else
                {
                    string taskedLine = line;

                    if (string.IsNullOrEmpty(VoteString.GetVotePrefix(line)))
                    {
                        parentTask = VoteString.GetVoteTask(line);
                    }
                    else if (string.IsNullOrEmpty(VoteString.GetVoteTask(line)))
                    {
                        taskedLine = VoteString.ModifyVoteLine(line, task: parentTask);
                    }

                    partitions.Add(taskedLine + "\r\n");
                }
            }

            return(partitions);
        }
Beispiel #2
0
        /// <summary>
        /// If all sub-lines of a provided group of lines are indented (have a prefix),
        /// then 'promote' them up a tier (remove one level of the prefix) while discarding
        /// the initial line.
        /// </summary>
        /// <param name="lines">A list of strings to examine/promote.</param>
        /// <returns>Returns the strings without the initial line, and with the
        /// remaining lines reduced by one indent level.</returns>
        private static IEnumerable <string> PromoteLines(IEnumerable <string> lines)
        {
            if (lines == null)
            {
                throw new ArgumentNullException(nameof(lines));
            }

            var remainder = lines.Skip(1);

            if (remainder.All(l => VoteString.GetVotePrefix(l).Length > 0))
            {
                return(remainder.Select(l => l.Substring(1).Trim()));
            }

            return(remainder);
        }
Beispiel #3
0
        /// <summary>
        /// Gets a list of all full-vote plans (of which there will only be one, if found).
        /// </summary>
        /// <param name="post">The post to extract plans from.</param>
        /// <returns>Returns a list of plans (which are lists of vote lines).</returns>
        private List <List <string> > GetAllFullPostPlans(PostComponents post)
        {
            List <List <string> > results = new List <List <string> >();

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

                // If the vote has any plans with content in them, we can't make this a full-post plan.
                if (!voteBlocks.Any(b => b.Count() > 1 && VoteString.GetPlanName(b.Key) != null))
                {
                    // The post must have more than one line to count for a plan label.
                    if (post.VoteLines.Count > 1)
                    {
                        var firstLine = post.VoteLines.First();

                        string planname = VoteString.GetPlanName(firstLine);

                        if (planname != null)
                        {
                            // If it's named after a user, it must be the post author.  Otherwise, anything is fine.
                            if (VoteCounter.ReferenceVoters.Contains(planname, Agnostic.StringComparer))
                            {
                                if (Agnostic.StringComparer.Equals(planname, post.Author))
                                {
                                    results.Add(post.VoteLines);
                                }
                            }
                            else
                            {
                                results.Add(post.VoteLines);
                            }
                        }
                    }
                }
            }

            return(results);
        }
Beispiel #4
0
        /// <summary>
        /// Gets a list of all plans within the post that have defined content (child lines).
        /// </summary>
        /// <param name="post">The post to extract plans from.</param>
        /// <returns>Returns a list of plans (which are lists of vote lines).</returns>
        private List <List <string> > GetAllPlansWithContent(PostComponents post)
        {
            List <List <string> > results = new List <List <string> >();

            results.AddRange(post.BasePlans.Select(a => a.ToList()));

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

                foreach (var block in voteBlocks)
                {
                    if (block.Count() > 1)
                    {
                        string planname = VoteString.GetPlanName(block.Key);

                        if (planname != null)
                        {
                            // Add a named vote that is named after a user only if it matches the post author's name.
                            if (VoteCounter.ReferenceVoters.Contains(planname, Agnostic.StringComparer))
                            {
                                if (Agnostic.StringComparer.Equals(planname, post.Author))
                                {
                                    results.Add(block.ToList());
                                }
                            }
                            else
                            {
                                // If it's not named after a user, add it normally.
                                results.Add(block.ToList());
                            }
                        }
                    }
                }
            }

            return(results);
        }
Beispiel #5
0
        /// <summary>
        /// Gets a list of all full-vote plans (of which there will only be one, if found).
        /// </summary>
        /// <param name="post">The post to extract plans from.</param>
        /// <returns>Returns a list of plans (which are lists of vote lines).</returns>
        private List <List <string> > GetAllOneLinePlans(PostComponents post)
        {
            List <List <string> > results = new List <List <string> >();

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

                foreach (var block in voteBlocks)
                {
                    if (block.Count() == 1)
                    {
                        string planname = VoteString.GetPlanName(block.Key);

                        if (planname != null)
                        {
                            if (VoteCounter.ReferenceVoters.Contains(planname, Agnostic.StringComparer))
                            {
                                if (Agnostic.StringComparer.Equals(planname, post.Author))
                                {
                                    results.Add(block.ToList());
                                }
                            }
                            else
                            {
                                results.Add(block.ToList());
                            }
                        }
                    }
                }
            }

            return(results);
        }
Beispiel #6
0
        /// <summary>
        /// Get the lines of the vote that we will be processing out of the post.
        /// Only take the .VoteLines, and condense any instances of known plans
        /// to just a reference to the plan name.
        /// </summary>
        /// <param name="post">The post we're getting the vote from.</param>
        /// <returns>Returns the vote with plans compressed.</returns>
        public List <string> GetWorkingVote(PostComponents post)
        {
            List <string> vote = new List <string>();

            if (post == null || !post.IsVote)
            {
                return(vote);
            }

            // First determine if any base plans are copies of an original definition, or being defined in this post.
            // If they're just copies, then embed them in the working vote.

            if (post.BasePlans.Any())
            {
                var    voters    = VoteCounter.GetVotersCollection(VoteType.Plan);
                bool   checkPlan = true;
                string planName;

                foreach (var bPlan in post.BasePlans)
                {
                    planName = VoteString.GetMarkedPlanName(bPlan.Key);
                    if (planName == null)
                    {
                        continue;
                    }

                    // As long as we keep finding base plans that are defined in this post, keep skipping.
                    if (checkPlan)
                    {
                        if (VoteCounter.HasPlan(planName) && voters[planName] == post.ID)
                        {
                            continue;
                        }
                    }

                    checkPlan = false;

                    // If we reach here, any further plans are copy/pastes of defined plans, and should
                    // have the key added to the working vote.
                    vote.Add(bPlan.Key);
                }
            }

            // Then make sure there are actual vote lines to process.
            if (!post.VoteLines.Any())
            {
                return(vote);
            }

            // Then check if the *entire post* should be treated as a complete plan.
            string postPlanName = VoteString.GetPlanName(post.VoteLines.First());

            if (postPlanName != null && VoteCounter.ReferencePlans.ContainsKey(postPlanName) &&
                VoteCounter.ReferencePlans[postPlanName].Skip(1).SequenceEqual(post.VoteLines.Skip(1), Agnostic.StringComparer))
            {
                // Replace known plans with just the plan key.  They'll be expanded later.
                vote.Add(post.VoteLines.First());
            }
            else
            {
                // If the entire post isn't an auto-plan, break it down into blocks.

                // Break the remainder of the vote into blocks so that we can compare vs auto-plans.
                // Group blocks based on parent vote lines (no prefix).
                // Key for each block is the parent vote line.
                var voteBlocks = post.VoteLines.GroupAdjacentToPreviousKey(
                    (s) => string.IsNullOrEmpty(VoteString.GetVotePrefix(s)),
                    (s) => s,
                    (s) => s);


                foreach (var block in voteBlocks)
                {
                    // Multi-line blocks might be a plan.  Check.
                    if (block.Count() > 1)
                    {
                        // See if the block key marks a known plan.
                        string planName = VoteString.GetPlanName(block.Key);

                        if (planName != null && VoteCounter.ReferencePlans.ContainsKey(planName) &&
                            VoteCounter.ReferencePlans[planName].Skip(1).SequenceEqual(block.Skip(1), Agnostic.StringComparer))
                        {
                            // Replace known plans with just the plan key.  They'll be expanded later.
                            vote.Add(block.Key);
                        }
                        else
                        {
                            // If it's not a known plan, pass everything through.
                            vote.AddRange(block);
                        }
                    }
                    else
                    {
                        // Single lines can be added normally
                        vote.AddRange(block);
                        //vote.Add(block.Key);
                    }
                }
            }

            return(vote);
        }
Beispiel #7
0
        /// <summary>
        /// Partition the provided vote into individual partitions, by block.
        /// Referral votes are added as their own partitioned form.
        /// </summary>
        /// <param name="lines">The lines of a vote.</param>
        /// <param name="author">The author of the post.</param>
        /// <returns>Returns a the vote partitioned by block.</returns>
        private List <string> PartitionByBlock(IEnumerable <string> lines, string author)
        {
            List <string> partitions    = new List <string>();
            List <string> referralVotes = new List <string>();
            StringBuilder sb            = new StringBuilder();

            foreach (string line in lines)
            {
                // If someone copy/pasted a vote with a referral at the top (eg: self-named plan),
                // skip the copy/pasted section.
                if (referralVotes.Any())
                {
                    if (Agnostic.StringComparer.Equals(line, referralVotes.First()))
                    {
                        referralVotes = referralVotes.Skip(1).ToList();
                        continue;
                    }

                    referralVotes.Clear();
                }

                referralVotes = VoteCounter.GetVotesFromReference(line, author);

                if (referralVotes.Any())
                {
                    if (sb.Length > 0)
                    {
                        partitions.Add(sb.ToString());
                        sb.Clear();
                    }

                    partitions.AddRange(referralVotes);

                    referralVotes = referralVotes.SelectMany(a => a.GetStringLines()).ToList();
                    if (Agnostic.StringComparer.Equals(line, referralVotes.First()))
                    {
                        referralVotes = referralVotes.Skip(1).ToList();
                        continue;
                    }
                }
                else
                {
                    string prefix = VoteString.GetVotePrefix(line);

                    // If we encountered a new top-level vote line, store any existing stringbuilder contents.
                    if (string.IsNullOrEmpty(prefix) && sb.Length > 0)
                    {
                        partitions.Add(sb.ToString());
                        sb.Clear();
                    }

                    sb.AppendLine(line);
                }
            }

            if (sb.Length > 0)
            {
                partitions.Add(sb.ToString());
            }

            return(partitions);
        }