public TransferActionsResult ValidateAndApplyTransfers(SeasonState seasonState, TransferActions transferActions)
        {
            if (seasonState == null) throw new ArgumentNullException("seasonState");
            if (transferActions == null) throw new ArgumentNullException("transferActions");

            var transferValidity = _transferValidator.ValidateTransfers(seasonState, transferActions);
            if(transferValidity != TransferValidity.Valid)
            {
                throw new InvalidTransferException(transferValidity);
            }

            _transferActioner.VerboseLoggingEnabled = true;
            var result = _transferActioner.ApplyTransfers(seasonState, transferActions);

            return result;
        }
        public TransferValidity ValidateTransfers(SeasonState seasonState, TransferActions transferActions)
        {
            if (seasonState.Gameweek == 1 && transferActions.Transfers.Any())
            {
                return TransferValidity.NoTransfersAllowedInFirstGameweek;
            }

            foreach (var transfer in transferActions.Transfers)
            {
                var transferValidity = CheckTransferValidity(transfer, seasonState.CurrentTeam);
                if (transferValidity != TransferValidity.Valid)
                {
                    return transferValidity;
                }
            }

            if (transferActions.Transfers.DistinctBy(t => t.PlayerIn.Id).Count() != transferActions.Transfers.Count)
            {
                return TransferValidity.PlayerTransferredInMultipleTimes;
            }

            if (transferActions.Transfers.DistinctBy(t => t.PlayerOut.Id).Count() != transferActions.Transfers.Count)
            {
                return TransferValidity.PlayerTransferredOutMultipleTimes;
            }

            var wildcardValidity = CheckWildcardValidity(seasonState, transferActions);
            if(wildcardValidity != TransferValidity.Valid)
            {
                return wildcardValidity;
            }

            if(!TeamCanAffordTransfers(seasonState, transferActions))
            {
                return TransferValidity.NotEnoughMoney;
            }

            var teamVailidity = CheckResultingTeamValidity(seasonState, transferActions);
            if(teamVailidity != TeamValidationStatus.Valid)
            {
                return TransferValidity.LeavesTeamInInvalidState;
            }

            return TransferValidity.Valid;
        }
        public TransferActionsResult ApplyTransfers(SeasonState seasonState, TransferActions transferActions)
        {
            var actionResults = new TransferActionsResult();

            if (VerboseLoggingEnabled)
            {
                _logger.Log(Tag.Transfers, string.Format("Applying gameweek {0} transfers", seasonState.Gameweek), true);
            }

            //set transferred in player cost
            foreach (var transfer in transferActions.Transfers)
            {
                seasonState.CurrentTeam = ProcessTransfer(transfer, seasonState.CurrentTeam);
            }

            seasonState.CurrentTeam.EnsureValidCaptains();

            actionResults.TotalTransfersMade = transferActions.Transfers.Count;

            actionResults.PenalisedTransfersMade = Math.Max(transferActions.Transfers.Count - seasonState.FreeTransfers, 0);
            seasonState.Money = CommonTransferFunctions.CalculateUpdatedTeamMoney(transferActions.Transfers, seasonState.Money);

            if (VerboseLoggingEnabled)
            {
                _logger.Log(Tag.Transfers, string.Format("Total transfers made: {0}", actionResults.TotalTransfersMade));
                _logger.Log(Tag.Transfers, string.Format("Penalised transfers made: {0}", actionResults.PenalisedTransfersMade));
                _logger.Log(Tag.Transfers, string.Format("Updated money: {0}", seasonState.Money.ToMoney()));
            }

            UpdateFreeTransfers(transferActions, seasonState);

            actionResults.UpdatedSeasonState = seasonState;

            actionResults = ApplyWildcards(seasonState, transferActions, actionResults);

            return actionResults;
        }
        private static void UpdateFreeTransfers(TransferActions actions, SeasonState seasonState)
        {
            //transfers carry over if you're playing wildcard
            if (!actions.PlayTransferWindowWildcard && !actions.PlayStandardWildcard)
            {
                //deduct the transfers made
                seasonState.FreeTransfers -= actions.Transfers.Count;

                //you can never have negative free transfers
                seasonState.FreeTransfers = Math.Max(seasonState.FreeTransfers, 0);

                //add on one transfer for new game week
                seasonState.FreeTransfers++;

                //add one another free transfer if you didn't make any this week
                if (actions.Transfers.Count == 0)
                {
                    seasonState.FreeTransfers++;
                }

                //you can only ever have a max of two free transfers
                seasonState.FreeTransfers = Math.Min(seasonState.FreeTransfers, 2);
            }
        }
 private bool TeamCanAffordTransfers(SeasonState seasonState, TransferActions transferActions)
 {
     var newMoneyValue = CommonTransferFunctions.CalculateUpdatedTeamMoney(transferActions.Transfers,
                                                                           seasonState.Money);
     return newMoneyValue >= 0;
 }
        private TransferValidity CheckWildcardValidity(SeasonState seasonState, TransferActions transferActions)
        {
            if (transferActions.PlayStandardWildcard && seasonState.StandardWildCardPlayed)
            {
               return TransferValidity.WildcardPlayedTwice;
            }

            if (transferActions.PlayTransferWindowWildcard)
            {
                if (seasonState.TransferWindowWildcardPlayed)
                {
                    return TransferValidity.WildcardPlayedTwice;
                }

                var insideTransferWindowWildcardPeriod = IsInsideTransferWindow(seasonState.Gameweek);
                if (!insideTransferWindowWildcardPeriod)
                {
                    return TransferValidity.WildcardPlayedOutsideWindow;
                }
            }

            return TransferValidity.Valid;
        }
        private TeamValidationStatus CheckResultingTeamValidity(SeasonState seasonState, TransferActions transferActions)
        {
            var clonedSeasonState = seasonState.ShallowClone();

            _transferActioner.VerboseLoggingEnabled = false;
            var result = _transferActioner.ApplyTransfers(clonedSeasonState, transferActions);
            return result.UpdatedSeasonState.CurrentTeam.Validity;
        }
        public void transfer_actions_and_results_are_included_in_gameweek_results()
        {
            //Arrange

            //set up 2 gameweeks as first has no transfers
            _allPlayers = TeamCreationHelper.CreatePlayersWithPastFixtures(2);
            _playerServiceMock.Setup(x => x.GetAllPlayers()).Returns(_allPlayers);

            var transfers = new TransferActions{Transfers = new List<Transfer>{new Transfer(), new Transfer()}};
            _strategyMock.Setup(x => x.MakeTransfers(It.IsAny<SeasonState>())).Returns(transfers);

            //Act
            var result = _seasonSimulator.PerformSimulation(_strategyMock.Object, _simulationOptions);

            //Assert
            Assert.That(result.GameweekResults[1].TransferActions, Is.EqualTo(transfers));
            Assert.That(result.GameweekResults[1].TransferResults, Is.Not.Null);
        }
        public void strategy_not_asked_to_make_transfer_decision_for_first_gameweek()
        {
            //Arrange
            var decision = new TransferActions();
            _strategyMock.Setup(x => x.MakeTransfers(It.Is<SeasonState>(s => s.Gameweek == 1))).Returns(decision);

            //Act
            _seasonSimulator.PerformSimulation(_strategyMock.Object, _simulationOptions);

            //Assert
            _strategyMock.Verify(x => x.MakeTransfers(It.Is<SeasonState>(s => s.Gameweek == 1)), Times.Never());
        }
        public void SetUp()
        {
            _seasonState = new SeasonState
            {
                Gameweek = 2,
                FreeTransfers = 1,
                CurrentTeam = TeamCreationHelper.CreateTestTeam(4, 3, 3, Position.Defender,
                                                                                        Position.Midfielder,
                                                                                        Position.Midfielder)

            };
            _transferActions = new TransferActions();

            _transferValidatorMock = new Mock<ITransferValidator>();
            _transferActionerMock = new Mock<ITransferActioner>();

            _decisionActioner = new DecisionActioner(_transferActionerMock.Object, _transferValidatorMock.Object);

            _allPlayers = new List<Player>();
        }
        public void can_not_transfer_the_same_player_in_multiple_times_in_same_gameweek()
        {
            // Arrange
            var playerIn = _seasonState.AllPlayers.First();
            _transferActions = new TransferActions
                                   {
                                       Transfers = new List<Transfer>
                                                       {
                                                           new Transfer
                                                               {
                                                                   PlayerIn = playerIn,
                                                                   PlayerOut = _seasonState.CurrentTeam.Players.Where(p => p.Position == playerIn.Position).ElementAt(0)
                                                               },
                                                           new Transfer
                                                               {
                                                                   PlayerIn = playerIn,
                                                                   PlayerOut = _seasonState.CurrentTeam.Players.Where(p => p.Position == playerIn.Position).ElementAt(1)
                                                               }
                                                       }
                                   };

            //Act
            var transferValidity = _transferValidator.ValidateTransfers(_seasonState, _transferActions);

            //Assert
            Assert.That(transferValidity, Is.EqualTo(TransferValidity.PlayerTransferredInMultipleTimes));
        }
        public void SetUp()
        {
            _seasonState = new SeasonState
                               {
                                   CurrentTeam = TeamCreationHelper.CreateTestTeam(),
                                   AllPlayers = TeamCreationHelper.CreatePlayerList(10,10,10,10, startingId: 100),
                                   Gameweek = 2
                               };
            _transferActions = new TransferActions();

            _transferActionerMock = new Mock<ITransferActioner>();
            _transferActionerMock.Setup(x => x.ApplyTransfers(It.IsAny<SeasonState>(), It.IsAny<TransferActions>())).
                Returns((SeasonState s, TransferActions t) => new TransferActionsResult{UpdatedSeasonState = s});

            _configSettingsMock = new Mock<IConfigurationSettings>();
            _transferValidator = new TransferValidator(_configSettingsMock.Object, _transferActionerMock.Object);
        }
        public void can_not_transfer_the_same_player_out_multiple_times_in_same_gameweek()
        {
            // Arrange
            var playerOut = _seasonState.CurrentTeam.Players.First();
            _transferActions = new TransferActions
            {
                Transfers = new List<Transfer>
                                                       {
                                                           new Transfer
                                                               {
                                                                   PlayerIn = _seasonState.AllPlayers[0],
                                                                   PlayerOut = playerOut
                                                               },
                                                           new Transfer
                                                               {
                                                                   PlayerIn = _seasonState.AllPlayers[1],
                                                                   PlayerOut =playerOut
                                                               }
                                                       }
            };

            //Act
            var transferValidity = _transferValidator.ValidateTransfers(_seasonState, _transferActions);

            //Assert
            Assert.That(transferValidity, Is.EqualTo(TransferValidity.PlayerTransferredOutMultipleTimes));
        }
        private TransferActionsResult ApplyWildcards(SeasonState seasonState, TransferActions actions, TransferActionsResult result)
        {
            if (actions.PlayStandardWildcard)
            {
                if (VerboseLoggingEnabled)
                {
                    _logger.Log(Tag.Transfers, "Standard wildcard played", true);
                }
                seasonState.StandardWildCardPlayed = true;
                result.PenalisedTransfersMade = 0;
            }
            else if (actions.PlayTransferWindowWildcard)
            {
                if (VerboseLoggingEnabled)
                {
                    _logger.Log(Tag.Transfers, "Transfer window wildcard played", true);
                }
                seasonState.TransferWindowWildcardPlayed = true;
                result.PenalisedTransfersMade = 0;
            }

            return result;
        }
        private StrategyDecisionsResult ProcessStrategyDecisions(SeasonState seasonState, IStrategy strategy)
        {
            var updatedSeasonState = seasonState;

            var transferActions = new TransferActions();
            var transferResults = new TransferActionsResult();

            //no transfers in first gameweek
            if (seasonState.Gameweek > 1)
            {
                transferActions = strategy.MakeTransfers(updatedSeasonState);
                transferResults = _decisionActioner.ValidateAndApplyTransfers(updatedSeasonState, transferActions);
                updatedSeasonState = transferResults.UpdatedSeasonState;
            }

            var selectedTeamForGameweek = strategy.PickGameweekTeam(updatedSeasonState);
            updatedSeasonState = _decisionActioner.ValidateAndApplyGameweekTeamSelection(updatedSeasonState, selectedTeamForGameweek);

            return new StrategyDecisionsResult
                   {
                       TransfersMade = transferActions,
                       TransferResults = transferResults,
                       UpdatedSeasonState = updatedSeasonState
                   };
        }