using System;
using System.Collections.Generic;

namespace Fort23.Core
{
    public class ComponentQueue: CObject
    {
        public string TypeName
        {
            get;
        }

        private readonly Queue<CObject> _queue = new Queue<CObject>();

        public ComponentQueue(string typeName)
        {
            this.TypeName = typeName;
        }

        public void Enqueue(CObject entity)
        {
            this._queue.Enqueue(entity);
        }

        public CObject Dequeue()
        {
            return this._queue.Dequeue();
        }

        public CObject Peek()
        {
            return this._queue.Peek();
        }

        public Queue<CObject> Queue => this._queue;

        public int Count => this._queue.Count;

        public override void Dispose()
        {
            while (this._queue.Count > 0)
            {
                CObject component = this._queue.Dequeue();
                component.Dispose();
            }
        }
    }

    public class CObjectPool: CObject
    {
        private static CObjectPool _instance;

        public static CObjectPool Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new CObjectPool();
                }

                return _instance;
            }
        }

        private readonly Dictionary<Type, ComponentQueue> _dictionary = new Dictionary<Type, ComponentQueue>();

        public CObject Fetch(Type type)
        {
            CObject obj;
            if (!this._dictionary.TryGetValue(type, out ComponentQueue queue))
            {
                obj = (CObject) Activator.CreateInstance(type);
            }
            else if (queue.Count == 0)
            {
                obj = (CObject) Activator.CreateInstance(type);
            }
            else
            {
                obj = queue.Dequeue();
            }

            return obj;
        }

        public T Fetch<T>() where T : CObject
        {
            T t = (T) this.Fetch(typeof (T));
            return t;
        }

        public void Recycle(CObject obj)
        {
            Type type = obj.GetType();
            ComponentQueue queue;
            if (!this._dictionary.TryGetValue(type, out queue))
            {
                queue = new ComponentQueue(type.Name);
                this._dictionary.Add(type, queue);
            }
            queue.Enqueue(obj);
        }

        public void Clear()
        {
            foreach (KeyValuePair<Type, ComponentQueue> kv in this._dictionary)
            {
                kv.Value.Dispose();
            }

            this._dictionary.Clear();
        }

        public override void Dispose()
        {
            foreach (KeyValuePair<Type, ComponentQueue> kv in this._dictionary)
            {
                kv.Value.Dispose();
            }

            this._dictionary.Clear();
            _instance = null;
        }
    }
}