using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using BeWo.Controls.Calendar;
using BS.Shared;
using BS.Shared.Core;
using BS.Shared.Extensions;

namespace BeWo.Controls.Controls.Calendar
{
    public partial class AppointmentCalendar
    {
        private const int MinBarSize = 25;
        private const bool _DoInitialScroll = true;

        public static readonly DependencyProperty AppointmentsProperty = DependencyProperty.Register("Appointments",
            typeof (ObservableCollection<Appointment>), typeof (AppointmentCalendar),
            new UIPropertyMetadata(new ObservableCollection<Appointment>(), AppointmentListReplaced));

        public static readonly DependencyProperty BarFillProperty = DependencyProperty.Register("BarFill",
            typeof (Brush), typeof (AppointmentCalendar), new UIPropertyMetadata(Brushes.Gray));

        public static readonly DependencyProperty BarHoverFillProperty = DependencyProperty.Register("BarHoverFill",
            typeof (Brush), typeof (AppointmentCalendar), new UIPropertyMetadata(Brushes.LightGray));

        public static readonly DependencyProperty BarPressedFillProperty = DependencyProperty.Register(
            "BarPressedFill", typeof (Brush), typeof (AppointmentCalendar), new UIPropertyMetadata(Brushes.DarkGray));

        public static readonly DependencyProperty CalendarStartDateProperty =
            DependencyProperty.Register("CalendarStartDate", typeof (DateTime), typeof (AppointmentCalendar),
                new UIPropertyMetadata(DateTime.Now.Date, ConfigPropertyChanged));

        public static readonly DependencyProperty DaysToShowCountProperty =
            DependencyProperty.Register("DaysToShowCount", typeof (int), typeof (AppointmentCalendar),
                new UIPropertyMetadata(31, ConfigPropertyChanged));

        public static readonly DependencyProperty GridLineBrushProperty = DependencyProperty.Register("GridLineBrush",
            typeof (Brush), typeof (AppointmentCalendar),
            new UIPropertyMetadata(Brushes.LightGray, ConfigPropertyChanged));

        public static readonly DependencyProperty ShowDatesInIndexProperty =
            DependencyProperty.Register("ShowDatesInIndex", typeof (bool), typeof (AppointmentCalendar),
                new UIPropertyMetadata(false, ConfigPropertyChanged));

        public static readonly DependencyProperty ShowWeekendProperty = DependencyProperty.Register("ShowWeekend",
            typeof (bool), typeof (AppointmentCalendar), new UIPropertyMetadata(false, ConfigPropertyChanged));

        public static readonly DependencyProperty TimeIntervalProperty = DependencyProperty.Register("TimeInterval",
            typeof (Interval), typeof (AppointmentCalendar),
            new UIPropertyMetadata(Interval.HalfHour, ConfigPropertyChanged));

        public static readonly DependencyProperty WorkHoursEndProperty = DependencyProperty.Register("WorkHoursEnd",
            typeof (TimeSpan), typeof (AppointmentCalendar),
            new UIPropertyMetadata(TimeSpan.FromHours(17), ConfigPropertyChanged));

        public static readonly DependencyProperty WorkHoursStartProperty = DependencyProperty.Register(
            "WorkHoursStart", typeof (TimeSpan), typeof (AppointmentCalendar),
            new UIPropertyMetadata(TimeSpan.FromHours(8), ConfigPropertyChanged));

        private readonly List<CalendarContentGrid> _ContentGrids = new List<CalendarContentGrid>();

        private readonly IndexHeaderContent _HeaderContent = new IndexHeaderContent();

        private readonly IndexHeaderContent _IndexContent = new IndexHeaderContent();

        private readonly Dictionary<AppointmentBar, AppointmentBarRenderInf> _RenderedBars =
            new Dictionary<AppointmentBar, AppointmentBarRenderInf>();

        private Appointment _SelectedAppointment;

        public AppointmentCalendar()
        {
            InitializeComponent();
            Loaded += (s, e) => Render();
            Appointments.CollectionChanged += Appointments_CollectionChanged;
        }

        public ObservableCollection<Appointment> Appointments
        {
            get { return (ObservableCollection<Appointment>) GetValue(AppointmentsProperty); }

            set { SetValue(AppointmentsProperty, value); }
        }

        public Brush BarFill
        {
            get { return (Brush) GetValue(BarFillProperty); }

            set { SetValue(BarFillProperty, value); }
        }

        public Brush BarHoverFill
        {
            get { return (Brush) GetValue(BarHoverFillProperty); }

            set { SetValue(BarHoverFillProperty, value); }
        }

