#if FRAMEWORK20
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using DevComponents.Schedule.Model;
namespace DevComponents.DotNetBar.Schedule
{
    public class YearView : BaseView
    {
        #region Constants
        private const int MaxNumberOfMonths = 120;
        #endregion
        #region Private variables
        private YearMonth[] _YearMonths;        // Array of YearMonths
        private int _NumberOfMonths;            // Number of months in display
        private int _NumberOfCols;
        private int _NumberOfRows;
        private CalendarMonthColor _ViewColor =
            new CalendarMonthColor(eCalendarColor.Automatic);
        private bool _RecalcInProgress;
        private int _MouseDownMonthIndex = -1;
        private int _MouseDownDayIndex = -1;
        private int _LastMouseDownDayIndex = -1;
        private DateTime _LastMouseUpTime = DateTime.MinValue;
        private int _VScrollPos;
        private Size _PreferredSize;
        private Size _CellSize;
        #endregion
        /// 
        /// Constructor
        /// 
        /// Parent CalendarView
        public YearView(CalendarView calendarView)
            : base(calendarView, eCalendarView.Year)
        {
            // Set our non-client drawing info and our CalendarColor
            NClientData = new NonClientData(
                eTabOrientation.Horizontal,
                (int)eCalendarMonthPart.OwnerTabBorder,
                (int)eCalendarMonthPart.OwnerTabForeground,
                (int)eCalendarMonthPart.OwnerTabBackground,
                (int)eCalendarMonthPart.OwnerTabContentBackground,
                (int)eCalendarMonthPart.OwnerTabSelectedForeground,
                (int)eCalendarMonthPart.OwnerTabSelectedBackground);
            CalendarColorTable = _ViewColor;
            // Hook onto needed event
            HookEvents(true);
        }
        #region Internal properties
        #region AllowDateSelection
        /// 
        /// Gets whether date selections are permitted
        /// 
        internal bool AllowDateSelection
        {
            get { return (CalendarView.YearViewAllowDateSelection); }
        }
        #endregion
        #region CellSize
        /// 
        /// Gets the default day cell size
        /// 
        internal Size CellSize
        {
            get
            {
                if (_CellSize.IsEmpty)
                {
                    Control container = GetContainerControl(true) as Control;
                    if (container != null)
                    {
                        using (Graphics g = BarFunctions.CreateGraphics(container))
                            _CellSize = g.MeasureString("00", Font).ToSize();
                    }
                }
                return (_CellSize);
            }
        }
        #endregion
        #region ShowGridLines
        /// 
        /// Gets whether Grid lines are to be displayed
        /// 
        internal bool ShowGridLines
        {
            get { return (CalendarView.YearViewShowGridLines); }
        }
        #endregion
        #region YearViewAppointmentLink
        /// 
        /// Gets the Appointment Link click style
        /// 
        internal eYearViewDayLink YearViewAppointmentLink
        {
            get { return (CalendarView.YearViewAppointmentLink); }
        }
        #endregion
        #region YearViewNonAppointmentLink
        /// 
        /// Gets the non-Appointment Link click style
        /// 
        internal eYearViewDayLink YearViewNonAppointmentLink
        {
            get { return (CalendarView.YearViewNonAppointmentLink); }
        }
        #endregion
        #region ViewColor
        /// 
        /// Gets the Month Color table
        /// 
        internal CalendarMonthColor ViewColor
        {
            get { return (_ViewColor); }
        }
        #endregion
        #region VsPanel
        /// 
        /// Gets the Year vertical scroll panel
        /// 
        private VScrollPanel VsPanel
        {
            get { return (CalendarView.YearVScrollPanel); }
        }
        #endregion
        #endregion
        #region Public properties
        #region Font
        /// 
        /// Gets or sets the display font
        /// 
        [Category("Behavior")]
        [Description("Indicates the display font.")]
        public override Font Font
        {
            get { return (base.Font ?? CalendarView.Font); }
            set
            {
                base.Font = value;
                if (DaysOfTheWeek != null)
                    DaysOfTheWeek.NeedsMeasured = true;
                _CellSize = Size.Empty;
                _PreferredSize = Size.Empty;
            }
        }
        #endregion
        #region YearMonths
        /// 
        /// Gets the array of YearMonths
        /// 
        public YearMonth[] YearMonths
        {
            get { return (_YearMonths); }
        }
        #endregion
        #endregion
        #region HookEvents
        /// 
        /// Hooks (or unhooks) needed events
        /// 
        /// True to hook, false to unhook
        private void HookEvents(bool hook)
        {
            if (hook == true)
            {
                CalendarView.SelectedViewChanged += SelectedViewChanged;
                CalendarView.YearViewStartDateChanged += YearViewStartDateChanged;
                CalendarView.YearViewEndDateChanged += YearViewEndDateChanged;
                CalendarView.YearViewShowGridLinesChanged += YearViewShowGridLinesChanged;
                CalendarView.YearViewAllowDateSelectionChanged += YearViewAllowDateSelectionChanged;
                CalendarView.YearVScrollPanel.ScrollBarChanged += VScrollPanelScrollBarChanged;
            }
            else
            {
                CalendarView.SelectedViewChanged -= SelectedViewChanged;
                CalendarView.YearViewStartDateChanged -= YearViewStartDateChanged;
                CalendarView.YearViewEndDateChanged -= YearViewEndDateChanged;
                CalendarView.YearViewShowGridLinesChanged -= YearViewShowGridLinesChanged;
                CalendarView.YearViewAllowDateSelectionChanged -= YearViewAllowDateSelectionChanged;
                CalendarView.YearVScrollPanel.ScrollBarChanged -= VScrollPanelScrollBarChanged;
            }
        }
        #endregion
        #region Event handling
        #region SelectedViewChanged
        /// 
        /// Processes CalendarView SelectedViewChanged events
        /// 
        /// CalendarView
        /// SelectedViewEventArgs
        void SelectedViewChanged(object sender, SelectedViewEventArgs e)
        {
            IsViewSelected = (e.NewValue == eCalendarView.Year);
            if (IsViewSelected == true && Displayed == true)
            {
                AutoSyncViewDate(e.OldValue);
                UpdateView();
                UpdateDateSelection();
            }
            else
            {
                ResetView();
            }
        }
        #endregion
        #region YearViewStartDateChanged
        /// 
        /// Processes StartDate changes
        /// 
        /// 
        /// 
        void YearViewStartDateChanged(object sender, DateChangeEventArgs e)
        {
            StartDate = e.NewValue;
        }
        #endregion
        #region YearViewEndDateChanged
        /// 
        /// Processes EndDate changes
        /// 
        /// 
        /// 
        void YearViewEndDateChanged(object sender, DateChangeEventArgs e)
        {
            EndDate = e.NewValue;
        }
        #endregion
        #region YearViewAllowDateSelectionChanged
        /// 
        /// Handles YearViewAllowDateSelectionChanged events
        /// 
        /// 
        /// 
        void YearViewAllowDateSelectionChanged(object sender, AllowDateSelectionChangedEventArgs e)
        {
            Refresh();
        }
        #endregion
        #region YearViewShowGridLinesChanged
        /// 
        /// Processes CalendarView YearViewShowGridLinesChanged events
        /// 
        /// CalendarView
        /// SelectedViewEventArgs
        void YearViewShowGridLinesChanged(object sender, ShowGridLinesChangedEventArgs e)
        {
            Refresh();
        }
        #endregion
        #region VScrollPanel_ScrollBarChanged
        /// 
        /// Handles ScrollBarChanged events
        /// 
        /// 
        /// 
        void VScrollPanelScrollBarChanged(object sender, EventArgs e)
        {
            int vdelta = -VsPanel.ScrollBar.Value - _VScrollPos;
            if (vdelta != 0)
            {
                _VScrollPos = -VsPanel.ScrollBar.Value;
                
                // Offset our DayColumn accordingly
                for (int i = 0; i < _NumberOfMonths; i++)
                {
                    YearMonth ym = _YearMonths[i];
                    Rectangle r = ym.Bounds;
                    r.Y += vdelta;
                    ym.Bounds = r;
                }
                // Redraw our view
                InvalidateRect();
            }
        }
        #endregion
        #endregion
        #region GetViewAreaFromPoint
        /// 
        /// Gets the view area under the given mouse
        /// point (tab, header, content, etc)
        /// 
        /// Point
        /// eViewArea
        public override eViewArea GetViewAreaFromPoint(Point pt)
        {
            if (Bounds.Contains(pt) == true)
            {
                if (ClientRect.Contains(pt))
                {
                    for (int i = 0; i < _NumberOfMonths; i++)
                    {
                        eViewArea area = _YearMonths[i].GetViewAreaFromPoint(pt);
                        if (area != eViewArea.NotInView)
                            return (area);
                    }
                    return (eViewArea.NotInView);
                }
                return (base.GetViewAreaFromPoint(pt));
            }
            return (eViewArea.NotInView);
        }
        #endregion
        #region GetDateSelectionFromPoint
        /// 
        /// Gets the date selection from the given point.
        /// 
        /// Point in question
        /// out start date
        /// out end date
        /// True if a valid selection exists
        /// at the given point
        public override bool GetDateSelectionFromPoint(
            Point pt, out DateTime startDate, out DateTime endDate)
        {
            base.GetDateSelectionFromPoint(pt, out startDate, out endDate);
            int monthIndex = GetMonthIndexFromPoint(pt);
            if (monthIndex >= 0)
            {
                if (_YearMonths[monthIndex].GetDateFromPoint(pt, ref startDate))
                {
                    endDate = startDate.AddDays(1);
                    return (true);
                }
            }
            return (false);
        }
        #endregion
        #region UpdateDateSelection
        /// 
        /// Updates each monthWeeks DayRects to reflect
        /// the date selection start and end values
        /// 
        protected override void UpdateDateSelection()
        {
            if (IsViewSelected == true)
            {
                // Loop through each month, setting
                // the selection status according to the date
                // selection range
                for (int i = 0; i < _NumberOfMonths; i++)
                    _YearMonths[i].UpdateDateSelection();
            }
        }
        #endregion
        #region RecalcSize routines
        /// 
        /// Performs NeedRecalcSize requests
        /// 
        public override void RecalcSize()
        {
            if (_RecalcInProgress == false)
            {
                try
                {
                    _RecalcInProgress = true;
                    RecalcDisplaySize();
                }
                finally
                {
                    _RecalcInProgress = false;
                }
            }
        }
        #region RecalcDisplaySize
        /// 
        /// Performs all necessary recalc operations
        /// 
        private void RecalcDisplaySize()
        {
            base.RecalcSize();
            if (IsViewSelected == true)
            {
                // Normalize our start and end dates
                DateTime startDate;
                DateTime endDate;
                NormalizeDates(out startDate, out endDate);
                // Calculate each months display info and then
                // initiate a YearMonth layout 
                CalcYearMonths(startDate, endDate);
                LayoutYearMonths(startDate);
                // Update our Model connection and views
                UpdateView();
                UpdateDateSelection();
                NeedRecalcLayout = false;
            }
        }
        #endregion
        #region NormalizeDates
        /// 
        /// Normalizes the user specified start and end dates
        /// 
        /// [out] Normalized start date
        /// [out] Normalized end date
        private void NormalizeDates(out DateTime startDate, out DateTime endDate)
        {
            startDate = this.StartDate.Date;
            endDate = this.EndDate.Date;
            // If both values are unset, then set them to
            // today's date / + 12 months
            if (startDate == DateTime.MinValue && endDate == DateTime.MinValue)
            {
                startDate = DateTime.Today.AddDays(-(DateTime.Today.Day - 1));
                endDate = startDate.AddMonths(12).AddDays(-1);
            }
            if (DaysOfTheWeek == null)
                DaysOfTheWeek = new DaysOfTheWeek();
        }
        #endregion
        #region Update View
        /// 
        /// Updates our connection model view
        /// 
        private void UpdateView()
        {
            // If we have had a date range change, just
            // reset our entire view
            if (DateRangeChanged == true)
                ResetView();
            // If we have no Model connection, attempt
            // to reconnect if this view is selected
            if (Connector == null)
            {
                if (CalendarModel != null)
                {
                    Connector = new ModelYearViewConnector(CalendarModel, this);
                    CalendarView.DoViewLoadComplete(this);
                }
            }
        }
        #endregion
        #region ResetView
        /// 
        /// Disconnects and resets the Model connection
        /// 
        internal override void ResetView()
        {
            base.ResetView();
            ModelYearViewConnector.ResetModelData();
        }
        #endregion
        #region CalcYearMonths
        /// 
        /// Calculates display info for the YearMonth data
        /// 
        /// Start date
        /// End date
        private void CalcYearMonths(DateTime startDate, DateTime endDate)
        {
            // Get the number of months for the date range
            _NumberOfMonths = (endDate.Year * 12 + endDate.Month) -
                (startDate.Year * 12 + startDate.Month) + 1;
            _NumberOfMonths = Math.Max(1, _NumberOfMonths);
            _NumberOfMonths = Math.Min(_NumberOfMonths, MaxNumberOfMonths);
            // Allocate our MonthWeeks array to
            // hold our weeks info
            if (_YearMonths == null || _YearMonths.Length != _NumberOfMonths)
                _YearMonths = new YearMonth[_NumberOfMonths];
        }
        #endregion
        #region LayoutYearMonths
        /// 
        /// Performs size and positioning layout for the control
        /// 
        /// 
        private void LayoutYearMonths(DateTime startDate)
        {
            Size size = GetPreferredSize(startDate);
            if (size.Width > 0 && size.Height > 0)
            {
                int maxCols = Math.Max(1, (ClientRect.Width - 1) / size.Width);
                int maxRows = Math.Max(1, (ClientRect.Height - 1) / size.Height);
                int targetCols = (int)Math.Ceiling(Math.Sqrt(_NumberOfMonths));
                if (targetCols >= maxCols)
                {
                    targetCols = maxCols;
                }
                else
                {
                    while (targetCols < maxCols)
                    {
                        int targetRows =
                            Math.Max(1, (_NumberOfMonths + targetCols - 1) / targetCols);
                        if (targetRows <= maxRows)
                            break;
                        targetCols++;
                    }
                }
                _NumberOfRows = Math.Max(1, (_NumberOfMonths + targetCols - 1) / targetCols);
                _NumberOfCols = (_NumberOfMonths + _NumberOfRows - 1) / _NumberOfRows;
                int monthHeight = (ClientRect.Height - 1) / _NumberOfRows;
                int monthWidth = (ClientRect.Width - 1) / _NumberOfCols;
                int rowSpread = 0;
                if (monthHeight < size.Height)
                    monthHeight = size.Height;
                else
                    rowSpread = ClientRect.Height - (_NumberOfRows * monthHeight) - 1;
                int colSpread = 0;
                if (monthWidth < size.Width)
                    monthWidth = size.Width;
                else
                    colSpread = ClientRect.Width - (_NumberOfCols * monthWidth) - 1;
                // Loop through each week
                int n = 0;
                DateTime date = startDate;
                Rectangle r = new Rectangle(ClientRect.X, ClientRect.Y, monthWidth, monthHeight);
                r.Y += _VScrollPos;
                for (int i = 0; i < _NumberOfRows; i++)
                {
                    if (i < rowSpread)
                        r.Height++;
                    for (int j = 0; j < _NumberOfCols; j++)
                    {
                        if (n >= _NumberOfMonths)
                            break;
                        if (_YearMonths[n] == null)
                            _YearMonths[n] = new YearMonth(this, date);
                        else
                            _YearMonths[n].StartDate = date;
                        // Calculate the bounding rect limits
                        r.Width = monthWidth;
                        
                        if (j < colSpread)
                            r.Width++;
                        // Set the bounding rect
                        _YearMonths[n].Bounds = r;
                        r.X += r.Width;
                        n++;
                        date = date.AddMonths(1);
                    }
                    r.X = ClientRect.X;
                    r.Y += r.Height;
                    r.Height = monthHeight;
                }
                CalendarView.YearViewMax = (r.Y - (ClientRect.Y + _VScrollPos));
            }
        }
        #endregion
        #region GetPreferredSize
        /// 
        /// Gets the preferred size of the control
        /// 
        /// 
        /// 
        private Size GetPreferredSize(DateTime startDate)
        {
            if (_PreferredSize.IsEmpty)
            {
                if (_YearMonths[0] == null)
                    _YearMonths[0] = new YearMonth(this, startDate);
                _PreferredSize = _YearMonths[0].GetPreferredSize();
            }
            return (_PreferredSize);
        }
        #endregion
        #endregion
        #region Paint processing
        #region Root paint code
        /// 
        /// Paint processing
        /// 
        /// ItemPaintArgs
        public override void Paint(ItemPaintArgs e)
        {
            // Set our current color table
            _ViewColor.SetColorTable();
            // Only draw something if we have something to draw
            if (_NumberOfMonths > 0)
            {
                // Calculate our drawing ranges
                int colStart, colEnd;
                int rowStart, rowEnd;
                int colCount = GetColRange(e, out colStart, out colEnd);
                int rowCount = GetRowRange(e, out rowStart, out rowEnd);
                // Draw our calendar parts
                if (colCount > 0 && rowCount > 0)
                    DrawContent(e, rowStart, rowEnd, colStart, colEnd);
            }
            // Let the base painting take place
            base.Paint(e);
        }
        #endregion
        #region DrawContent
        /// 
        /// Draws YearMonth header and content
        /// 
        /// ItemPaintArgs
        /// Row start index
        /// Row end index
        /// Col start index
        /// Col end index
        private void DrawContent(ItemPaintArgs e,
            int rowStart, int rowEnd, int colStart, int colEnd)
        {
            Graphics g = e.Graphics;
            // Set our clipping region
            Rectangle r = ClientRect;
            r.X = ClientRect.X;
            r.Width = ClientRect.Width;
            Region regSave = g.Clip;
            g.SetClip(r, CombineMode.Intersect);
            // Loop through each day in each week, displaying
            // the associated day content and header
            DateTime date = DateTime.Now;
            int nowMonth = -1;
            for (int i = rowStart; i <= rowEnd; i++)
            {
                for (int j = colStart; j <= colEnd; j++)
                {
                    int n = (i * _NumberOfCols) + j;
                    if (n < _NumberOfMonths)
                    {
                        YearMonth ym = _YearMonths[n];
                        bool now = CalendarView.HighlightCurrentDay == true &&
                            ym.StartDate.Month == date.Month && ym.StartDate.Year == date.Year;
                        if (now == true)
                            nowMonth = n;
                        else
                            ym.Paint(e, false);
                    }
                }
            }
            if (nowMonth >= 0)
                _YearMonths[nowMonth].Paint(e, true);
            // Restore our original clip region
            g.Clip = regSave;
        }
        #endregion
        #region GetRange
        #region GetColRange
        /// 
        /// Calculates the range of columns needed to be drawn
        /// to satisfy the specified paint request
        /// 
        /// ItemPaintArgs
        /// [out] Col start index
        /// [out] COl end index
        /// Col range count (end - start)
        private int GetColRange(ItemPaintArgs e, out int colStart, out int colEnd)
        {
            // Calc our starting index
            int nCols = Math.Min(_NumberOfMonths, _NumberOfCols);
            int start = 0;
            while (start < nCols)
            {
                Rectangle dr1 = _YearMonths[start].Bounds;
                if (dr1.Right > e.ClipRectangle.X)
                    break;
                start++;
            }
            // Calc our ending index
            int end = start;
            while (end < nCols)
            {
                Rectangle dr2 = _YearMonths[end].Bounds;
                if (dr2.X >= e.ClipRectangle.Right)
                    break;
                end++;
            }
            // Set the user supplied 'out' values, and
            // return the range count to the caller
            if (end - start == 0)
            {
                colStart = 0;
                colEnd = 0;
                return (0);
            }
            colStart = start;
            colEnd = end - 1;
            return (end - start);
        }
        #endregion
        #region GetRowRange
        /// 
        /// Calculates the range of rows needed to be drawn
        /// to satisfy the specified paint request
        /// 
        /// ItemPaintArgs
        /// [out] Row start index
        /// [out] Row end index
        /// Row range count (end - start)
        private int GetRowRange(ItemPaintArgs e, out int rowStart, out int rowEnd)
        {
            // Calc our starting index
            int start = 0;
            while (start < _NumberOfRows)
            {
                if (_YearMonths[start * _NumberOfCols].Bounds.Bottom > e.ClipRectangle.Y)
                    break;
                start++;
            }
            // Calc our ending index
            int end = start;
            while (end < _NumberOfRows)
            {
                if (_YearMonths[end * _NumberOfCols].Bounds.Y >= e.ClipRectangle.Bottom)
                    break;
                end++;
            }
            // Set the user supplied 'out' values, and
            // return the range count to the caller
            if (end - start == 0)
            {
                rowStart = 0;
                rowEnd = 0;
                return (0);
            }
            rowStart = start;
            rowEnd = end - 1;
            return (end - start);
        }
        #endregion
        #endregion
        #endregion
        #region MouseMove processing
        /// 
        /// MouseMove event processing
        /// 
        /// MouseEventArgs
        public override void InternalMouseMove(MouseEventArgs objArg)
        {
            // Forward on the event, but only if we are not in
            // the middle of moving or resizing a CalendarItem
            if (Control.MouseButtons == MouseButtons.None)
                ClearMouseStates();
            base.InternalMouseMove(objArg);
            if (IsTabMoving == false)
            {
                // Locate where the event took place
                // and process it accordingly
                int monthIndex, dayIndex, ndayIndex;
                if (GetPointItem(objArg.Location, out monthIndex, out dayIndex, out ndayIndex))
                {
                    if (objArg.Button == MouseButtons.Left)
                        ProcessMouseMove(monthIndex, ndayIndex);
                }
                // Set the cursor
                MyCursor = GetCursor(monthIndex, dayIndex, ndayIndex);
            }
        }
        #region ProcessMouseMove
        /// 
        /// Processes view mouseMove events
        /// 
        /// 
        /// 
        private void ProcessMouseMove(int monthIndex, int dayIndex)
        {
            if (AllowDateSelection == true)
            {
                if (DateSelectionAnchor != null)
                {
                    DateTime date = _YearMonths[monthIndex].GetDateFromIndex(dayIndex);
                    // Let the user select forwards or backwards
                    if (date >= DateSelectionAnchor)
                    {
                        CalendarView.DateSelectionStart = DateSelectionAnchor.Value;
                        CalendarView.DateSelectionEnd = date.AddDays(1);
                    }
                    else
                    {
                        CalendarView.DateSelectionStart = date;
                        CalendarView.DateSelectionEnd = DateSelectionAnchor.Value.AddDays(1);
                    }
                }
            }
        }
        #endregion
        #endregion
        #region MouseDown processing
        #region InternalMouseDown
        /// 
        /// MouseDown event processing
        /// 
        /// 
        public override void InternalMouseDown(MouseEventArgs objArg)
        {
            // Forward on the event
            base.InternalMouseDown(objArg);
            if (objArg.Button == MouseButtons.Left)
            {
                if (IsTabMoving == false)
                {
                    // Locate where the event took place
                    int monthIndex, dayIndex, ndayIndex;
                    if (GetPointItem(objArg.Location, out monthIndex, out dayIndex, out ndayIndex))
                    {
                        if (dayIndex == ndayIndex || 
                            (Control.ModifierKeys & Keys.Shift) == Keys.Shift)
                        {
                            ProcessMouseDown(monthIndex, ndayIndex);
                        }
                        else
                        {
                            CalendarView.DateSelectionStart = null;
                            CalendarView.DateSelectionEnd = null;
                            DateSelectionAnchor = null; 
                        }
                    }
                    MyCursor = GetCursor(monthIndex, dayIndex, ndayIndex);
                }
            }
        }
        #endregion
        #region ProcessMouseDown
        /// 
        /// Handles MonthView left MouseDown events
        /// 
        /// Month index
        /// Day index
        private void ProcessMouseDown(int monthIndex, int dayIndex)
        {
            if (AllowDateSelection == true)
            {
                DateTime startDate = _YearMonths[monthIndex].GetDateFromIndex(dayIndex);
                DateTime endDate = startDate.AddDays(1);
                ExtendSelection(ref startDate, ref endDate);
                CalendarView.DateSelectionStart = startDate;
                CalendarView.DateSelectionEnd = endDate;
            }
            _MouseDownMonthIndex = monthIndex;
            _MouseDownDayIndex = dayIndex;
        }
        #endregion
        #endregion
        #region MouseUp processing
        #region InternalMouseUp
        /// 
        /// Handles InternalMouseUp events
        /// 
        /// 
        public override void InternalMouseUp(MouseEventArgs objArg)
        {
            // Forward on the event
            base.InternalMouseUp(objArg);
            ClearMouseStates();
            if (objArg.Button == MouseButtons.Left)
            {
                if (IsTabMoving == false)
                {
                    // Locate where the event took place
                    int monthIndex, dayIndex, ndayIndex;
                    if (GetPointItem(objArg.Location, out monthIndex, out dayIndex, out ndayIndex))
                        ProcessMouseUp(monthIndex, ndayIndex);
                    MyCursor = GetCursor(monthIndex, dayIndex, ndayIndex);
                }
            }
        }
        #endregion
        #region ProcessMouseUp
        /// 
        /// Process mouse up events
        /// 
        /// 
        /// 
        private void ProcessMouseUp(int monthIndex, int dayIndex)
        {
            // If the user is mousing-up on the same day that he
            // moused-down on, then check to see if we need to navigate
            // to a linked Calendar view
            if (_MouseDownMonthIndex == monthIndex && _MouseDownDayIndex == dayIndex)
            {
                YearMonth ym = _YearMonths[monthIndex];
                DateTime date = ym.GetDateFromIndex(dayIndex);
                eYearViewDayLink dl = (ym.DayIndexHasAppointments(dayIndex) == true)
                    ? YearViewAppointmentLink : YearViewNonAppointmentLink;
                if (((dl & eYearViewDayLink.DoubleClick) != eYearViewDayLink.DoubleClick) || _LastMouseDownDayIndex != dayIndex ||
                    _LastMouseUpTime == DateTime.MinValue ||
                    DateTime.Now.Subtract(_LastMouseUpTime).TotalMilliseconds > SystemInformation.DoubleClickTime)
                {
                    _LastMouseUpTime = DateTime.Now;
                    if ((dl & eYearViewDayLink.Click) == eYearViewDayLink.Click)
                    {
                        if ((Control.ModifierKeys & Keys.Control) != Keys.Control)
                            PerformLinkSelect(date);
                    }
                    else if ((dl & eYearViewDayLink.CtrlClick) == eYearViewDayLink.CtrlClick)
                    {
                        if ((Control.ModifierKeys & Keys.Control) == Keys.Control)
                            PerformLinkSelect(date);
                    }
                }
                else
                {
                    _LastMouseUpTime = DateTime.MinValue;
                    PerformLinkSelect(date);
                }
            }
            _LastMouseDownDayIndex = _MouseDownDayIndex;
            _MouseDownMonthIndex = -1;
            _MouseDownDayIndex = -1;
        }
        #endregion
        #region PerformLinkSelect
        /// 
        /// Performs a day link selection
        /// 
        /// 
        private void PerformLinkSelect(DateTime date)
        {
            DateTime startDate = date;
            if (CalendarView.YearViewLinkAction == eYearViewLinkAction.GoToFirstCalendarItem)
            {
                if (Connector != null)
                {
                    Appointment app = ((ModelYearViewConnector) Connector).GetFirstAppointment(date);
                    if (app != null)
                        startDate = date.Date.AddHours(app.StartTime.Hour).AddMinutes(app.StartTime.Minute);
                    CustomCalendarItem cci = ((ModelYearViewConnector) Connector).GetFirstCustomItem(date);
                    if (cci != null)
                    {
                        if (app == null || cci.StartTime < startDate)
                            startDate = date.Date.AddHours(cci.StartTime.Hour).AddMinutes(cci.StartTime.Minute);
                    }
                }
            }
            DateTime endDate = startDate;
            eCalendarView calendarView = CalendarView.YearViewLinkView;
            if (CalendarView.DoYearViewLinkSelected(ref startDate, ref endDate, ref calendarView) == false)
            {
                if (CalendarView.YearViewLinkView != eCalendarView.None &&
                    CalendarView.YearViewLinkView != eCalendarView.Year)
                {
                    CalendarView.DateSelectionStart = startDate;
                    CalendarView.DateSelectionEnd = endDate;
                    CalendarView.SelectedView = calendarView;
                    CalendarView.EnsureVisible(startDate, endDate);
                }
            }
        }
        #endregion
        #endregion
        #region InternalKeyDown
        #region InternalKeyDown
        /// 
        /// Processes KeyDown events
        /// 
        /// 
        public override void InternalKeyDown(KeyEventArgs objArg)
        {
            switch (objArg.KeyData)
            {
                case Keys.Up:
                case Keys.Up | Keys.Shift:
                case Keys.Up | Keys.Control:
                case Keys.Up | Keys.Control | Keys.Shift:
                    ProcessUpDownKey(objArg, -7);
                    break;
                case Keys.Down:
                case Keys.Down | Keys.Shift:
                case Keys.Down | Keys.Control:
                case Keys.Down | Keys.Control | Keys.Shift:
                    ProcessUpDownKey(objArg, 7);
                    break;
                case Keys.Left:
                case Keys.Left | Keys.Shift:
                case Keys.Left | Keys.Control:
                case Keys.Left | Keys.Control | Keys.Shift:
                    ProcessLeftRightKey(objArg, -1);
                    break;
                case Keys.Right:
                case Keys.Right | Keys.Shift:
                case Keys.Right | Keys.Control:
                case Keys.Right | Keys.Control | Keys.Shift:
                    ProcessLeftRightKey(objArg, 1);
                    break;
                case Keys.Home:
                case Keys.Home | Keys.Shift:
                case Keys.Home | Keys.Control:
                case Keys.Home | Keys.Control | Keys.Shift:
                    ProcessHomeKey(objArg);
                    break;
                case Keys.End:
                case Keys.End | Keys.Shift:
                case Keys.End | Keys.Control:
                case Keys.End | Keys.Control | Keys.Shift:
                    ProcessEndKey(objArg);
                    break;
                case Keys.LButton | Keys.ShiftKey | Keys.Control:
                    ProcessControlKey();
                    break;
                case Keys.Enter:
                case Keys.Space:
                    ProcessEnterKey();
                    break;
                case Keys.PageUp:
                case Keys.PageUp | Keys.Shift:
                case Keys.PageUp | Keys.Control:
                case Keys.PageUp | Keys.Control | Keys.Shift:
                    ProcessUpDownKey(objArg, -7);
                    break;
                case Keys.PageDown:
                case Keys.PageDown | Keys.Shift:
                case Keys.PageDown | Keys.Control:
                case Keys.PageDown | Keys.Control | Keys.Shift:
                    ProcessUpDownKey(objArg, 7);
                    break;
            }
        }
        #endregion
        #region ProcessUpDownKey
        /// 
        /// Processes Up and Down Key events
        /// 
        /// 
        /// 
        protected virtual void ProcessUpDownKey(KeyEventArgs objArg, int dy)
        {
            if (ValidDateSelection())
            {
                DateTime startDate = CalendarView.DateSelectionStart.Value;
                DateTime endDate = CalendarView.DateSelectionEnd.Value;
                if (DateSelectionAnchor != null)
                {
                    if (startDate.Equals(DateSelectionAnchor.Value) == true)
                        startDate = endDate.AddDays(-1);
                }
                startDate = startDate.AddDays(dy);
                endDate = startDate.AddDays(1);
                ExtendSelection(ref startDate, ref endDate);
                CalendarView.DateSelectionStart = startDate;
                CalendarView.DateSelectionEnd = endDate;
            }
            objArg.Handled = true;
        }
        #endregion
        #region ProcessLeftRightKey
        /// 
        /// Processes Left and Right key events
        /// 
        /// 
        /// 
        protected virtual void ProcessLeftRightKey(KeyEventArgs objArg, int dx)
        {
            if (ValidDateSelection())
            {
                DateTime startDate = CalendarView.DateSelectionStart.Value;
                DateTime endDate = CalendarView.DateSelectionEnd.Value;
                if (DateSelectionAnchor != null)
                {
                    if (startDate.Equals(DateSelectionAnchor.Value) == true)
                        startDate = endDate.AddDays(-1);
                }
                startDate = startDate.AddDays(dx);
                endDate = startDate.AddDays(1);
                ExtendSelection(ref startDate, ref endDate);
                CalendarView.DateSelectionStart = startDate;
                CalendarView.DateSelectionEnd = endDate;
            }
            objArg.Handled = true;
        }
        #endregion
        #region ProcessHomeKey
        /// 
        /// Processes Hoe key events
        /// 
        /// 
        protected virtual void ProcessHomeKey(KeyEventArgs objArg)
        {
            int monthIndex = ((objArg.Modifiers & Keys.Control) != Keys.Control)
                                 ? GetHomeEndMonth()
                                 : 0;
            if (monthIndex >= 0)
            {
                DateTime startDate = _YearMonths[monthIndex].StartDate;
                DateTime endDate = startDate.AddDays(1);
                ExtendSelection(ref startDate, ref endDate);
                CalendarView.DateSelectionStart = startDate;
                CalendarView.DateSelectionEnd = endDate;
                SelectedItem = null;
            }
            objArg.Handled = true;
        }
        #endregion
        #region ProcessEndKey
        /// 
        /// Processes End key events
        /// 
        /// 
        protected virtual void ProcessEndKey(KeyEventArgs objArg)
        {
            int monthIndex = ((objArg.Modifiers & Keys.Control) != Keys.Control)
                                 ? GetHomeEndMonth()
                                 : _NumberOfMonths - 1;
            if (monthIndex >= 0)
            {
                DateTime startDate = _YearMonths[monthIndex].EndDate;
                DateTime endDate = startDate.AddDays(1);
                ExtendSelection(ref startDate, ref endDate);
                CalendarView.DateSelectionStart = startDate;
                CalendarView.DateSelectionEnd = endDate;
                SelectedItem = null;
            }
            objArg.Handled = true;
        }
        #endregion
        #region ProcessControlKey
        private void ProcessControlKey()
        {
            Point pt = Control.MousePosition;
            Control container = GetContainerControl(true) as Control;
            if (container != null)
            {
                pt = container.PointToClient(pt);
                CalendarView.CalendarPanel.InternalMouseMove(new
                    MouseEventArgs(MouseButtons.None, 0, pt.X, pt.Y, 0));
            }
        }
        #endregion
        #region ProcessEnterKey
        private void ProcessEnterKey()
        {
            if (ValidDateSelection())
            {
                TimeSpan ts = CalendarView.DateSelectionEnd.Value -
                    CalendarView.DateSelectionStart.Value;
                if (ts.Days == 1)
                    PerformLinkSelect(CalendarView.DateSelectionStart.Value);
            }
        }
        #endregion
        #region GetMonthFromDate
        /// 
        /// Gets the month containing the given date
        /// 
        /// 
        /// MonthIndex or -1
        private int GetMonthFromDate(DateTime date)
        {
            for (int i = 0; i < _NumberOfMonths; i++)
            {
                YearMonth ym = _YearMonths[i];
                if (ym.ContainsDate(date))
                    return (i);
            }
            return (-1);
        }
        #endregion
        #region GetHomeEndMonth
        /// 
        /// Gets the Home and End month from the
        /// current selection range
        /// 
        /// 
        private int GetHomeEndMonth()
        {
            if (ValidDateSelection() == true)
            {
                if (CalendarView.DateSelectionStart.Equals(DateSelectionAnchor.Value) == true)
                    return (GetMonthFromDate(DateSelectionEnd.Value.AddDays(-1)));
                return (GetMonthFromDate(DateSelectionStart.Value));
            }
            return (-1);
        }
        #endregion
        #endregion
        #region InternalKeyUp
        /// 
        /// InternalKeyUp
        /// 
        /// 
        internal override void InternalKeyUp(KeyEventArgs e)
        {
            base.InternalKeyUp(e);
            switch (e.KeyData)
            {
                case Keys.LButton | Keys.ShiftKey:
                    ProcessControlKey();
                    break;
            }
        }
        #endregion
        #region GetCursor
        /// 
        /// Gets the cursor
        /// 
        /// Cursor
        private Cursor GetCursor(int monthIndex, int dayIndex, int ndayIndex)
        {
            if (monthIndex >= 0 && dayIndex >= 0 && dayIndex == ndayIndex)
            {
                if (_MouseDownMonthIndex < 0 ||
                    (_MouseDownMonthIndex == monthIndex && _MouseDownDayIndex == dayIndex))
                {
                    YearMonth ym = _YearMonths[monthIndex];
                    eYearViewDayLink dl = (ym.DayIndexHasAppointments(dayIndex) == true)
                                              ? YearViewAppointmentLink
                                              : YearViewNonAppointmentLink;
                    if ((dl & eYearViewDayLink.Click) == eYearViewDayLink.Click)
                    {
                        if ((Control.ModifierKeys & Keys.Control) != Keys.Control)
                            return (Cursors.Hand);
                    }
                    else if ((dl & eYearViewDayLink.CtrlClick) == eYearViewDayLink.CtrlClick)
                    {
                        if ((Control.ModifierKeys & Keys.Control) == Keys.Control)
                            return (Cursors.Hand);
                    }
                }
            }
            return (DefaultCursor);
        }
        #endregion
        #region GetPointItem
        /// 
        /// Gets the month and dey index for the given Point
        /// 
        /// 
        /// Month index
        /// Day index
        /// Normalized day index
        /// 
        private bool GetPointItem(Point pt,
            out int monthIndex, out int dayIndex, out int ndayIndex)
        {
            monthIndex = GetMonthIndexFromPoint(pt);
            if (monthIndex >= 0)
            {
                YearMonth ym = _YearMonths[monthIndex];
                dayIndex = ym.GetDayIndexFromPoint(pt);
                ndayIndex = ym.GetNormalizedDayIndex(dayIndex);
            }
            else
            {
                dayIndex = -1;
                ndayIndex = -1;
            }
            return (dayIndex >= 0);
        }
        #endregion
        #region GetMonthIndexFromPoint
        /// 
        /// Gets the month index from the given point
        /// 
        /// Point
        /// month index or -1
        private int GetMonthIndexFromPoint(Point pt)
        {
            for (int i = 0; i < _NumberOfMonths; i++)
            {
                if (_YearMonths[i].Bounds.Contains(pt))
                    return (i);
            }
            return (-1);
        }
        #endregion
        #region IDisposable Members
        protected override void Dispose(bool disposing)
        {
            if (disposing == true && IsDisposed == false)
            {
                ResetView();
                HookEvents(false);
            }
            base.Dispose(disposing);
        }
        #endregion
        #region Copy object
        /// 
        /// Returns copy of the item.
        /// 
        public override BaseItem Copy()
        {
            YearView objCopy = new YearView(this.CalendarView);
            CopyToItem(objCopy);
            return (objCopy);
        }
        /// 
        /// Copies the YearView specific properties to new instance of the item.
        /// 
        /// New YearView instance
        protected override void CopyToItem(BaseItem copy)
        {
            YearView objCopy = copy as YearView;
            if (objCopy != null)
                base.CopyToItem(objCopy);
        }
        #endregion
    }
}
#endif