#if FRAMEWORK20
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace DevComponents.DotNetBar.Schedule
{
    public class TimeRulerPanel : BaseItem
    {
        #region Private Variables
        private CalendarView _CalendarView;         // Assoc CalendarView
        private int _VScrollPos;                    // Vertical scroll position
        private TimeRulerColor _ViewColor =         // View display color table
            new TimeRulerColor();
        #endregion
        /// 
        /// Constructor
        /// 
        /// 
        public TimeRulerPanel(CalendarView calendarView)
        {
            _CalendarView = calendarView;
            Name = "TimeRulerPanel";
            HookEvents(true);
        }
        #region Private properties
        #region General display properties
        /// 
        /// Gets the TimeRuler font
        /// 
        private Font TimeRulerFont
        {
            get { return (_CalendarView.TimeRulerFont); }
        }
        /// 
        /// Gets the TimeRuler font (small)
        /// 
        private Font TimeRulerFontSm
        {
            get { return (_CalendarView.TimeRulerFontSm); }
        }
        #endregion
        #region Time Slice Properties
        /// 
        /// Gets the default Time Slice height
        /// 
        private float TimeSliceHeight
        {
            get { return (_CalendarView.TimeSliceHeight); }
        }
        /// 
        /// Gets the TimeSlotDuration
        /// 
        private int TimeSlotDuration
        {
            get { return (_CalendarView.TimeSlotDuration); }
        }
        /// 
        /// Gets the SlotsPerHour
        /// 
        private int SlotsPerHour
        {
            get { return (_CalendarView.SlotsPerHour); }
        }
        /// 
        /// Gets the NumberOfSlices
        /// 
        private int NumberOfSlices
        {
            get { return (_CalendarView.NumberOfSlices); }
        }
        /// 
        /// Gets the starting Time Slice
        /// 
        private int StartSlice
        {
            get { return (_CalendarView.StartSlice); }
        }
        #endregion
        #region AM / PM designators
        /// 
        /// Gets the culturally correct AM time designator
        /// 
        private string AmDesignator
        {
            get
            {
                return (ScheduleSettings.GetActiveCulture().
                    DateTimeFormat.AMDesignator.ToLower());
            }
        }
        /// 
        /// Gets the culturally correct PM time designator
        /// 
        private string PmDesignator
        {
            get
            {
                return (ScheduleSettings.GetActiveCulture().
                    DateTimeFormat.PMDesignator.ToLower());
            }
        }
        #endregion
        #endregion
        #region Hook / Unhook Events
        /// 
        /// Routine hooks all necessary events for this control
        /// 
        /// True to hook, false to unhook
        private void HookEvents(bool hook)
        {
            if (hook == true)
            {
                _CalendarView.LabelTimeSlotsChanged += CalendarView_LabelTimeSlotsChanged;
                _CalendarView.Is24HourFormatChanged += CalendarView_Is24HourFormatChanged;
                _CalendarView.TimeSlotDurationChanged += CalendarView_TimeSlotDurationChanged;
                _CalendarView.TimeIndicatorsChanged += CalendarView_TimeIndicatorsChanged;
                _CalendarView.TimeIndicatorTimeChanged += CalendarView_TimeIndicatorTimeChanged;
                _CalendarView.WeekDayVScrollPanel.ScrollBarChanged +=  VScrollPanel_ScrollBarChanged;
            }
            else
            {
                _CalendarView.LabelTimeSlotsChanged -= CalendarView_LabelTimeSlotsChanged;
                _CalendarView.Is24HourFormatChanged -= CalendarView_Is24HourFormatChanged;
                _CalendarView.TimeSlotDurationChanged -= CalendarView_TimeSlotDurationChanged;
                _CalendarView.TimeIndicatorsChanged -= CalendarView_TimeIndicatorsChanged;
                _CalendarView.TimeIndicatorTimeChanged -= CalendarView_TimeIndicatorTimeChanged;
                _CalendarView.WeekDayVScrollPanel.ScrollBarChanged -= VScrollPanel_ScrollBarChanged;
            }
        }
        #endregion
        #region Event Processing
        #region CalendarView_LabelTimeSlotsChanged
        /// 
        /// Processes LabelTimeSlotsChanged events
        /// 
        /// 
        /// 
        void CalendarView_LabelTimeSlotsChanged(
            object sender, LabelTimeSlotsChangedEventArgs e)
        {
            Refresh();
        }
        #endregion
        #region CalendarView_Is24HourFormatChanged
        /// 
        /// Processes Is24HourFormatChanged events
        /// 
        /// 
        /// 
        void CalendarView_Is24HourFormatChanged(
            object sender, Is24HourFormatChangedEventArgs e)
        {
            Refresh();
        }
        #endregion
        #region CalendarView_TimeSlotDurationChanged
        /// 
        /// Processes TimeSlotDurationChanged events
        /// 
        /// 
        /// 
        void CalendarView_TimeSlotDurationChanged(
            object sender, TimeSlotDurationChangedEventArgs e)
        {
            Refresh();
        }
        #endregion
        #region CalendarView_TimeIndicatorsChanged
        /// 
        /// Processes CalendarView_TimeIndicatorsChanged events
        /// 
        /// 
        /// 
        void CalendarView_TimeIndicatorsChanged(object sender, EventArgs e)
        {
            Refresh();
        }
        #endregion
        #region CalendarView_TimeIndicatorTimeChanged
        /// 
        /// Processes CalendarView_TimeIndicatorTimeChanged events
        /// 
        /// 
        /// 
        void CalendarView_TimeIndicatorTimeChanged(
            object sender, TimeIndicatorTimeChangedEventArgs e)
        {
            Refresh();
        }
        #endregion
        #region VScrollPanel_ScrollBarChanged
        void VScrollPanel_ScrollBarChanged(object sender, EventArgs e)
        {
            Refresh();
            Rectangle r = Bounds;
            r.Y = _CalendarView.WeekDayVScrollPanel.Bounds.Y;
            r.Height = _CalendarView.WeekDayVScrollPanel.Bounds.Height;
            Bounds = r;
            _VScrollPos = -_CalendarView.WeekDayVScrollPanel.ScrollBar.Value;
            Refresh();
        }
        #endregion
        #endregion
        #region Paint processing
        /// 
        /// Paint processing routine
        /// 
        /// 
        public override void Paint(ItemPaintArgs e)
        {
            int sliceStart, sliceEnd;
            int sliceCount = GetSliceRange(e, out sliceStart, out sliceEnd);
            if (sliceCount > 0)
            {
                _ViewColor.SetColorTable();
                DrawTimeRuler(e, sliceStart, sliceEnd);
            }
        }
        #region Slice Support Routines
        /// 
        /// Calculates the range of slices needed to be drawn
        /// to satisfy the specified paint request
        /// 
        /// ItemPaintArgs
        /// [out] Slice start index
        /// [out] Slice end index
        /// Slice range count (end - start)
        internal int GetSliceRange(ItemPaintArgs e, out int sliceStart, out int sliceEnd)
        {
            // Calc our starting index
            int start = 0;
            while (start < NumberOfSlices)
            {
                Rectangle r = GetSliceRect(start);
                if (r.Bottom > Bounds.Top)
                {
                    if (r.Bottom > e.ClipRectangle.Y)
                        break;
                }
                start++;
            }
            // Calc our ending index
            int end = start;
            while (end < NumberOfSlices)
            {
                Rectangle r = GetSliceRect(end);
                
                if (r.Y >= e.ClipRectangle.Bottom)
                    break;
                end++;
            }
            // Set the user supplied 'out' values, and
            // return the range count to the caller
            if (end - start == 0)
            {
                sliceStart = 0;
                sliceEnd = 0;
                return (0);
            }
            sliceStart = start;
            sliceEnd = end - 1;
            return (end - start);
        }
        /// 
        /// Gets the given slice rectangle
        /// 
        /// Slice
        /// Bounding rectangle
        private Rectangle GetSliceRect(int slice)
        {
            Rectangle r = Bounds;
            float n = slice * TimeSliceHeight;
            r.Y += (int)(n) + _VScrollPos;
            r.Height = (int)(n + TimeSliceHeight) - (int)n;
            return (r);
        }
        #endregion
        #region DrawTimeRuler
        /// 
        /// Draws the TimeRuler
        /// 
        /// ItemPaintArgs
        /// 
        /// 
        private void DrawTimeRuler(ItemPaintArgs e, int sliceStart, int sliceEnd)
        {
            Graphics g = e.Graphics;
            Region regSav = g.Clip;
            g.SetClip(Bounds);
            DrawBackGround(g);
            DrawTimeIndicators(g, sliceStart, sliceEnd);
            DrawRulerContent(g, sliceStart, sliceEnd);
            // Restore our original clip region
            g.Clip = regSav;
        }
        #endregion
        #region DrawBackGround
        /// 
        /// DrawBackGround
        /// 
        /// 
        private void DrawBackGround(Graphics g)
        {
            using (Brush br = _ViewColor.BrushPart((int)eTimeRulerPart.TimeRulerBackground, Bounds))
                g.FillRectangle(br, Bounds);
        }
        #endregion
        #region DrawTimeIndicators
        #region DrawTimeIndicators
        /// 
        /// Draws TimeIndicators
        /// 
        /// 
        /// 
        /// 
        private void DrawTimeIndicators(Graphics g, int sliceStart, int sliceEnd)
        {
            DateTime start, end;
            GetViewDates(out start, out end);
            Rectangle r = Rectangle.Union(GetSliceRect(sliceStart), GetSliceRect(sliceEnd));
            for (int i = 0; i < _CalendarView.TimeIndicators.Count; i++)
            {
                TimeIndicator ti = _CalendarView.TimeIndicators[i];
                if (ti.IndicatorArea == eTimeIndicatorArea.All ||
                    ti.IndicatorArea == eTimeIndicatorArea.Header)
                {
                    if (ti.IsVisible())
                    {
                        DateTime time = ti.IndicatorDisplayTime;
                        if (time >= start && time < end)
                            DrawTimeIndicator(g, r, ti);
                    }
                }
            }
        }
        #endregion
        #region DrawTimeIndicator
        #region DrawTimeIndicator
        /// 
        /// Draws individual TimeIndicators
        /// 
        /// 
        /// 
        /// 
        private void DrawTimeIndicator(Graphics g, Rectangle sRect, TimeIndicator ti)
        {
            Rectangle r = GetIndicatorRect(ti);
            if (r.IntersectsWith(sRect) == true)
            {
                if (r.Height > 0)
                {
                    ColorDef cdef = GetIndicatorColor(ti);
                    if (cdef != null)
                    {
                        using (Brush br = _ViewColor.BrushPart(cdef, r))
                        {
                            if (br is LinearGradientBrush)
                                ((LinearGradientBrush)br).WrapMode = WrapMode.TileFlipX;
                            g.FillRectangle(br, r);
                        }
                    }
                }
                Color color = GetIndicatorBorder(ti);
                if (color.IsEmpty == false)
                {
                    using (Pen pen = new Pen(color))
                        g.DrawLine(pen, r.X + 1, r.Bottom, r.Right - 1, r.Bottom);
                }
            }
        }
        #endregion
        #region GetIndicatorColor
        /// 
        /// Gets the Indicator Back color
        /// 
        /// 
        /// 
        private ColorDef GetIndicatorColor(TimeIndicator ti)
        {
            ColorDef cdef = ti.IndicatorColor;
            if (cdef == null || cdef.IsEmpty == true)
                cdef = _ViewColor.GetColorDef((int)eTimeRulerPart.TimeRulerIndicator);
            return (cdef);
        }
        #endregion
        #region GetIndicatorBorder
        /// 
        /// Gets the Indicator Border color
        /// 
        /// 
        /// 
        private Color GetIndicatorBorder(TimeIndicator ti)
        {
            return (ti.BorderColor.IsEmpty == false ? ti.BorderColor :
                _ViewColor.GetColor((int)eTimeRulerPart.TimeRulerIndicatorBorder));
        }
        #endregion
        #endregion
        #region GetViewDates
        /// 
        /// GetViewDates
        /// 
        /// 
        /// 
        private void GetViewDates(out DateTime start, out DateTime end)
        {
            switch (_CalendarView.SelectedView)
            {
                case eCalendarView.Day:
                    start = _CalendarView.DayViewDate;
                    end = _CalendarView.DayViewDate.AddDays(1);
                    break;
                default:
                    start = _CalendarView.WeekViewStartDate;
                    end = _CalendarView.WeekViewEndDate.AddDays(1);
                    break;
            }
        }
        #endregion
        #region GetIndicatorRect
        /// 
        /// GetIndicatorRect
        /// 
        /// 
        /// 
        private Rectangle GetIndicatorRect(TimeIndicator ti)
        {
            DateTime time = ti.IndicatorDisplayTime;
            int offset = (int)(time.Hour * SlotsPerHour * TimeSliceHeight +
                    (TimeSliceHeight * time.Minute) / TimeSlotDuration);
            offset -= (int)(StartSlice * TimeSliceHeight);
            Rectangle r = Bounds;
            r.Y += (offset - ti.Thickness + _VScrollPos);
            r.Height = ti.Thickness;
            return (r);
        }
        #endregion
        #endregion
        #region DrawRulerContent
        private void DrawRulerContent(Graphics g, int sliceStart, int sliceEnd)
        {
            Point pt1 = new Point();
            Point pt2 = new Point();
            using (Pen pen = new Pen(
                _ViewColor.GetColor((int)eTimeRulerPart.TimeRulerBorder)))
            {
                pt1.X = 3;
                pt2.X = Bounds.Width - 4;
                for (int i = sliceStart; i <= sliceEnd; i++)
                {
                    Rectangle r = GetSliceRect(i);
                    // Draw an hourly separation border line
                    if ((i % SlotsPerHour) == 0)
                    {
                        pt1.Y = pt2.Y = r.Y;
                        g.DrawLine(pen, pt1, pt2);
                    }
                    // Draw the time text
                    DrawTimeRulerText(g, r, i);
                }
            }
        }
        #endregion
        #region DrawTimeRulerText
        /// 
        /// Draws the time text
        /// 
        /// 
        /// 
        /// 
        private void DrawTimeRulerText(Graphics g, Rectangle r, int slice)
        {
            // Get our hour and minute display text
            slice += StartSlice;
            int hour = slice / SlotsPerHour;
            int minute = (slice % SlotsPerHour) * TimeSlotDuration;
            if (_CalendarView.LabelTimeSlots == true || minute == 0)
            {
                string sHour = GetRulerHour(hour);
                string sMinute = GetRulerMinute(hour, minute);
                // Setup for our output
                Color color = _ViewColor.GetColor(
                    (int)eTimeRulerPart.TimeRulerForeground);
                eTextFormat tf = eTextFormat.Top | eTextFormat.Left | eTextFormat.NoPadding;
                Size sz = TextDrawing.MeasureString(g, sHour, TimeRulerFont, 0, tf);
                Rectangle r2 = new Rectangle(Bounds.X, r.Y + 1,
                    Bounds.Width / 2, (int)TimeSliceHeight - 1);
                // If we are displaying an hourly marker, then display
                // it as an offset hour and minute (or AM/PM designator) display
                if (minute == 0)
                {
                    r2.X = r2.Right - sz.Width;
                    if (r2.X < 0)
                        r2.X = 0;
                    r2.Width = sz.Width;
                    TextDrawing.DrawString(g, sHour, TimeRulerFont, color, r2, tf);
                    r2.X = r2.Right + 2;
                    r2.Y += 1;
                    tf = eTextFormat.Top | eTextFormat.Left | eTextFormat.NoPadding;
                    TextDrawing.DrawString(g, sMinute, TimeRulerFontSm, color, r2, tf);
                }
                else
                {
                    // Non-hourly display
                    r2.Width = Bounds.Width - 4;
                    r2.Y += 2;
                    tf = eTextFormat.Top | eTextFormat.Right | eTextFormat.NoPadding;
                    TextDrawing.DrawString(g,
                        sHour + ScheduleSettings.GetActiveCulture().DateTimeFormat.TimeSeparator +
                        sMinute, TimeRulerFontSm, color, r2, tf);
                }
            }
        }
        /// 
        /// Gets the hourly display text
        /// 
        /// Hour
        /// Hourly text
        private string GetRulerHour(int hour)
        {
            if (_CalendarView.Is24HourFormat == false)
            {
                int h = hour % 12;
                hour = (h == 0) ? 12 : h;
            }
            else
            {
                int h = hour % 24;
                hour = (h == 0) ? 0 : h;
            }
            return (hour.ToString(ScheduleSettings.TimeRulerHourFormatString));
        }
        /// 
        /// Gets the minute display text
        /// 
        /// Hour
        /// Minute
        /// Minute text
        private string GetRulerMinute(int hour, int minute)
        {
            if (minute == 0 && _CalendarView.Is24HourFormat == false)
            {
                hour %= 24;
                if (hour == 0)
                    return (AmDesignator);
                if (hour == 12)
                    return (PmDesignator);
            }
            return (minute.ToString(ScheduleSettings.TimeRulerMinuteFormatString));
        }
        #endregion
        #endregion
        #region IDisposable Members
        protected override void Dispose(bool disposing)
        {
            if (disposing == true && IsDisposed == false)
                HookEvents(false);
            base.Dispose(disposing);
        }
        #endregion
        #region Copy
        /// 
        /// Returns copy of the item.
        /// 
        public override BaseItem Copy()
        {
            TimeRulerPanel objCopy = new TimeRulerPanel(_CalendarView);
            CopyToItem(objCopy);
            return (objCopy);
        }
        /// 
        /// Copies the TimeRulerPanel specific properties to new instance of the item.
        /// 
        /// New TimeRulerPanel instance
        protected override void CopyToItem(BaseItem copy)
        {
            TimeRulerPanel objCopy = copy as TimeRulerPanel;
            base.CopyToItem(objCopy);
        }
        #endregion
    }
}
#endif