/// <summary>
        /// Set the solve state of some puzzle state records. In the course of setting the state, instantiate any state records that are missing on the server.
        /// </summary>
        /// <param name="context">The puzzle DB context</param>
        /// <param name="eventObj">The event we are querying from</param>
        /// <param name="puzzle">
        ///     The puzzle; if null, get all puzzles in the event.
        /// </param>
        /// <param name="team">
        ///     The team; if null, get all the teams in the event.
        /// </param>
        /// <param name="value">The solve time (null if unsolving)</param>
        /// <param name="author"></param>
        /// <returns>
        ///     A task that can be awaited for the solve/unsolve operation
        /// </returns>
        public static async Task SetSolveStateAsync(
            PuzzleServerContext context,
            Event eventObj,
            Puzzle puzzle,
            Team team,
            DateTime?value,
            PuzzleUser author = null)
        {
            IQueryable <PuzzleStatePerTeam> statesQ = PuzzleStateHelper
                                                      .GetFullReadWriteQuery(context, eventObj, puzzle, team, author);

            List <PuzzleStatePerTeam> states = await statesQ.ToListAsync();

            for (int i = 0; i < states.Count; i++)
            {
                // Only allow solved time to be modified if it is being marked as unsolved (set to null) or if it is being solved for the first time
                if (value == null || states[i].SolvedTime == null)
                {
                    // Unlock puzzles when solving them
                    if (value != null && states[i].UnlockedTime == null)
                    {
                        states[i].UnlockedTime = value;
                    }

                    states[i].SolvedTime = value;
                }
            }

            // Award hint coins
            if (value != null && puzzle != null && puzzle.HintCoinsForSolve != 0)
            {
                if (team != null)
                {
                    team.HintCoinCount += puzzle.HintCoinsForSolve;
                }
                else
                {
                    var allTeams = from Team curTeam in context.Teams
                                   where curTeam.Event == eventObj
                                   select curTeam;
                    foreach (Team curTeam in allTeams)
                    {
                        curTeam.HintCoinCount += puzzle.HintCoinsForSolve;
                    }
                }
            }

            await context.SaveChangesAsync();

            // if this puzzle got solved, look for others to unlock
            if (puzzle != null && value != null)
            {
                await UnlockAnyPuzzlesThatThisSolveUnlockedAsync(context,
                                                                 eventObj,
                                                                 puzzle,
                                                                 team,
                                                                 value.Value);
            }
        }
        /// <summary>
        /// Set the unlock state of some puzzle state records. In the course of setting the state, instantiate any state records that are missing on the server.
        /// </summary>
        /// <param name="context">The puzzle DB context</param>
        /// <param name="eventObj">The event we are querying from</param>
        /// <param name="puzzle">The puzzle; if null, get all puzzles in the event.</param>
        /// <param name="team">The team; if null, get all the teams in the event.</param>
        /// <param name="value">The unlock time (null if relocking)</param>
        /// <returns>A task that can be awaited for the unlock/lock operation</returns>
        public static async Task SetUnlockStateAsync(PuzzleServerContext context, Event eventObj, Puzzle puzzle, Team team, DateTime?value, PuzzleUser author = null)
        {
            IQueryable <PuzzleStatePerTeam> statesQ = PuzzleStateHelper.GetFullReadWriteQuery(context, eventObj, puzzle, team, author);
            List <PuzzleStatePerTeam>       states  = await statesQ.ToListAsync();

            for (int i = 0; i < states.Count; i++)
            {
                // Only allow unlock time to be modified if we were relocking it (setting it to null) or unlocking it for the first time
                if (value == null || states[i].UnlockedTime == null)
                {
                    states[i].UnlockedTime = value;
                }
            }
            await context.SaveChangesAsync();
        }
        /// <summary>
        /// Set the lockout expiry time of some puzzle state records. In the
        /// course of setting the state, instantiate any state records that are
        /// missing on the server.
        /// </summary>
        /// <param name="context">The puzzle DB context</param>
        /// <param name="eventObj">The event we are querying from</param>
        /// <param name="puzzle">
        ///     The puzzle; if null, get all puzzles in the event.
        /// </param>
        /// <param name="team">
        ///     The team; if null, get all the teams in the event.
        /// </param>
        /// <param name="value">The Lockout expiry time<param>
        /// <param name="author"></param>
        /// <returns>
        ///     A task that can be awaited for the lockout operation
        /// </returns>
        public static async Task SetLockoutExpiryTimeAsync(
            PuzzleServerContext context,
            Event eventObj,
            Puzzle puzzle,
            Team team,
            DateTime?value,
            PuzzleUser author = null)
        {
            IQueryable <PuzzleStatePerTeam> statesQ = PuzzleStateHelper
                                                      .GetFullReadWriteQuery(context, eventObj, puzzle, team, author);

            List <PuzzleStatePerTeam> states = await statesQ.ToListAsync();

            for (int i = 0; i < states.Count; i++)
            {
                states[i].LockoutExpiryTime = value;
            }

            await context.SaveChangesAsync();
        }
        /// <summary>
        /// Set the email only mode of some puzzle state records. In the course
        /// of setting the state, instantiate any state records that are
        /// missing on the server.
        /// </summary>
        /// <param name="context">The puzzle DB context</param>
        /// <param name="eventObj">The event we are querying from</param>
        /// <param name="puzzle">
        ///     The puzzle; if null, get all puzzles in the event.
        /// </param>
        /// <param name="team">
        ///     The team; if null, get all the teams in the event.
        /// </param>
        /// <param name="value">The new email only state for the puzzle</param>
        /// <param name="author"></param>
        /// <returns>
        ///     A task that can be awaited for the lockout operation
        /// </returns>
        public static async Task SetEmailOnlyModeAsync(
            PuzzleServerContext context,
            Event eventObj,
            Puzzle puzzle,
            Team team,
            bool value,
            PuzzleUser author = null)
        {
            IQueryable <PuzzleStatePerTeam> statesQ = PuzzleStateHelper
                                                      .GetFullReadWriteQuery(context, eventObj, puzzle, team, author);

            List <PuzzleStatePerTeam> states = await statesQ.ToListAsync();

            for (int i = 0; i < states.Count; i++)
            {
                states[i].IsEmailOnlyMode = value;
                if (value == true)
                {
                    states[i].WrongSubmissionCountBuffer += eventObj.MaxSubmissionCount;
                }
            }

            await context.SaveChangesAsync();
        }