using Cryville.Common.Buffers;
using System.Collections.Generic;
using UnityEngine;

namespace Cryville.Crtr.Skin {
	public class EffectGroup {
		public EffectDefinition Definition { get; private set; }
		readonly EffectPool _pool;
		class EffectPool : ObjectPool<EffectInstance> {
			readonly List<EffectInstance> _instances
				= new List<EffectInstance>();
			readonly EffectGroup _group;
			public EffectPool(EffectGroup group) : base(256) {
				_group = group;
			}
			protected override EffectInstance Construct() {
				var result = new EffectInstance(_group.Definition);
				_instances.Add(result);
				return result;
			}
			public void DisposeAll() {
				foreach (var i in _instances) i.Dispose();
			}
		}
		readonly Dictionary<float, EffectInstance> _instances
			= new Dictionary<float, EffectInstance>();
		readonly List<EffectInstance> _endQueue
			= new List<EffectInstance>();
		public EffectGroup(EffectDefinition def) {
			Definition = def;
			_pool = new EffectPool(this);
		}
		double _time;
		public void Tick(double time) {
			_time = time;
			while (_endQueue.Count > 0) {
				var item = _endQueue[0];
				if (item.EndTime > _time) break;
				_endQueue.RemoveAt(0);
				if (item.OnStateDone()) {
					QueueInstance(item);
				}
				else {
					item.Tick(time);
					_instances.Remove(item.Index);
					_pool.Return(item);
				}
			}
			foreach (var instance in _instances) {
				instance.Value.Tick(time);
			}
		}
		public void Emit(float index, Transform target = null) {
			EffectInstance instance;
			bool flag = _instances.TryGetValue(index, out instance);
			if (!flag) _instances.Add(index, instance = _pool.Rent());
			instance.Index = index;
			if (instance.CanEmit()) {
				if (flag) {
					var i = _endQueue.BinarySearch(instance);
					_endQueue.RemoveAt(i);
				}
				instance.OnEmit(_time, target);
				QueueInstance(instance);
			}
		}
		void QueueInstance(EffectInstance i) {
			var index = ~_endQueue.BinarySearch(i);
			_endQueue.Insert(index, i);
		}
		public void Dispose() {
			_pool.DisposeAll();
		}
	}
}
