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

namespace AidA.Data.ViewModel
{
	public abstract class AbstractBaseVM : INotifyPropertyChanged
	{
		private bool _IsDirty;

		public virtual bool IsDirty
		{
			get { return _IsDirty; }
		}

		public Type Type
		{
			get { return GetType(); }
		}

		public event PropertyChangedEventHandler PropertyChanged;

		public virtual void SetDirty(bool newDirty)
		{
			_IsDirty = newDirty;
		}

		protected bool AreDifferent(object pMember, object pNewValue)
		{
			if (pNewValue is string && ((string)pNewValue) == string.Empty)
			{
				return pMember != null && ((string)pMember) != string.Empty;
			}

			return (pMember == null && pNewValue != null) || (pMember != null && !pMember.Equals(pNewValue));
		}

		protected bool AreDifferent<T>(object pMember, object pNewValue)
		{
			if (pMember is IEnumerable<T> l1 && pNewValue is IEnumerable<T> l2)
			{
				return !Enumerable.SequenceEqual(l1, l2);
			}

			return AreDifferent(pMember, pNewValue);
		}

		protected bool AreEqual(object x, object y)
		{
			if (x == null)
            {
				return y == null;
            }
			return x.Equals(y);
		}

		public object Itself
		{
			get
			{
				return this;
			}
		}

		public void FirePropertyChangedItself()
		{
			FirePropertyChanged(nameof(Itself));
		}

		protected virtual void FirePropertyChanged(string pPropertyName)
		{
			FirePropertyChanged(PropertyChanged, this, pPropertyName);
		}

		protected void FirePropertyChanged(PropertyChangedEventHandler handler, string pPropertyName)
		{
			FirePropertyChanged(handler, this, pPropertyName);
		}

		protected void FirePropertyChanged(object sender, string pPropertyName)
		{
			FirePropertyChanged(PropertyChanged, sender, pPropertyName);
		}

		protected void FirePropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			FirePropertyChanged(PropertyChanged, sender, e);
		}

		protected void FirePropertyChanged(PropertyChangedEventHandler handler, object sender, string pPropertyName)
		{
			FirePropertyChanged(handler, sender, new PropertyChangedEventArgs(pPropertyName));
		}

		protected void FirePropertyChanged(PropertyChangedEventHandler handler, object sender, PropertyChangedEventArgs e)
		{
			_IsDirty = true;
			handler?.Invoke(sender, e);
		}
	}
}