Code/BehaviorTree/Decorator/BlackboardCondition.cs
namespace NPBehave
{
    public class BlackboardCondition : ObservingDecorator
    {
        private string _key;
        private object _value;
        private Operator _op;

        public string Key
        {
            get
            {
                return _key;
            }
        }

        public object Value
        {
            get
            {
                return _value;
            }
        }

        public Operator Operator
        {
            get
            {
                return _op;
            }
        }
        
        #if DEBUG
	    public override string DebugIcon => "quiz";
	    public override string ComputedLabel
	    {
		    get
		    {
			    return $"{Key} {OperatorToString(Operator)} {Value}";
		    }
	    }

	    public string OperatorToString( Operator _op )
	    {
		    return _op switch
		    {
			    Operator.IsSet => "?=",
			    Operator.IsNotSet => "?!=",
			    Operator.IsEqual => "==",
			    Operator.IsNotEqual => "!=",
			    Operator.IsGreaterOrEqual => ">=",
			    Operator.IsGreater => ">",
			    Operator.IsSmallerOrEqual => "<=",
			    Operator.IsSmaller => "<",
			    Operator.AlwaysTrue => "ALWAYS_TRUE",
			    _ => $"<{_op}>"
		    };
	    }


#endif

        public BlackboardCondition(string key, Operator op, object value, Stops stopsOnChange, Node decoratee) : base("BlackboardCondition", stopsOnChange, decoratee)
        {
            _op = op;
            _key = key;
            _value = value;
            StopsOnChange = stopsOnChange;
        }
        
        public BlackboardCondition(string key, Operator op, Stops stopsOnChange, Node decoratee) : base("BlackboardCondition", stopsOnChange, decoratee)
        {
            _op = op;
            _key = key;
            StopsOnChange = stopsOnChange;
        }


        protected override void StartObserving()
        {
            RootNode.Blackboard.AddObserver(_key, OnValueChanged);
        }

        protected override void StopObserving()
        {
            RootNode.Blackboard.RemoveObserver(_key, OnValueChanged);
        }

        private void OnValueChanged(Blackboard.Type type, object newValue)
        {
            Evaluate();
        }

        protected override bool IsConditionMet()
        {
            if (_op == Operator.AlwaysTrue)
            {
                return true;
            }

            if (!RootNode.Blackboard.IsSet(_key))
            {
                return _op == Operator.IsNotSet;
            }

            object o = RootNode.Blackboard.Get(_key);

            switch (_op)
            {
                case Operator.IsSet: return true;
                case Operator.IsEqual: return Equals(o, _value);
                case Operator.IsNotEqual: return !Equals(o, _value);

                case Operator.IsGreaterOrEqual:
                    if (o is float)
                    {
                        return (float)o >= (float)_value;
                    }
                    else if (o is int)
                    {
                        return (int)o >= (int)_value;
                    }
                    else
                    {
                        Log.Error( $"Type not compareable: {o.GetType()}" );
                        return false;
                    }

                case Operator.IsGreater:
                    if (o is float)
                    {
                        return (float)o > (float)_value;
                    }
                    else if (o is int)
                    {
                        return (int)o > (int)_value;
                    }
                    else
                    {
	                    Log.Error( $"Type not compareable: {o.GetType()}" );
                        return false;
                    }

                case Operator.IsSmallerOrEqual:
                    if (o is float)
                    {
                        return (float)o <= (float)_value;
                    }
                    else if (o is int)
                    {
                        return (int)o <= (int)_value;
                    }
                    else
                    {
	                    Log.Error( $"Type not compareable: {o.GetType()}" );
                        return false;
                    }

                case Operator.IsSmaller:
                    if (o is float)
                    {
                        return (float)o < (float)_value;
                    }
                    else if (o is int)
                    {
                        return (int)o < (int)_value;
                    }
                    else
                    {
	                    Log.Error( $"Type not compareable: {o.GetType()}" );
                        return false;
                    }

                default: return false;
            }
        }

        public override string ToString()
        {
            return $"({_op}) {_key} ? {_value}";
        }
    }
}