using System;
using System.Collections.Generic;
using UnityEngine;
namespace BehaviorTreeSlayer
{
    /// <summary>
    /// Agent of behavior tree,
    /// This class is not required. 
    /// You only need to call Entry.update in the right place to drive the behavior tree to run
    /// use event drive method to communicate data with outside
    /// </summary>
    public class BehaviorTree : MonoBehaviour
    {
        System.Random rd = new System.Random();
        public System.Random MyRandom => rd;//random inside behavior tree call
        public bool AutoRun;

        Dictionary<string, Action<object>> actions = new Dictionary<string, Action<object>>();
        public void Regist(string key, Action<object> onEvent)
        {
            if (actions.ContainsKey(key))
            {
                actions[key] = onEvent;
            }
            else
            {
                actions.Add(key, onEvent);
            }
        }
        public void UnRegist(string key)
        {
            actions.Remove(key);
        }
        public void Dispatch(string key, object obj)
        {
            if (actions.ContainsKey(key))
            {
                actions[key].Invoke(obj);
            }
        }
        public TextAsset config;
        Entry Entry;
        public List<GameObject> Obj = new List<GameObject>();
        Dictionary<string, object> blackBoard = new Dictionary<string, object>();

        public object this[string key]
        {
            get
            {

                if (blackBoard.TryGetValue(key, out object v))
                {
                    return v;
                }
                GameObject obj = Obj.Find(o => o.name.Equals(key));
                return obj;
            }
            set
            {
                if (blackBoard.ContainsKey(key))
                {
                    blackBoard[key] = value;
                }
                else
                {
                    blackBoard.Add(key, value);
                }
            }
        }
        public void Remove(string key)
        {
            blackBoard.Remove(key);
        }



        private void Start()
        {
            Load();
            if (AutoRun) Entry?.Enter(this);
        }

        public Entry Load()
        {
            if (Entry == null && config != null)
            {
                Entry = XmlUtils.DeSerialize<Entry>(config.text);
            }
            return Entry;
        }

        private void Update()
        {
            Entry?.Tick(Time.deltaTime, this);
        }
    }
}