using System;
using System.Collections;
using System.Collections.Generic;

namespace InABox.Core
{
    public class FluentList<T> : IEnumerable<T>
    {
        public delegate void FluentListChangedEvent(object sender, EventArgs args);

        private bool _enabled = true;

        private readonly List<T> _values = new List<T>();

        public bool Enabled
        {
            get => _enabled;
            set
            {
                if (value)
                    EndUpdate();
                else
                    BeginUpdate();
            }
        }

        public T this[int i]
        {
            get => _values[i];
            set
            {
                _values[i] = value;
                Changed();
            }
        }

        public int Count => _values.Count;

        public IEnumerator<T> GetEnumerator()
        {
            return ((IEnumerable<T>)_values).GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable<T>)_values).GetEnumerator();
        }

        public FluentList<T> Add(T value)
        {
            if (!_values.Contains(value))
                _values.Add(value);
            return Changed();
        }

        public FluentList<T> AddRange(params T[] values)
        {
            foreach (var value in values)
                if (!_values.Contains(value))
                    _values.Add(value);
            return Changed();
        }

        public FluentList<T> AddRange(IEnumerable<T> values)
        {
            foreach (var value in values)
                if (!_values.Contains(value))
                    _values.Add(value);
            return Changed();
        }

        public FluentList<T> Remove(T value)
        {
            if (_values.Contains(value))
                _values.Remove(value);
            return Changed();
        }

        public FluentList<T> RemoveAt(int index)
        {
            if (index > 0 && index < _values.Count)
                _values.RemoveAt(index);
            return Changed();
        }

        public FluentList<T> Clear()
        {
            _values.Clear();
            return Changed();
        }

        public event FluentListChangedEvent OnChanged;

        public FluentList<T> BeginUpdate()
        {
            _enabled = false;
            return this;
        }

        private FluentList<T> Changed()
        {
            if (_enabled)
                OnChanged?.Invoke(this, new EventArgs());
            return this;
        }

        public FluentList<T> EndUpdate()
        {
            _enabled = true;
            return Changed();
        }
    }
}