#if FRAMEWORK20
using System;
using System.Collections.Generic;
using DevComponents.Schedule.Model;
using System.ComponentModel;
namespace DevComponents.DotNetBar.Schedule
{
    internal class ModelMonthViewConnector : ModelViewConnector
    {
        #region Constants
        private const int DaysInWeek = 7;
        #endregion
        #region Private variables
        private CalendarModel _Model;       // The associated CalendarModel
        private MonthView _View;            // The associated MonthView
        private bool _IsConnected;          // Connection status
        private uint _RefreshCount;
        #endregion
        /// 
        /// Constructor
        /// 
        /// Assoc CalendarModel
        /// Assoc MonthView
        public ModelMonthViewConnector(CalendarModel model, MonthView monthView)
        {
            _Model = model;
            _View = monthView;
        }
        #region Public properties
        /// 
        /// Gets the connection status
        /// 
        public override bool IsConnected
        {
            get { return _IsConnected; }
        }
        #endregion
        #region Connect
        /// 
        /// Performs Model connection processing
        /// 
        public override void Connect()
        {
            VerifyModel();
            // Load the connection data
            if (_IsConnected)
                Disconnect();
            LoadData();
            // Get notification on Model property changes
            _Model.PropertyChanged += ModelPropertyChanged;
            _Model.SubPropertyChanged += ModelSubPropertyChanged;
            _View.CalendarView.CustomItems.CollectionChanged += CustomItemsCollectionChanged;
            _IsConnected = true;
        }
        #endregion
        #region Disconnect
        /// 
        /// Severs the Model/MonthView connection
        /// 
        public override void Disconnect()
        {
            VerifyModel();
            if (_IsConnected)
            {
                // Loop through each week, clearing each
                // associated view connection
                for (int i = 0; i < _View.MonthWeeks.Length; i++)
                    ClearMonthWeek(_View.MonthWeeks[i]);
                _View.SubItems.Clear();
                // Stop notification on Model property changes
                _Model.PropertyChanged -= ModelPropertyChanged;
                _Model.SubPropertyChanged -= ModelSubPropertyChanged;
                _View.CalendarView.CustomItems.CollectionChanged -= CustomItemsCollectionChanged;
                _IsConnected = false;
            }
        }
        /// 
        /// Clears individual MonthWeek view connections
        /// 
        /// MonthWeek
        private void ClearMonthWeek(MonthWeek monthWeek)
        {
            if (monthWeek.CalendarItems.Count > 0)
            {
                // Loop through each CalendarItem, resetting
                // it's associated connection
                for (int i = monthWeek.CalendarItems.Count - 1; i >= 0; i--)
                {
                    AppointmentMonthView view =
                        monthWeek.CalendarItems[i] as AppointmentMonthView;
                    if (view != null)
                    {
                        view.IsSelectedChanged -= _View.ItemIsSelectedChanged;
                        view.Appointment = null;
                        view.IsSelected = false;
                        view.MonthWeek = null;
                    }
                    monthWeek.CalendarItems.RemoveAt(i);
                }
            }
        }
        #endregion
        #region LoadData
        /// 
        /// Loads Model/MonthView connection data
        /// 
        private void LoadData()
        {
            MonthWeek[] wks = _View.MonthWeeks;
            if (wks.Length > 0)
            {
                _RefreshCount++;
                DateTime startDate = wks[0].FirstDayOfWeek;
                DateTime endDate = DateTimeHelper.EndOfDay(wks[wks.Length - 1].LastDayOfWeek);
                DateTime appStartDate = startDate.AddMonths(-1);
                List appts = GetAppointmentList(_Model, appStartDate, endDate);
                for (int i = 0; i < wks.Length; i++)
                {
                    MonthWeek monthWeek = wks[i];
                    startDate = monthWeek.FirstDayOfWeek;
                    endDate = DateTimeHelper.EndOfDay(monthWeek.LastDayOfWeek);
                    UpdateWeekView(monthWeek, appts, startDate, endDate);
                    UpdateCustomItems(monthWeek, startDate, endDate);
                }
            }
        }
        #endregion
        #region RefreshData
        /// 
        /// Refreshes the data in a previously established
        /// and loaded connection
        /// 
        public void RefreshData()
        {
            LoadData();
            List removedViews = null;
            foreach (MonthWeek monthWeek in _View.MonthWeeks)
                RemoveOutdatedViews(monthWeek, ref removedViews);
            ProcessRemovedData(removedViews);
        }
        #region RemoveOutdatedViews
        private void RemoveOutdatedViews(
            MonthWeek monthWeek, ref List removedViews)
        {
            for (int i = monthWeek.CalendarItems.Count - 1; i >= 0; i--)
            {
                CalendarItem view = monthWeek.CalendarItems[i];
                if (view != null)
                {
                    if (view.RefreshCount != _RefreshCount)
                    {
                        if (removedViews == null)
                            removedViews = new List();
                        removedViews.Add(view);
                        _View.SubItems._Remove(view);
                        _View.NeedRecalcSize = true;
                        monthWeek.CalendarItems.RemoveAt(i);
                    }
                }
            }
        }
        #endregion
        #region ProcessRemovedData
        private void ProcessRemovedData(List removedViews)
        {
            if (removedViews != null && removedViews.Count > 0)
            {
                for (int i = 0; i < removedViews.Count; i++)
                {
                    CalendarItem item = removedViews[i];
                    item.IsSelectedChanged -= _View.ItemIsSelectedChanged;
                    item.Dispose();
                }
                _View.NeedRecalcLayout = true;
            }
        }
        #endregion
        #endregion
        #region UpdateWeekView
        private void UpdateWeekView(MonthWeek monthWeek,
            List apps, DateTime startDate, DateTime endDate)
        {
            // Loop through each appointment
            // updating the assoc view accordingly
            foreach (Appointment app in  apps)
            {
                if (app.StartTime < endDate && app.EndTime > startDate)
                {
                    if (IsAppointmentVisible(app))
                    {
                        // Get the assoc view
                        AppointmentMonthView view = GetViewFromWeek(monthWeek, app) ??
                                                    GetNewView(app);
                        // Set the view start and end times to
                        // match the assoc appointment
                        view.StartTime = app.StartTime;
                        view.EndTime = app.EndTime;
                        view.RefreshCount = _RefreshCount;
                        // And update the MonthWeek data
                        if (view.MonthWeek == null)
                        {
                            view.MonthWeek = monthWeek;
                            monthWeek.CalendarItems.Add(view);
                            _View.SubItems.Add(view);
                        }
                        view.IsSelected = app.IsSelected;
                    }
                }
            }
        }
        #endregion
        #region UpdateCustomItems
        private void UpdateCustomItems(
            MonthWeek monthWeek, DateTime startDate, DateTime endDate)
        {
            CustomCalendarItemCollection items = _View.CalendarView.CustomItems;
            if (items != null && items.Count > 0)
            {
                for (int i = 0; i < items.Count; i++)
                {
                    CustomCalendarItem item = items[i];
                    if (IsCustomItemVisible(item) == true &&
                        (item.StartTime < endDate && item.EndTime > startDate))
                    {
                        item.CalendarView = _View.CalendarView;
                        CustomCalendarItem ci = GetItemFromWeek(monthWeek, item);
                        if (ci == null)
                        {
                            ci = GetNewCustomItem(item);
                            monthWeek.CalendarItems.Add(ci);
                            _View.SubItems.Insert(0, ci);
                        }
                        ci.RefreshCount = _RefreshCount;
                        if (ci.BaseCalendarItem != item)
                        {
                            ci.StartTime = item.StartTime;
                            ci.EndTime = item.EndTime;
                        }
                    }
                }
            }
        }
        #endregion
        #region GetViewFrom
        private List GetViewsFromAll(Appointment app)
        {
            List list = new List();
            for (int i = 0; i < _View.MonthWeeks.Length; i++)
            {
                AppointmentMonthView view =
                    GetViewFromWeek(_View.MonthWeeks[i], app);
                if (view != null)
                    list.Add(view);
            }
            return (list);
        }
        private AppointmentMonthView GetViewFromWeek(MonthWeek monthWeek, Appointment appointment)
        {
            foreach (CalendarItem item in monthWeek.CalendarItems)
            {
                AppointmentMonthView view = item as AppointmentMonthView;
                if (view != null && view.Appointment == appointment)
                    return (view);
            }
            return (null);
        }
        #endregion
        #region GetItemFromWeek
        private CustomCalendarItem GetItemFromWeek(MonthWeek monthWeek, CustomCalendarItem item)
        {
            foreach (CalendarItem citem in monthWeek.CalendarItems)
            {
                CustomCalendarItem view = citem as CustomCalendarItem;
                if (view != null && (view == item || view.BaseCalendarItem == item))
                    return (view);
            }
            return (null);
        }
        #endregion
        #region GetNewView
        /// 
        /// Gets a new appointment view
        /// 
        /// Appointment
        /// New view
        private AppointmentMonthView GetNewView(Appointment appointment)
        {
            AppointmentMonthView view = new AppointmentMonthView(_View, appointment);
            view.Tooltip = appointment.Tooltip;
            // Set the selected state to match any current
            // views that are present for this appointment
            for (int i = 0; i < _View.MonthWeeks.Length; i++)
            {
                AppointmentMonthView viewPart =
                    GetViewFromWeek(_View.MonthWeeks[i], appointment);
                if (viewPart != null)
                {
                    view.IsSelected = viewPart.IsSelected;
                    break;
                }
            }
            view.IsSelectedChanged += _View.ItemIsSelectedChanged;
            return (view);
        }
        #endregion
        #region GetNewCustomItem
        /// 
        /// Gets a new CustomItem
        /// 
        /// 
        /// 
        private CustomCalendarItem GetNewCustomItem(CustomCalendarItem item)
        {
            CustomCalendarItem ci = (CustomCalendarItem)item.Copy();
            ci.BaseCalendarItem = item;
            ci.ModelItem = item;
            // Set the selected state to match any current
            // views that are present for this appointment
            for (int i = 0; i < _View.MonthWeeks.Length; i++)
            {
                CustomCalendarItem viewPart =
                    GetItemFromWeek(_View.MonthWeeks[i], item);
                if (viewPart != null)
                {
                    ci.IsSelected = viewPart.IsSelected;
                    break;
                }
            }
            ci.IsSelectedChanged += _View.ItemIsSelectedChanged;
            return (ci);
        }
        #endregion
        #region GetView
        /// 
        /// Returns the Month view
        /// 
        /// 
        public override eCalendarView GetView()
        {
            return (eCalendarView.Month);
        }
        /// 
        /// Verifies the Model and MonthView are valid
        /// 
        private void VerifyModel()
        {
            if (_Model == null)
                throw new NullReferenceException("CalendarModel must be set on connector.");
            if (_View == null)
                throw new NullReferenceException("MonthCalendarView must be set on connector.");
        }
        #endregion
        #region ModelPropertyChanged
        /// 
        /// Handles Model property change notifications
        /// 
        /// 
        /// 
        private void ModelPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == CalendarModel.AppointmentsPropertyName)
            {
                RefreshData();
                _View.NeedRecalcSize = true;
                _View.Refresh();
            }
        }
        #endregion
        #region ModelSubPropertyChanged
        /// 
        /// Handles ModelSubProperty change notifications
        /// 
        /// object
        /// SubPropertyChangedEventArgs
        private void ModelSubPropertyChanged(object sender, SubPropertyChangedEventArgs e)
        {
            if (e.Source is Owner)
            {
                Owner owner = (Owner)e.Source;
                if (_View.OwnerKey != null && _View.OwnerKey.Equals(owner.Key))
                {
                    if (e.PropertyChangedArgs.PropertyName == Owner.DisplayNamePropertyName)
                        _View.DisplayName = owner.DisplayName;
                    else if (e.PropertyChangedArgs.PropertyName.Equals("ColorScheme"))
                        _View.CalendarColor = owner.ColorScheme;
                }
            }
            else if (e.Source is Appointment)
            {
                Appointment app = e.Source as Appointment;
                List list;
                string name = e.PropertyChangedArgs.PropertyName;
                if (name.Equals("Tooltip"))
                {
                    list = GetViewsFromAll(app);
                    for (int i = 0; i < list.Count; i++)
                        list[i].Tooltip = app.Tooltip;
                }
                else if (name.Equals("IsSelected"))
                {
                    list = GetViewsFromAll(app);
                    for (int i = 0; i < list.Count; i++)
                        list[i].IsSelected = app.IsSelected;
                }
                else if (name.Equals("CategoryColor") || name.Equals("TimeMarkedAs"))
                {
                    list = GetViewsFromAll(app);
                    for (int i = 0; i < list.Count; i++)
                        list[i].Refresh();
                }
                else if (name.Equals("OwnerKey"))
                {
                    if (_View.CalendarView.IsMultiCalendar == true)
                    {
                        if (_View.OwnerKey == app.OwnerKey)
                        {
                            RefreshData();
                            _View.NeedRecalcSize = true;
                            _View.Refresh();
                        }
                        else
                        {
                            list = GetViewsFromAll(app);
                            if (list.Count > 0)
                            {
                                RefreshData();
                                _View.NeedRecalcSize = true;
                                _View.Refresh();
                            }
                        }
                    }
                }
                else if (name.Equals("Visible"))
                {
                    RefreshData();
                }
            }
        }
        #endregion
        #region CustomItems_CollectionChanged
        void CustomItemsCollectionChanged(object sender, EventArgs e)
        {
            RefreshData();
            _View.NeedRecalcSize = true;
            _View.Refresh();
        }
        #endregion
    }
}
#endif