﻿using System.Collections.Generic;
using JLGames.RocketDriver.Games.RpgMaterial.Common;

namespace JLGames.RocketDriver.Games.RpgMaterial.Service
{
    public sealed class TriggerQueue : ITriggerRegister, ITriggerContainer, ITriggerHandler
    {
        private readonly int m_Type;
        private readonly List<ITriggerEntity> m_Triggers;

        public TriggerQueue(int mType = 0)
        {
            m_Type = mType;
            m_Triggers = new List<ITriggerEntity>();
        }

        public TriggerQueue(int capacity, int mType = 0)
        {
            m_Type = mType;
            m_Triggers = new List<ITriggerEntity>(capacity);
        }

        // ITriggerRegister

        public void RegisterTrigger(ITriggerEntity trigger)
        {
            Add(trigger);
        }

        public int RegisterTrigger(Trigger.TrackingType tType, int mType, int eId, Trigger.CompareType cType, int cValue,
            Trigger.TriggerInvoke invokeFunc, bool post = true, int times = -1)
        {
            switch (tType)
            {
                case Trigger.TrackingType.Offset:
                    return RegisterOffsetTrigger(mType, eId, cType, cValue, invokeFunc, post, times);
                case Trigger.TrackingType.Value:
                    return RegisterValueTrigger(mType, eId, cType, cValue, invokeFunc, post, times);
            }

            return -1;
        }

        public int RegisterOffsetTrigger(int mType, int eId, Trigger.CompareType cType, int cValue, Trigger.TriggerInvoke invokeFunc,
            bool post = true, int times = -1)
        {
            if (0 != m_Type && m_Type != mType) return -1;
            var trigger = new OffsetCompareTrigger(mType, eId, cType, cValue, invokeFunc, post, times);
            Add(trigger);
            return trigger.TriggerId;
        }

        public int RegisterValueTrigger(int mType, int eId, Trigger.CompareType cType, int cValue, Trigger.TriggerInvoke invokeFunc, bool post = true,
            int times = -1)
        {
            if (0 != m_Type && m_Type != mType) return -1;
            var trigger = new ValueCompareTrigger(mType, eId, cType, cValue, invokeFunc, post, times);
            Add(trigger);
            return trigger.TriggerId;
        }

        public void UnregisterTrigger(ITriggerEntity trigger)
        {
            Remove(trigger);
        }

        public void UnregisterTrigger(int triggerId)
        {
            Remove(triggerId);
        }

        // ITriggerContainer

        public bool Exist(int triggerId)
        {
            return m_Triggers.FindIndex(o => o.TriggerId == triggerId) >= 0;
        }

        public bool Exist(ITriggerEntity trigger)
        {
            return m_Triggers.Contains(trigger);
        }

        public void Add(ITriggerEntity trigger)
        {
            if (null == trigger || m_Triggers.Contains(trigger)) return;
            m_Triggers.Add(trigger);
        }

        public void Remove(int triggerId)
        {
            if (m_Triggers.Count == 0) return;
            var index = m_Triggers.FindIndex(entity => entity.TriggerId == triggerId);
            if (-1 == index) return;
            m_Triggers.RemoveAt(index);
        }

        public void Remove(ITriggerEntity trigger)
        {
            if (null == trigger) return;
            if (m_Triggers.Count == 0 || !m_Triggers.Contains(trigger)) return;
            m_Triggers.Remove(trigger);
        }

        public void Clear()
        {
            m_Triggers.Clear();
        }

        public void ClearInvalid()
        {
            for (var index = m_Triggers.Count - 1; index >= 0; index--)
            {
                if (m_Triggers[index].RemainEmpty) m_Triggers.RemoveAt(index);
            }
        }

        public void ForeachBefore(UserNotifyData data)
        {
            if (m_Triggers.Count == 0) return;
            m_Triggers.ForEach(element =>
            {
                if (element.IsPost) return;
                if (!element.Match(data)) return;
                element.InvokeTrigger(data);
            });
            ClearInvalid();
        }

        public void ForeachPost(UserNotifyData data)
        {
            if (m_Triggers.Count == 0) return;
            m_Triggers.ForEach(element =>
            {
                if (!element.IsPost) return;
                if (!element.Match(data)) return;
                element.InvokeTrigger(data);
            });
            ClearInvalid();
        }
    }
}