﻿using System;
using JLGames.RocketDriver.Games.RpgMaterial.Service;
using JLGames.RocketDriver.Games.RpgMaterial.Common;

namespace JLGames.RocketDriver.Games.RpgMaterial.Material
{
    public class MaterialSet : IMaterialSetMod
    {
        protected readonly IElementSet<IElement> m_Elements;

        public int MaterialSize => m_Elements.Size;

        public MaterialSet()
        {
            m_Elements = new ElementSet<IElement>();
        }

        public MaterialSet(IElementSet<IElement> elements)
        {
            m_Elements = elements;
        }

        public void UpdateSet(IElementSet elements)
        {
            m_Elements.RemoveAll();
            m_Elements.AddRange(elements.GetElements<IElement>());
        }

        public bool ExistMaterial(int mId)
        {
            return m_Elements.Exist(mId + "");
        }

        public int GetSizeAs<TMAs>(Predicate<TMAs> match) where TMAs : class, IMaterial
        {
            var count = 0;
            for (var index = m_Elements.Size - 1; index >= 0; index--)
            {
                if (match.Invoke(m_Elements[index] as TMAs)) count += 1;
            }

            return count;
        }

        public TMAs GetMaterialAs<TMAs>(int mId) where TMAs : class, IMaterial
        {
            return m_Elements.GetElement<TMAs>(mId + "");
        }

        public void ForeachMaterialAs<TMAs>(Action<TMAs> each) where TMAs : class, IMaterial
        {
            m_Elements.ForeachElement(each);
        }
    }

    public class MaterialSet<TM, TCfg> : IMaterialSetMod<TM, TCfg> where TM : IMaterial<TCfg>
    {
        protected readonly IElementSet<TM> m_Elements;

        public MaterialSet()
        {
            m_Elements = new ElementSet<TM>();
        }

        public MaterialSet(IElementSet<TM> elements)
        {
            m_Elements = elements;
        }

        // IMaterialSetMod

        public void UpdateSet(IElementSet elements)
        {
            m_Elements.RemoveAll();
            m_Elements.AddRange(elements.GetElements<TM>());
        }

        public void UpdateSet(IElementSet<TM> elements)
        {
            m_Elements.RemoveAll();
            m_Elements.AddRange(elements.GetElements<TM>());
        }

        // IMaterialSet

        public int MaterialSize => m_Elements.Size;

        public int GetSizeAs<TMAs>(Predicate<TMAs> match) where TMAs : class, IMaterial
        {
            var count = 0;
            for (var index = m_Elements.Size - 1; index >= 0; index--)
            {
                if (match.Invoke(m_Elements[index] as TMAs)) count += 1;
            }

            return count;
        }

        public bool ExistMaterial(int mId)
        {
            return m_Elements.Exist(mId + "");
        }

        public TMAs GetMaterialAs<TMAs>(int mId) where TMAs : class, IMaterial
        {
            return m_Elements.GetElement<TMAs>(mId + "");
        }

        public void ForeachMaterialAs<TMAs>(Action<TMAs> each) where TMAs : class, IMaterial
        {
            m_Elements.ForeachElement(each);
        }

        // IMaterialSet<TM, TCfg>

        public int GetSize(Predicate<TM> match)
        {
            var count = 0;
            for (var index = m_Elements.Size - 1; index >= 0; index--)
            {
                if (match.Invoke(m_Elements[index])) count += 1;
            }

            return count;
        }

        public TM GetMaterial(int mId)
        {
            return m_Elements.Get(mId + "");
        }

        public TM[] GetMaterials()
        {
            return m_Elements.GetAll();
        }

        public TM[] GetMaterials(Predicate<TM> match)
        {
            return m_Elements.GetRange(match);
        }

        public void ForeachMaterial(Action<TM> each)
        {
            m_Elements.Foreach(each);
        }
    }
}