/// <summary>
 /// Checks an interrupt condition, executing the given behaviour only if the condition returns False
 /// -Returns Success if the given behaviour returns Success and the condition returns False
 /// -Returns Running if the given behaviour returns Running and the condition returns False
 /// -Returns Failure if the given behaviour returns Failure or the condition returns True
 /// 
 /// Possibly not a good solution for interrupt style behaviour in the long run as it is very difficult to write
 /// conditions for interrupting without adding lots of state elsewhere to track when interrupts occur
 /// </summary>
 /// <param name="name">the name of the interruptible</param>
 /// <param name="behaviour"></param>
 /// <param name="interruptCondition"></param>
 /// <param name="onInterruptReturn"></param>
 public Interruptible(string name, BehaviourComponent behaviour, Conditional interruptCondition, BehaviourReturnCode onInterruptReturn)
 {
     Name = name;
     _behaviourComponent = behaviour;
     _interruptCondition = interruptCondition;
     _onInterruptReturn = onInterruptReturn;
 }
        public void When_interrupt_throws_then_doesnt_interrupt()
        {
            const BehaviourReturnCode actual = BehaviourReturnCode.Success;
            var action = new BehaviourAction(() => actual);

            var condition = new Conditional(() => { throw new Exception(); });
            var returnCode = new Interruptible(action, condition, BehaviourReturnCode.Success).Behave();
            Assert.AreEqual(actual, returnCode);
        }
        public void When_interrupt_is_true_returns_assigned_interrupt_return_value()
        {
            var action = new BehaviourAction(() => BehaviourReturnCode.Success);

            var condition = new Conditional(() => true);

            var successInterruptable = new Interruptible(action, condition, BehaviourReturnCode.Success);
            var failureInterruptable = new Interruptible(action, condition, BehaviourReturnCode.Failure);
            var runningInterruptable = new Interruptible(action, condition, BehaviourReturnCode.Running);

            Assert.AreEqual(successInterruptable.Behave(), BehaviourReturnCode.Success);
            Assert.AreEqual(failureInterruptable.Behave(), BehaviourReturnCode.Failure);
            Assert.AreEqual(runningInterruptable.Behave(), BehaviourReturnCode.Running);
        }
        public void When_interrupt_is_false_child_behaves_as_normal()
        {
            var successAction = new BehaviourAction(() => BehaviourReturnCode.Success);
            var failureAction = new BehaviourAction(() => BehaviourReturnCode.Failure);
            var runningAction = new BehaviourAction(() => BehaviourReturnCode.Running);

            var condition = new Conditional(() => false);

            var successInterruptable = new Interruptible(successAction, condition, BehaviourReturnCode.Failure);
            var failureInterruptable = new Interruptible(failureAction, condition, BehaviourReturnCode.Failure);
            var runningInterruptable = new Interruptible(runningAction, condition, BehaviourReturnCode.Failure);

            Assert.AreEqual(successInterruptable.Behave(), BehaviourReturnCode.Success);
            Assert.AreEqual(failureInterruptable.Behave(), BehaviourReturnCode.Failure);
            Assert.AreEqual(runningInterruptable.Behave(), BehaviourReturnCode.Running);
        }
        public void Setup()
        {
            var isThiefNearTreasureConditional = new Conditional(IsThiefNearTreasure);
            var makethiefFleeAction = new BehaviourAction(MakeThiefFlee);
            var sequence = new Sequence(new Inverter(isThiefNearTreasureConditional), makethiefFleeAction);

            var chooseCastleAction = new BehaviourAction(ChooseACastleToFlyTo);
            var flytoCastleAction = new BehaviourAction(FlyToCastle);
            var fightAction = new BehaviourAction(FightGuards);
            var strongEnoughConditional = new Conditional(StrongEnough);
            var takeGold = new BehaviourAction(TakeGold);
            var flytoHomeAction = new BehaviourAction(FlyToHome);
            var storeRobingsAction = new BehaviourAction(StoreGold);
            var secondSequence = new Sequence(chooseCastleAction, flytoCastleAction, fightAction, strongEnoughConditional, takeGold,
                                    flytoHomeAction, storeRobingsAction);
            var rootSelector = new RootSelector(SwitchNodes, sequence, secondSequence);
            _behaviour = new Behaviour(rootSelector);
        }
        private void Setup()
        {
            var tooClose = new Conditional(isTooClose);
            var targetMoved = new Conditional(hasTargetMoved);
            var pathFound = new Conditional(hasPathBeenFound);
            var reachedCell = new Conditional(hasReachedCell);
            var reachedTarget = new Conditional(hasReachedTarget);
            var isNewPath = new Conditional(hasNewPath);

            //setup all actions and their delegate functions
            BehaviourAction moveToCell = new BehaviourAction(moveTowardsCell);
            BehaviourAction calcPath = new BehaviourAction(calculatePath);
            BehaviourAction initPathfinder = new BehaviourAction(initializePathfinder);
            BehaviourAction getNextCell = new BehaviourAction(getNextPathCell);
            BehaviourAction setPath = new BehaviourAction(setNewPath);
            BehaviourAction getPath = new BehaviourAction(getCurrentPath);
            BehaviourAction updatePosition = new BehaviourAction(updateTargetPosision);
            BehaviourAction reset = new BehaviourAction(resetPathfinder);
            BehaviourAction animate = new BehaviourAction(updateAnimation);

            //setup an initilization branch
            var initialize = new Sequence(initPathfinder, calcPath);

            //if the target has moved, reset and calculate a new path
            var ifMovedCreateNewPath = new Selector(new Inverter(targetMoved), new Inverter(reset), calcPath);
            var ifPathFoundGetPath = new Selector(new Inverter(pathFound), getPath);
            var ifPathNewUseIt = new Selector(new Inverter(isNewPath), setPath);
            var ifReachedCellGetNext = new Selector(new Inverter(reachedCell), getNextCell);
            var ifNotReachedTargetMoveTowardsCell = new Selector(reachedTarget, moveToCell);

            var follow = new Selector(new Inverter(tooClose), updatePosition, ifMovedCreateNewPath, ifPathFoundGetPath,
                ifPathNewUseIt, ifReachedCellGetNext, ifNotReachedTargetMoveTowardsCell, animate);

            var root = new RootSelector(SwitchBehaviours, initialize, follow);

            //set a reference to the root
            _behaviour = new Behaviour(root);
        }
 /// <summary>
 /// Checks an interrupt condition, executing the given behaviour only if the condition returns False
 /// -Returns Success if the given behaviour returns Success and the condition returns False
 /// -Returns Running if the given behaviour returns Running and the condition returns False
 /// -Returns Failure if the given behaviour returns Failure or the condition returns True
 /// 
 /// Possibly not a good solution for interrupt style behaviour in the long run as it is very difficult to write
 /// conditions for interrupting without adding lots of state elsewhere to track when interrupts occur
 /// </summary>
 /// <param name="behaviour"></param>
 /// <param name="interruptCondition"></param>
 /// <param name="onInterruptReturn"></param>
 public Interruptible(BehaviourComponent behaviour, Conditional interruptCondition, BehaviourReturnCode onInterruptReturn)
     : this("", behaviour, interruptCondition, onInterruptReturn)
 {
 }