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

namespace InABox.Core
{
    public class ObservableList<T> : List<T>, IBaseObject where T : BaseObject, new()
    {
        private bool _observing = true;

        private bool bApplyingChanges;

        private bool bChanged;

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

        public bool IsObserving()
        {
            return _observing;
        }

        public void SetObserving(bool active)
        {
            _observing = active;
        }

        public bool IsChanged()
        {
            return QueryChanged();
        }

        public void CancelChanges()
        {
            Clear();
            AddRange(OriginalItems);
            bChanged = false;
        }

        public void CommitChanges()
        {
            OriginalItems.Clear();
            OriginalItems.AddRange(this);
            bChanged = false;
        }

        private bool QueryChanged()
        {
            if (bChanged)
                return true;

            foreach (var item in this)
                if (item.IsChanged())
                    return true;

            return false;
        }

        private void Changed()
        {
            bChanged = true;

            if (!bApplyingChanges)
            {
                bApplyingChanges = true;
                OnChanged?.Invoke(this, new EventArgs());
                bApplyingChanges = false;
            }
        }

        public new void Add(T item)
        {
            base.Add(item);
            item.PropertyChanged += Item_PropertyChanged;
            Changed();
        }

        private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            Changed();
        }

        public new void AddRange(IEnumerable<T> collection)
        {
            base.AddRange(collection);
            foreach (var item in collection)
                item.PropertyChanged += Item_PropertyChanged;
            Changed();
        }

        public new void Clear()
        {
            foreach (var item in this)
                item.PropertyChanged -= Item_PropertyChanged;
            base.Clear();
            Changed();
        }

        public new void Remove(T item)
        {
            base.Remove(item);
            item.PropertyChanged -= Item_PropertyChanged;
            Changed();
        }

        public event EventHandler OnChanged;
    }

    public class EntityList<T> : ObservableList<T> where T : Entity, new()
    {
    }
}