        public Brush BarPressedFill
        {
            get { return (Brush) GetValue(BarPressedFillProperty); }

            set { SetValue(BarPressedFillProperty, value); }
        }

        public DateTime CalendarStartDate
        {
            get { return (DateTime) GetValue(CalendarStartDateProperty); }

            set { SetValue(CalendarStartDateProperty, value); }
        }

        public DateTimeSpan DaySpan
        {
            get
            {
                return new DateTimeSpan
                {
                    StartDateTime = CalendarStartDate,
                    EndDateTime = CalendarStartDate.AddDays(DaysToShowCount)
                };
            }
        }

        public int DaysToShowCount
        {
            get { return (int) GetValue(DaysToShowCountProperty); }

            set { SetValue(DaysToShowCountProperty, value); }
        }

        public Brush GridLineBrush
        {
            get { return (Brush) GetValue(GridLineBrushProperty); }

            set { SetValue(GridLineBrushProperty, value); }
        }

        public bool ShowDatesInIndex
        {
            get { return (bool) GetValue(ShowDatesInIndexProperty); }

            set { SetValue(ShowDatesInIndexProperty, value); }
        }

        public bool ShowWeekend
        {
            get { return (bool) GetValue(ShowWeekendProperty); }

            set { SetValue(ShowWeekendProperty, value); }
        }

        public Interval TimeInterval
        {
            get { return (Interval) GetValue(TimeIntervalProperty); }

            set { SetValue(TimeIntervalProperty, value); }
        }

        public TimeSpan WorkHoursEnd
        {
            get { return (TimeSpan) GetValue(WorkHoursEndProperty); }

            set { SetValue(WorkHoursEndProperty, value); }
        }

        public TimeSpan WorkHoursStart
        {
            get { return (TimeSpan) GetValue(WorkHoursStartProperty); }

            set { SetValue(WorkHoursStartProperty, value); }
        }

        private TimeSpan TimeIntervalSpan
        {
            get
            {
                if (TimeInterval == Interval.Hour)
                {
                    return TimeSpan.FromHours(1);
                }

                if (TimeInterval == Interval.HalfHour)
                {
                    return TimeSpan.FromMinutes(30);
                }

                return TimeSpan.FromMinutes(15);
            }
        }

        private DateTimeSpan UsedCalendarDuration
        {
            get
            {
                var lResult = new DateTimeSpan
                {
                    StartDateTime = ShowWeekend ? CalendarStartDate : CalendarStartDate.GetNextMondayIfWeekend()
                };
                DateTime lUsedCalendarEnd = CalendarStartDate.AddDays(DaysToShowCount).AddMilliseconds(-1);
                if (!ShowWeekend)
                {
                    lResult.EndDateTime = lUsedCalendarEnd.GetLastFridayIfWeekend();
                }
                else
                {
                    lResult.EndDateTime = lUsedCalendarEnd;
                }

                return lResult;
            }
        }

        public event EventHandler<EventArgs<Appointment>> AppointmentDeselected;

        public event EventHandler<EventArgs<Appointment>> AppointmentSelected;

        public event EventHandler<EventArgs<DateTime>> CalendarStartDateChanged;

        public event EventHandler<EventArgs<int>> DaysToShowCountChanged;

        public void Deselect(Appointment pAppointment)
        {
            AppointmentBar lBar = _RenderedBars.Keys.SingleOrDefault(b => b.Appointment == pAppointment);
            if (lBar != null)
            {
                lBar.IsChecked = false;
            }
        }

        public int GetDaySpan(DateTime pDate1, DateTime pDate2)
        {
            DateTime l1 = pDate1.Date;
            DateTime l2 = pDate2.Date;

            int lResult = 0;
            int lWeekendCount = 0;

            do
            {
                if (l1.DayOfWeek == DayOfWeek.Saturday || l1.DayOfWeek == DayOfWeek.Sunday)
                {
                    lWeekendCount++;
                }

                l1 = l1.AddDays(1);
                lResult++;
            } while (l1 <= l2);
            return ShowWeekend ? lResult : lResult - lWeekendCount;
        }

        public int GetQuaterHourSpan(DateTime pDate, bool pCountIncomplete)
        {
            TimeSpan lQuater = TimeSpan.FromMinutes(15);
            DateTime lTemp = pDate.Date;
            int lResult = 0;

            if (pCountIncomplete)
            {
                while (lTemp < pDate)
                {
                    lTemp += lQuater;
                    lResult++;
                }
            }
            else
            {
                while (pDate - lTemp >= lQuater)
                {
                    lTemp += lQuater;
                    lResult++;
                }
            }

            return lResult;
        }

