public async Task <IActionResult> OnPostAsync(int?id, int?rating)
        {
            if (id == null)
            {
                return(NotFound());
            }
            Path = await _context.Paths.FindAsync(id);

            if (Path == null)
            {
                return(NotFound());
            }
            _ = await Path.AddCalculatedPropertiesAsync(_context);

            if (rating.HasValue)
            {
                if (rating > 0 && rating <= 5)
                {
                    _ = await Path.RegisterEventAsync(_context, EventType.UserRating, rating.ToString());
                }
            }
            // Now let's Apply a new rating to this Path
            _ = await Path.ApplyPathRatingAsyc(_context);

            RatingAcknowledged = true;
            RatingAccepted     = false;
            return(Page());
        }
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for
        // more details see https://aka.ms/RazorPagesCRUD.
        public async Task <IActionResult> OnPostAsync()
        {
            IdentityUser user = await _userManager.GetUserAsync(User);

            if (!ModelState.IsValid)
            {
                return(RedirectToPage("Group", new { Id = Group.Id }));
            }

            GameGroup UpdateGroup = await _context.GameGroups.FindAsync(Group.Id);

            if (UpdateGroup == null)
            {
                return(RedirectToPage("/error", new { errorMessage = "That's Odd! We weren't able to find that Group" }));
            }
            if (UpdateGroup.Owner != user.Email)
            {
                return(RedirectToPage("/error", new { errorMessage = "Sorry, Only the owner can manage a Group" }));
            }
            _context.Entry(UpdateGroup)
            .Collection(g => g.GameTeams)
            .Load();

            if (await TryUpdateModelAsync <GameGroup>(
                    UpdateGroup,
                    "Group", // Prefix for form value.
                    t => t.PathId))
            {
                UpdateGroup.GroupState = (int)GameGroup.GameGroupState.InPlay;
                UpdateGroup.Modified   = DateTime.Now;

                // go get the Path so we can set first step
                Path path = await _context.Paths.FindAsync(UpdateGroup.PathId);

                if (path == null)
                {
                    return(RedirectToPage("/error", new { errorMessage = "That's Very Odd! We were not able to find the Path for this Group" }));
                }

                // We will need that first step.
                _ = await path.AddCalculatedPropertiesAsync(_context);

                // Now we need to iterate through each Team and reset it.

                foreach (GameTeam Team in UpdateGroup.GameTeams)
                {
                    Team.CurrentStepId = path.FirstStepId;
                    Team.TeamType      = 0;
                    Team.BoardState    = (int)GameTeam.GameBoardState.WordSelect;
                    Team.StepNumber    = 1;
                    Team.Modified      = DateTime.Now;
                }
                await _context.SaveChangesAsync();

                return(RedirectToPage("Group", new { Id = UpdateGroup.Id, Message = String.Format("Group {0} has been Restarted!", UpdateGroup.Name) }));
            }
            return(Page());
        }
        public async Task <IActionResult> OnGetAsync(int?id)
        {
            if (id == null)
            {
                return(NotFound());
            }

            Path = await _context.Paths.FindAsync(id);

            if (Path == null)
            {
                return(NotFound());
            }
            _ = await Path.AddCalculatedPropertiesAsync(_context);

            // We have a 48 hour back off timer on rating a given path, to try and avoid rating abuse
            // To calculate this we need to find time of the the latest userRating
            RatingAccepted = false;
            DateTimeOffset?LatestUserRating = null;

            try
            {
                LatestUserRating = (await _context.PathStats
                                    .Where(s => s.PathId == Path.Id && s.EventType == (int)EventType.UserRating)
                                    .OrderByDescending(s => s.EventWritten)
                                    .FirstAsync()).EventWritten;
            }
            catch
            {
                // we assume this Path is not rated yet so let's accept a rating.
                RatingAccepted = true;
            }
            if (LatestUserRating.HasValue)
            {
                TimeSpan TimeSinceLastRated = (TimeSpan)(DateTime.Now - LatestUserRating);
                if (TimeSinceLastRated.TotalHours > 48)
                {
                    RatingAccepted = true;
                }
            }
            // To keep the score somewhat fresh we'll recalculate score on every 10 reads.
            if (Path.Reads % 10 == 0)
            {
                _ = await Path.ApplyPathRatingAsyc(_context);
            }
            RatingAcknowledged = false;
            return(Page());
        }
        public async Task OnGetAsync(SortBy SortOrder = SortBy.HighestRated)
        {
            var paths = from p in _context.Paths
                        select p;

            if (!string.IsNullOrEmpty(SearchString))
            {
                paths = paths.Where(s => (s.Name.Contains(SearchString) || s.Topics.Contains(SearchString)) && s.IsPublished == true && s.IsDeleted == false);
            }
            else
            {
                paths = paths.Where(s => s.IsPublished == true && s.IsDeleted == false);
            }

            switch (SortOrder)
            {
            case SortBy.HighestRated:
                paths = paths.OrderByDescending(p => p.ComputedRating);
                break;

            case SortBy.Newest:
                paths = paths.OrderByDescending(p => p.Created);
                break;

            case SortBy.Shortest:
                paths = paths.OrderBy(p => p.Length);
                break;

            case SortBy.Reads:
                paths = paths.OrderByDescending(p => p.Reads);
                break;

            default:
                paths = paths.OrderByDescending(p => p.ComputedRating);
                break;
            }

            OrderedBy = SortOrder;

            Paths = await paths.ToListAsync();

            foreach (Path Path in Paths)
            {
                _ = await Path.AddCalculatedPropertiesAsync(_context);
            }
        }
        public async Task <IActionResult> OnGetAsync(string name)
        {
            try
            {
                Path = await _context.Paths.Where(P => P.Name == name && P.IsPublished == true && P.IsDeleted == false).SingleAsync();

                if (Path == null)
                {
                    return(RedirectToPage("Index"));
                }
                // We need to find the first Step
                _ = await Path.AddCalculatedPropertiesAsync(_context);

                return(RedirectToPage("/Steps/Step", new { Id = Path.FirstStepId }));
            }
            catch
            {
                return(RedirectToPage("Index"));
            }
        }
        public async Task <IViewComponentResult> InvokeAsync(int GroupId, int TeamId)
        {
            List <PathNode> TeamSteps = new List <PathNode>();
            GameGroup       Group     = await _context.GameGroups.FindAsync(GroupId);

            GameTeam Team = await _context.GameTeams.FindAsync(TeamId);

            string BibleId = await GameTeam.GetValidBibleIdAsync(_context, null);

            Path Path = await _context.Paths.FindAsync(Group.PathId);

            _ = await Path.AddCalculatedPropertiesAsync(_context);

            if (Team.BoardState == (int)GameTeam.GameBoardState.StepSelect)
            {
                TeamSteps = await Team.GetTeamStepsAsync(_context, BibleId);
            }
            Team.Steps = TeamSteps;
            return(View(Team));
        }
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for
        // more details see https://aka.ms/RazorPagesCRUD.
        public async Task <IActionResult> OnPostAsync()
        {
            IdentityUser user = await _userManager.GetUserAsync(User);

            if (!ModelState.IsValid)
            {
                ViewData["PathSelectList"] = await GameGroup.GetPathSelectListAsync(_context);

                return(Page());
            }

            // Now let's create an empty group
            var emptyGroup = new GameGroup
            {
                Created    = DateTime.Now,
                Modified   = DateTime.Now,
                GroupState = (int)GameGroup.GameGroupState.Open,
                Owner      = user.Email
            };

            if (await TryUpdateModelAsync <GameGroup>(
                    emptyGroup,
                    "Group", // Prefix for form value.
                    g => g.Name, g => g.PathId))
            {
                _context.GameGroups.Add(emptyGroup);
                await _context.SaveChangesAsync();

                // go get the Path so we can set first step
                Path path = await _context.Paths.FindAsync(emptyGroup.PathId);

                if (path == null)
                {
                    return(RedirectToPage("/error", new { errorMessage = "That's Very Odd! We were not able to find the Path for this Group" }));
                }
                // We will need that first step.
                _ = await path.AddCalculatedPropertiesAsync(_context);

                // Now we need to parse our Teams and add/remove
                foreach (GameTeam Team in Teams)
                {
                    if (Team.Name != null)
                    {
                        if (Team.Name.Length > 0)
                        {
                            var emptyTeam = new GameTeam
                            {
                                CurrentStepId = path.FirstStepId,
                                TeamType      = 0,
                                BoardState    = (int)GameTeam.GameBoardState.WordSelect,
                                StepNumber    = 1,
                                Created       = DateTime.Now,
                                Modified      = DateTime.Now,
                            };
                            emptyTeam.Name  = Team.Name;
                            emptyTeam.Group = emptyGroup;
                            _context.GameTeams.Add(emptyTeam);
                        }
                    }
                }
                await _context.SaveChangesAsync();

                return(RedirectToPage("Group", new { Id = emptyGroup.Id, Message = String.Format("Group {0} successfully created...", emptyGroup.Name) }));
            }

            return(Page());
        }