using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Bitsplash.DatePicker
{ 
    /// 
    /// holds dates selected by the date picker
    /// 
    public class DatePickerCollection : IDatePickerCollectionPrivate
    {
        bool mInvalid = false;
        HashSet mData = new HashSet();
        bool mChanged = false;
        bool mAllowEmpty = false;
        DateTime[] mItems;
        bool IDatePickerCollectionPrivate.Changed { get { return mChanged; } set { mChanged = value; } }
        bool IDatePickerCollectionPrivate.AllowEmpty { get { return mAllowEmpty; } set
            {
                mAllowEmpty = value;
                if(mAllowEmpty == false && mData.Count ==0)
                {
                    ValidateNonEmpty();
                    Invalidate();
                }
            }
        }
        event Action InnerSelectionModified;
        event Action IDatePickerCollectionPrivate.SelectionModified
        {
            add
            {
                InnerSelectionModified += value;
            }
            remove
            {
                InnerSelectionModified -= value;
            }
        }
        public int Count
        {
            get { return mData.Count; }
        }
        /// 
        /// selects a range of dates , clearing all other dates
        /// 
        /// 
        /// 
        public void SelectRange(DateTime from,DateTime to)
        {
            if (CommonMethods.IsRangeSelected(from, to, mData))
                return;
            CommonMethods.SelectRange(from, to, mData);
            Invalidate();
        }
        void Invalidate()
        {
            mChanged = true;
            mInvalid = true;
            if (InnerSelectionModified != null)
                InnerSelectionModified();
        }
        /// 
        /// returns true if a date is the only date selected
        /// 
        /// 
        /// 
        public bool IsSingleDateSelected(DateTime date)
        {
            date = date.Date;
            if (mData.Contains(date) && mData.Count == 1)
                return true;
            return false;
        }
        /// 
        /// selects one date clearing all other dates
        /// 
        /// 
        public void SelectOne(DateTime date)
        {
            date = date.Date;
            if (mData.Contains(date) && mData.Count == 1)
                return;
            mData.Clear();
            Add(date);
        }
        void ValidateNonEmpty()
        {
            if (mAllowEmpty == false && mData.Count == 0)
                mData.Add(DateTime.Today.Date);
        }
        /// 
        /// clears all selected dates. If the selection cannot be empty , DateTime.Today is set as the selection
        /// 
        public void Clear()
        {
            if (mData.Count == 0)
                return;
            if (mAllowEmpty == false && IsSingleDateSelected(DateTime.Today))
                return;
            mData.Clear();
            ValidateNonEmpty();
            Invalidate();
        }
        /// 
        /// appends all the items to the date collection
        /// 
        /// 
        public void AddItems(HashSet range)
        {
            bool changed = false;
            foreach(DateTime d in range)
            {
                if (mData.Add(d))
                    changed = true;
            }
            if (changed)
                Invalidate();
        }
        /// 
        /// adds a date into the date selection. 
        /// 
        /// 
        public void Add(DateTime date)
        {
            if(mData.Add(date.Date))
                Invalidate();
        }
        /// 
        /// returns true if the date collection contains the specified date
        /// 
        /// 
        /// 
        public bool Contains(DateTime date)
        {
            return mData.Contains(date.Date);
        }
        /// 
        /// gets the date item at index 
        /// 
        /// 
        /// 
        public DateTime GetItem(int index)
        {
            if(mInvalid || mItems == null)
            {
                mInvalid = false;
                mItems = mData.OrderBy(x => x).ToArray();
            }
            return mItems[index];
        }
        /// 
        /// removes a date from the collection if it present. returns true if the date was present and was removed
        /// 
        /// 
        /// 
        public bool Remove(DateTime date)
        {
            if (mData.Remove(date.Date))
            {
                ValidateNonEmpty();
                Invalidate();
                return true;
            }
            return false;
        }
    }
}