        public void Select(Appointment pAppointment)
        {
            AppointmentBar lBar = _RenderedBars.Keys.SingleOrDefault(b => b.Appointment == pAppointment);
            if (lBar != null)
            {
                lBar.IsChecked = true;
                lBar[0].BringIntoView();
            }
        }

        private static void AppointmentListReplaced(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ((ObservableCollection<Appointment>) e.NewValue).CollectionChanged +=
                ((AppointmentCalendar) sender).Appointments_CollectionChanged;
            var lInstance = (AppointmentCalendar) sender;

            foreach (Appointment iAppointment in (ObservableCollection<Appointment>) e.NewValue)
            {
                iAppointment.PropertyChanged += (s, ev) => lInstance.RenderBar(iAppointment);
                iAppointment.Duration.PropertyChanged += (s, ev) => lInstance.RenderBar(iAppointment);
            }

            lInstance.Render();
        }

        // Callback
        private static void ConfigPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var lInstance = sender as AppointmentCalendar;

            lInstance.Render();
            if (e.Property == CalendarStartDateProperty)
            {
                lInstance.FireCalenderStartChanged();
            }
            else if (e.Property == DaysToShowCountProperty)
            {
                lInstance.FireDaysToShowCountChanged();
            }
        }

        private void Appointments_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            try
            {
                if (e.OldItems != null)
                {
                    foreach (Appointment iAppointment in e.OldItems)
                    {
                        AppointmentBar lBar = _RenderedBars.Keys.SingleOrDefault(b => b.Appointment == iAppointment);
                        if (lBar != null)
                        {
                            foreach (Border iBorder in lBar)
                            {
                                if (iBorder.Parent is CalendarContentGrid)
                                {
                                    ((CalendarContentGrid) iBorder.Parent).Remove(iBorder);
                                }
                            }

                            _RenderedBars.Remove(lBar);
                        }
                    }
                }

                if (e.NewItems != null)
                {
                    foreach (Appointment iAppointment in e.NewItems)
                    {
                        RenderBar(iAppointment);
                        iAppointment.PropertyChanged += (s, ev) => RenderBar(iAppointment);
                        iAppointment.Duration.PropertyChanged += (s, ev) => RenderBar(iAppointment);
                    }
                }

                if (e.Action == NotifyCollectionChangedAction.Reset)
                {
                    foreach (AppointmentBar iBar in _RenderedBars.Keys)
                    {
                        foreach (Border iBorder in iBar)
                        {
                            if (iBorder.Parent is CalendarContentGrid)
                            {
                                ((CalendarContentGrid) iBorder.Parent).Remove(iBorder);
                            }
                        }
                    }

                    _RenderedBars.Clear();
                }
            }
            catch (Exception)
            {
            }
        }

        private void CreateDates()
        {
            IndexHeaderContent lContent = ShowDatesInIndex ? _IndexContent : _HeaderContent;
            lContent.Clear();

            for (int i = 0; i < DaysToShowCount; i++)
            {
                DateTime lDate = CalendarStartDate.AddDays(i);

                if (ShowWeekend || (lDate.DayOfWeek != DayOfWeek.Saturday && lDate.DayOfWeek != DayOfWeek.Sunday))
                {
                    string lText = lDate.ToMyDateTimeString();
                    var lElement = new IndexHeaderElement {Content = lText, Tooltip = lDate.ToLongDateString()};

                    if (lDate.DayOfWeek == DayOfWeek.Saturday || lDate.DayOfWeek == DayOfWeek.Sunday)
                    {
                        lElement.ForeGround = Brushes.Gray;
                    }

                    if (lDate.DayOfWeek == DayOfWeek.Monday)
                    {
                        lElement.BorderBrush = Brushes.Black;
                    }

                    lElement.HorizontalAlignment = HorizontalAlignment.Center;
                    lElement.VerticalAlignment = VerticalAlignment.Center;
                    lContent.Add(lElement);
                }
            }
        }

        private AppointmentBarRenderInf CreateRenderInformation(Appointment pAppointment)
        {
            var lResult = new AppointmentBarRenderInf();
            lResult.Appointment = pAppointment;

            DateTime lUsedAppointmentStart = ShowWeekend
                ? pAppointment.Duration.StartDateTime
                : pAppointment.Duration.StartDateTime.GetNextMondayIfWeekend();
            DateTime lUsedAppointmentEnd = ShowWeekend
                ? pAppointment.Duration.EndDateTime
                : pAppointment.Duration.EndDateTime.GetLastFridayIfWeekend();

            if (lUsedAppointmentStart >= lUsedAppointmentEnd)
            {
                lResult.BarCount = 0;
                return lResult;
            }

            lResult.UsedDuration = new DateTimeSpan
            {
                StartDateTime =
                    lUsedAppointmentStart < UsedCalendarDuration.StartDateTime
                        ? UsedCalendarDuration.StartDateTime
                        : lUsedAppointmentStart,
                EndDateTime =
                    lUsedAppointmentEnd > UsedCalendarDuration.EndDateTime
                        ? UsedCalendarDuration.EndDateTime
                        : lUsedAppointmentEnd
            };

            lResult.BarCount = GetDaySpan(lResult.UsedDuration.StartDateTime, lResult.UsedDuration.EndDateTime);
            lResult.StartDateIndex =
                GetDaySpan(UsedCalendarDuration.StartDateTime, lResult.UsedDuration.StartDateTime) - 1;
            lResult.StartTimeIndex = GetQuaterHourSpan(lResult.UsedDuration.StartDateTime, false);
            lResult.EndTimeIndex = GetQuaterHourSpan(lResult.UsedDuration.EndDateTime, true);

            return lResult;
        }

        private void CreateTimes()
        {
            IndexHeaderContent lContent = ShowDatesInIndex ? _HeaderContent : _IndexContent;
            lContent.Clear();

            DateTime lDate = DateTime.Now.Date;

            do
            {
                IndexHeaderElement lElement = null;
                if (lDate.Minute == 0)
                {
                    lElement = new IndexHeaderElement
                    {
                        Content = string.Format("{0:00}", lDate.Hour) + ":00",
                        Tooltip = string.Format("{0:00}", lDate.Hour) + ":00"
                    };
                }
                else
                {
                    lElement = new IndexHeaderElement
                    {
                        Content = string.Format("{0:00}", lDate.Minute),
                        Tooltip = string.Format("{0:00}", lDate.Hour) + ":" + string.Format("{0:00}", lDate.Minute)
                    };
                }

                if (lDate - WorkHoursStart >= DateTime.Now.Date && lDate - WorkHoursEnd <= DateTime.Now.Date)
                {
                    lElement.BackGround = FindResource("WorkSpanBrush") as Brush;
                }

                if (lDate.Minute != 0)
                {
                    if (!ShowDatesInIndex)
                    {
                        lElement.HorizontalAlignment = HorizontalAlignment.Right;
                    }

                    lElement.FontStyle = FontStyles.Italic;
                }

                if (ShowDatesInIndex)
                {
                    lElement.HorizontalAlignment = HorizontalAlignment.Center;
                    lElement.VerticalAlignment = VerticalAlignment.Center;
                }

                lContent.Add(lElement);
                lDate = lDate + TimeIntervalSpan;
            } while (lDate - DateTime.Now.Date < TimeSpan.FromDays(1));
        }

        private void FireCalenderStartChanged()
        {
            if (CalendarStartDateChanged != null)
            {
                CalendarStartDateChanged(this, new EventArgs<DateTime>(CalendarStartDate));
            }
        }

        private void FireDaysToShowCountChanged()
        {
            if (DaysToShowCountChanged != null)
            {
                DaysToShowCountChanged(this, new EventArgs<int>(DaysToShowCount));
            }
        }

        private void Render()
        {
            grid_header.ColumnDefinitions.Clear();
            grid_header.RowDefinitions.Clear();
            grid_header.Children.Clear();
            grid_index.RowDefinitions.Clear();
            grid_index.ColumnDefinitions.Clear();
            grid_index.Children.Clear();
            grid_innerTable.RowDefinitions.Clear();
            grid_innerTable.ColumnDefinitions.Clear();
            grid_innerTable.Children.Clear();

            _ContentGrids.DoForEach(cg => cg.ParallelCountChanged -= lGrid_ParallelCountChanged);
            _ContentGrids.Clear();

            if (ShowDatesInIndex)
            {
                BarFill = (Brush) FindResource("HBarFill");
                BarHoverFill = (Brush) FindResource("HBarHoverFill");
                BarPressedFill = (Brush) FindResource("HBarPressedFill");
            }
            else
            {
                BarFill = (Brush) FindResource("VBarFill");
                BarHoverFill = (Brush) FindResource("VBarHoverFill");
                BarPressedFill = (Brush) FindResource("VBarPressedFill");
            }

            CreateDates();
            CreateTimes();
            RenderHeader();
            RenderIndex();
            RenderCells();
            if (_DoInitialScroll && IsLoaded)
            {
                ScrollToStartWorkHour();
            }

            Appointments.DoForEach(ap => RenderBar(ap));
        }

        private void RenderBar(Appointment pAppointment)
        {
            try
            {
                foreach (AppointmentBar iBar in _RenderedBars.Keys.ToList())
                {
                    if (iBar.Appointment.Equals(pAppointment))
                    {
                        foreach (Border iBorder in iBar)
                        {
                            if (iBorder.Parent != null)
                            {
                                ((CalendarContentGrid) iBorder.Parent).Remove(iBorder);
                            }
                        }

                        _RenderedBars.Remove(iBar);
                        break;
                    }
                }

                if (pAppointment.Duration.Overlaps(UsedCalendarDuration))
                {
                    var lAppointmentBar = new AppointmentBar(pAppointment,
                        ShowDatesInIndex ? Orientation.Horizontal : Orientation.Vertical, pAppointment.Brush)
                    {
                        MouseOverBrush = BarHoverFill,
                        PressedBrush = BarPressedFill
                    };

                    AppointmentBarRenderInf lBarInformation = CreateRenderInformation(pAppointment);

                    // 0 can occur if no weekends
                    if (lBarInformation.BarCount > 0)
                    {
                        var lCornerRound = new CornerRadius(5);
                        CornerRadius lCornerStartRound = ShowDatesInIndex
                            ? new CornerRadius(5, 0, 0, 5)
                            : new CornerRadius(5, 5, 0, 0);
                        CornerRadius lCornerEndRound = ShowDatesInIndex
                            ? new CornerRadius(0, 5, 5, 0)
                            : new CornerRadius(0, 0, 5, 5);
                        var lCornerNotRound = new CornerRadius();
                        var lBorderClose = new Thickness(1);
                        Thickness lBorderOpen = ShowDatesInIndex ? new Thickness(0, 1, 0, 1) : new Thickness(1, 0, 1, 0);
                        Thickness lBorderStartOpen = ShowDatesInIndex
                            ? new Thickness(0, 1, 1, 1)
                            : new Thickness(1, 0, 1, 1);
                        Thickness lBorderEndOpen = ShowDatesInIndex
                            ? new Thickness(1, 1, 0, 1)
                            : new Thickness(1, 1, 1, 0);

                        bool lStartTimeTrimmed = lBarInformation.UsedDuration.StartDateTime !=
                                                 pAppointment.Duration.StartDateTime;
                        bool lEndTimeTrimmed = lBarInformation.UsedDuration.EndDateTime !=
                                               pAppointment.Duration.EndDateTime;

                        if (lBarInformation.BarCount == 1)
                        {
                            var lFirstBar = new Border
                            {
                                CornerRadius = lStartTimeTrimmed ? lCornerEndRound : lCornerRound,
                                BorderThickness = lStartTimeTrimmed ? lBorderStartOpen : lBorderClose
                            };
                            if (!string.IsNullOrEmpty(pAppointment.Text))
                            {
                                lFirstBar.ToolTip = pAppointment.Text;
                            }

                            _ContentGrids[lBarInformation.StartDateIndex].Add(lFirstBar, lBarInformation.StartTimeIndex,
                                lBarInformation.EndTimeIndex - lBarInformation.StartTimeIndex, pAppointment.Index);

                            lAppointmentBar.Add(lFirstBar);
                        }
                        else
                        {
                            if (lBarInformation.BarCount > 1)
                            {
                                // first Bar
                                var lFirstBar = new Border
                                {
                                    BorderThickness = lStartTimeTrimmed ? lBorderOpen : lBorderEndOpen,
                                    CornerRadius = lStartTimeTrimmed ? lCornerNotRound : lCornerStartRound
                                };

                                if (!string.IsNullOrEmpty(pAppointment.Text))
                                {
                                    lFirstBar.ToolTip = pAppointment.Text;
                                }

                                if (ShowDatesInIndex)
                                {
                                    _ContentGrids[lBarInformation.StartDateIndex].Add(lFirstBar,
                                        lBarInformation.StartTimeIndex,
                                        grid_innerTable.ColumnDefinitions.Count - lBarInformation.StartTimeIndex,
                                        pAppointment.Index);
                                }
                                else
                                {
                                    _ContentGrids[lBarInformation.StartDateIndex].Add(lFirstBar,
                                        lBarInformation.StartTimeIndex,
                                        grid_innerTable.RowDefinitions.Count - lBarInformation.StartTimeIndex,
                                        pAppointment.Index);
                                }

                                lAppointmentBar.Add(lFirstBar);

                                // between Bars
                                if (lBarInformation.BarCount > 2)
                                {
                                    for (int iMiddleBarCount = 1;
                                        iMiddleBarCount <= lBarInformation.BarCount - 2;
                                        iMiddleBarCount++)
                                    {
                                        var lMiddleBar = new Border
                                        {
                                            CornerRadius = lCornerNotRound,
                                            BorderThickness = lBorderOpen
                                        };

                                        if (!string.IsNullOrEmpty(pAppointment.Text))
                                        {
                                            lMiddleBar.ToolTip = pAppointment.Text;
                                        }

                                        if (ShowDatesInIndex)
                                        {
                                            _ContentGrids[lBarInformation.StartDateIndex + iMiddleBarCount].Add(
                                                lMiddleBar, 0, grid_innerTable.ColumnDefinitions.Count,
                                                pAppointment.Index);
                                        }
                                        else
                                        {
                                            _ContentGrids[lBarInformation.StartDateIndex + iMiddleBarCount].Add(
                                                lMiddleBar, 0, grid_innerTable.RowDefinitions.Count, pAppointment.Index);
                                        }

                                        lAppointmentBar.Add(lMiddleBar);
                                    }
                                }

                                // last Bar
                                var lLastBar = new Border
                                {
                                    BorderThickness = lEndTimeTrimmed ? lBorderOpen : lBorderStartOpen,
                                    CornerRadius = lEndTimeTrimmed ? lCornerNotRound : lCornerEndRound
                                };

                                if (!string.IsNullOrEmpty(pAppointment.Text))
                                {
                                    lLastBar.ToolTip = pAppointment.Text;
                                }

                                if (lBarInformation.EndTimeIndex > 0)
                                {
                                    _ContentGrids[lBarInformation.StartDateIndex + lBarInformation.BarCount - 1].Add(
                                        lLastBar, 0, lBarInformation.EndTimeIndex, pAppointment.Index);
                                }

                                lAppointmentBar.Add(lLastBar);
                            }
                        }

                        lAppointmentBar.IsCheckedChanged += lAppointmentBar_IsCheckedChanged;

                        _RenderedBars.Add(lAppointmentBar, lBarInformation);
                        lAppointmentBar.IsChecked = pAppointment == _SelectedAppointment;
                    }
                }
            }
            catch (Exception)
            {
            }
        }

        private void RenderCells()
        {
            int lDivide = 1;
            if (TimeInterval == Interval.HalfHour)
            {
                lDivide = 2;
            }
            else if (TimeInterval == Interval.Hour)
            {
                lDivide = 4;
            }

            if (ShowDatesInIndex)
            {
                RenderColumnCells(lDivide, 1);
                RenderRowCells(1, lDivide);
            }
            else
            {
                RenderRowCells(lDivide, 1);
                RenderColumnCells(1, lDivide);
            }
        }

        private void RenderColumnCells(int pColumnsPerCell, int pRowsPerCell)
        {
            try
            {
                if (!ShowDatesInIndex)
                {
                    _ContentGrids.Clear();
                }

                for (int iCell = 0; iCell < grid_header.ColumnDefinitions.Count; iCell++)
                {
                    for (int i = 0; i < pColumnsPerCell; i++)
                    {
                        grid_innerTable.ColumnDefinitions.Add(new ColumnDefinition
                        {
                            Width = new GridLength(1, GridUnitType.Star)
                        });
                    }

                    var lBorder = new Border
                    {
                        BorderThickness = new Thickness(1, 0, 0, 0),
                        BorderBrush = _HeaderContent[iCell].BorderBrush,
                        Padding = new Thickness(0),
                        Margin = new Thickness(0),
                        Background = ShowDatesInIndex ? _HeaderContent[iCell].BackGround : Brushes.Transparent,
                        HorizontalAlignment = HorizontalAlignment.Stretch,
                        VerticalAlignment = VerticalAlignment.Stretch
                    };

                    lBorder.MinWidth = MinBarSize;

                    Grid.SetColumn(lBorder, iCell*pColumnsPerCell);
                    Grid.SetRowSpan(lBorder, _IndexContent.Count*pRowsPerCell);
                    Grid.SetColumnSpan(lBorder, pColumnsPerCell);
                    grid_innerTable.Children.Add(lBorder);

                    if (!ShowDatesInIndex)
                    {
                        var lGrid = new CalendarContentGrid();
                        lGrid.ColumnDefinitions.Add(new ColumnDefinition {Width = new GridLength(1, GridUnitType.Star)});

                        for (int iRow = 0; iRow < grid_innerTable.RowDefinitions.Count; iRow++)
                        {
                            lGrid.RowDefinitions.Add(new RowDefinition {Height = new GridLength(1, GridUnitType.Star)});
                        }

                        lBorder.Padding = new Thickness(2, 0, 2, 0);
                        lBorder.Child = lGrid;
                        lGrid.Tag = iCell;
                        lGrid.ParallelCountChanged += lGrid_ParallelCountChanged;
                        _ContentGrids.Add(lGrid);
                    }
                }
            }
            catch (Exception)
            {
            }
        }

        private void RenderHeader()
        {
            for (int iCol = 0; iCol < _HeaderContent.Count; iCol++)
            {
                grid_header.ColumnDefinitions.Add(new ColumnDefinition {Width = new GridLength(1, GridUnitType.Star)});

                var lBorder = new Border
                {
                    BorderThickness = new Thickness(1, 0, 0, 0),
                    BorderBrush = _HeaderContent[iCol].BorderBrush,
                    Background = _HeaderContent[iCol].BackGround,
                    Padding = new Thickness(0),
                    Margin = new Thickness(0),
                    HorizontalAlignment = HorizontalAlignment.Stretch,
                    VerticalAlignment = VerticalAlignment.Stretch
                };

                lBorder.MinWidth = MinBarSize;

                var lHeaderLabel = new Label
                {
                    Content = _HeaderContent[iCol].Content,
                    ToolTip = _HeaderContent[iCol].Tooltip, 
                    // FontStyle =  _HeaderContent[iCol].FontStyle,
                    LayoutTransform = new RotateTransform(-90),
                    Foreground = _HeaderContent[iCol].ForeGround,
                    Padding = new Thickness(0),
                    Margin = new Thickness(-2, 2, -2, 2),
                    HorizontalAlignment = _HeaderContent[iCol].HorizontalAlignment,
                    VerticalAlignment = _HeaderContent[iCol].VerticalAlignment
                };

                lBorder.Child = lHeaderLabel;
                Grid.SetColumn(lBorder, iCol);
                grid_header.Children.Add(lBorder);
            }
        }

        private void RenderIndex()
        {
            for (int iRow = 0; iRow < _IndexContent.Count; iRow++)
            {
                grid_index.RowDefinitions.Add(new RowDefinition {Height = new GridLength(1, GridUnitType.Star)});

                var lBorder = new Border
                {
                    BorderThickness = new Thickness(0, 1, 0, 0),
                    BorderBrush = _IndexContent[iRow].BorderBrush,
                    Background = _IndexContent[iRow].BackGround,
                    Padding = new Thickness(0)
                };

                lBorder.MinHeight = MinBarSize;

                var lIndexLabel = new Label
                {
                    HorizontalAlignment = _IndexContent[iRow].HorizontalAlignment,
                    VerticalAlignment = _IndexContent[iRow].VerticalAlignment, 
                    // FontStyle = _IndexContent[iRow].FontStyle,
                    Foreground = _IndexContent[iRow].ForeGround,
                    Padding = new Thickness(0),
                    Margin = new Thickness(3, 0, 3, 0),
                    Content = _IndexContent[iRow].Content,
                    ToolTip = _IndexContent[iRow].Tooltip
                };

                lBorder.Child = lIndexLabel;

                Grid.SetRow(lBorder, iRow);
                grid_index.Children.Add(lBorder);
            }
        }

        private void RenderRowCells(int pRowsPerCell, int pColumnsPerCell)
        {
            if (ShowDatesInIndex)
            {
                _ContentGrids.Clear();
            }

            for (int iCell = 0; iCell < _IndexContent.Count; iCell++)
            {
                for (int i = 0; i < pRowsPerCell; i++)
                {
                    grid_innerTable.RowDefinitions.Add(new RowDefinition {Height = new GridLength(1, GridUnitType.Star)});
                }

                var lBorder = new Border
                {
                    BorderThickness = new Thickness(0, 1, 0, 0),
                    BorderBrush = _IndexContent[iCell].BorderBrush,
                    Background = ShowDatesInIndex ? Brushes.Transparent : _IndexContent[iCell].BackGround,
                    Padding = new Thickness(0),
                    Margin = new Thickness(0),
                    HorizontalAlignment = HorizontalAlignment.Stretch,
                    VerticalAlignment = VerticalAlignment.Stretch
                };

                lBorder.MinHeight = MinBarSize;

                Grid.SetRow(lBorder, iCell*pRowsPerCell);
                Grid.SetColumnSpan(lBorder, _HeaderContent.Count*pColumnsPerCell);
                Grid.SetRowSpan(lBorder, pRowsPerCell);
                grid_innerTable.Children.Add(lBorder);

                if (ShowDatesInIndex)
                {
                    var lGrid = new CalendarContentGrid {Orientation = Orientation.Vertical};
                    lGrid.RowDefinitions.Add(new RowDefinition {Height = new GridLength(1, GridUnitType.Star)});

                    for (int iCol = 0; iCol < grid_innerTable.ColumnDefinitions.Count; iCol++)
                    {
                        lGrid.ColumnDefinitions.Add(new ColumnDefinition {Width = new GridLength(1, GridUnitType.Star)});
                    }

                    lBorder.Padding = new Thickness(0, 2, 0, 2);
                    lBorder.Child = lGrid;
                    lGrid.Tag = iCell;
                    lGrid.ParallelCountChanged += lGrid_ParallelCountChanged;
                    _ContentGrids.Add(lGrid);
                }
            }
        }

        // TODO stimmt nicht für Datesinheader
        private void ScrollToStartWorkHour()
        {
            double lOffset = 0;

            TimeSpan lCurrentTime = TimeIntervalSpan;

            while (lCurrentTime < WorkHoursStart)
            {
                lOffset += MinBarSize;
                lCurrentTime += TimeIntervalSpan;
            }

            if (ShowDatesInIndex)
            {
                scrollViewer_innerTable.ScrollToHorizontalOffset(lOffset);
            }
            else
            {
                scrollViewer_innerTable.ScrollToVerticalOffset(lOffset);
            }
        }

        private void lAppointmentBar_IsCheckedChanged(object sender, EventArgs e)
        {
            var lAppointmentBar = (AppointmentBar) sender;

            if (!lAppointmentBar.IsChecked)
            {
                if (AppointmentDeselected != null)
                {
                    AppointmentDeselected(this, new EventArgs<Appointment>(lAppointmentBar.Appointment));
                }

                _SelectedAppointment = null;
            }

            if (lAppointmentBar.IsChecked)
            {
                foreach (AppointmentBar iBar in _RenderedBars.Keys)
                {
                    if (iBar.IsChecked && iBar != lAppointmentBar)
                    {
                        iBar.IsChecked = false;
                    }
                }

                if (AppointmentSelected != null)
                {
                    AppointmentSelected(this, new EventArgs<Appointment>(lAppointmentBar.Appointment));
                }

                _SelectedAppointment = lAppointmentBar.Appointment;
            }
        }

        private void lGrid_ParallelCountChanged(object sender, EventArgs<int> e)
        {
            try
            {
                if (e.Data == 0)
                {
                    e.Data = 1;
                }

                var lIndex = (int) ((CalendarContentGrid) sender).Tag;
                if (ShowDatesInIndex)
                {
                    grid_index.RowDefinitions[lIndex].Height = new GridLength(e.Data*MinBarSize);
                    grid_innerTable.RowDefinitions[lIndex].Height = new GridLength(e.Data*MinBarSize);
                }
                else
                {
                    grid_header.ColumnDefinitions[lIndex].Width = new GridLength(e.Data, GridUnitType.Star);
                    grid_innerTable.ColumnDefinitions[lIndex].Width = new GridLength(e.Data, GridUnitType.Star);
                    grid_header.ColumnDefinitions[lIndex].MinWidth = e.Data*MinBarSize;
                    grid_innerTable.ColumnDefinitions[lIndex].MinWidth = e.Data*MinBarSize;
                }
            }
            catch (Exception)
            {
            }
        }

        private void srcollViewer_innerTable_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            if (IsLoaded)
            {
                if (e.HorizontalChange != 0d)
                {
                    scrollViewer_header.ScrollToHorizontalOffset(e.HorizontalOffset);
                }

                if (e.VerticalChange != 0d)
                {
                    scrollViewer_index.ScrollToVerticalOffset(e.VerticalOffset);
                }
            }
        }

        private void table_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (!(e.OriginalSource is Border) ||
                _RenderedBars.Keys.SingleOrDefault(bar => bar.Contains((Border) e.OriginalSource)) == null)
            {
                foreach (AppointmentBar iBar in _RenderedBars.Keys)
                {
                    if (iBar.IsChecked)
                    {
                        iBar.IsChecked = false;
                    }
                }
            }
        }
    }
}