using System;
using System.Collections.Generic;
using System.Linq;

using BeWo.Controls.Controls.Calendar;

using BS.Shared;
using BS.Shared.Core;
using BS.Shared.DataContracts;
using BS.Shared.Extensions;

namespace BeWo.ViewModel.ListViewModel
{
    public class BookingVM : AbstractDCListMapperVM<BookingSequenceDC, BookingSequenceVM>
    {
        public static string PropertyName_EditAppointment = "EditAppointment";

        private Appointment _EditAppointment;

        public BookingVM(IEnumerable<BookingSequenceDC> pDCList) : base(pDCList)
        {
        }

        public Appointment EditAppointment
        {
            get { return _EditAppointment; }

            set
            {
                _EditAppointment = value;
                FirePropertyChanged(PropertyName_EditAppointment);
            }
        }

        public static List<Appointment> GetOverlappingSingleBooking(Appointment pAppointment, BookingSequenceVM pParentSequence, IEnumerable<BookingSequenceVM> pList)
        {
            var lProblems = new List<Appointment>();

            int lAppointmentsSequencePosition = pParentSequence.GetSequencePosition(pAppointment);
            var lAllAppointments = pParentSequence.CalculateAppointmentsFromSequence(pAppointment.Duration);

            if (lAllAppointments.ContainsKey(lAppointmentsSequencePosition))
            {
                lAllAppointments.Remove(lAppointmentsSequencePosition);
            }

            lProblems.AddRange(lAllAppointments.Values.Where(ap => ap.Duration.Overlaps(pAppointment.Duration)));

            pList.Where(s => pAppointment.Duration.Overlaps(s.GetSequenceSpan()) && s != pParentSequence).DoForEach(
                iSeq => lProblems.AddRange(iSeq.CalculateAppointmentsFromSequence(pAppointment.Duration).Values));

            return lProblems;
        }

        public static List<Appointment> GetOverlappingWholeSequence(BookingSequenceVM pSequence, IEnumerable<BookingSequenceVM> pList)
        {
            var lProblems = new List<Appointment>();
            var lSequenceSpan = pSequence.GetSequenceSpan();

            foreach (var iSeq in pList.Where(s => lSequenceSpan.Overlaps(s.GetSequenceSpan()) && s != pSequence))
            {
                var lToConsider = new DateTimeSpan
                    {
                        StartDateTime = lSequenceSpan.StartDateTime > iSeq.GetSequenceSpan().StartDateTime ? lSequenceSpan.StartDateTime : iSeq.GetSequenceSpan().StartDateTime, 
                        EndDateTime = lSequenceSpan.EndDateTime < iSeq.GetSequenceSpan().EndDateTime ? lSequenceSpan.EndDateTime : iSeq.GetSequenceSpan().EndDateTime
                    };

                lProblems.AddRange(
                    iSeq.CalculateAppointmentsFromSequence(lToConsider).Values.Where(
                        a1 => pSequence.CalculateAppointmentsFromSequence(lToConsider).Values.FirstOrDefault(a2 => a1.Duration.Overlaps(a2.Duration)) != null));
            }

            return lProblems;
        }

        public IEnumerable<Appointment> GetAppointmentsByCategory(long pCategoryOid, DateTimeSpan pSpan)
        {
            var lResult = new List<Appointment>();
            foreach (var iSeq in VMList.Where(seq => seq.Resource.ResourceCategory.ValueListEntryOid == pCategoryOid))
            {
                iSeq.SpanToConsider = pSpan;
                lResult.AddRange(iSeq.AppointmentsInSpan);
            }

            return lResult;
        }

        public IEnumerable<Appointment> GetAppointmentsByResource(long pResourceOid, DateTimeSpan pSpan)
        {
            var lResult = new List<Appointment>();
            foreach (var iSeq in VMList.Where(seq => seq.Resource.ResourceOid == pResourceOid))
            {
                iSeq.SpanToConsider = pSpan;
                lResult.AddRange(iSeq.AppointmentsInSpan);
            }

            return lResult;
        }

        public BookingSequenceVM GetAppointmentsSequence(Appointment pAppointment)
        {
            return VMList.FirstOrDefault(iSeq => iSeq.AppointmentsInSpan.Contains(pAppointment));
        }

        protected override BookingSequenceVM CreateVM(BookingSequenceDC pDC)
        {
            if (pDC.SequenceOid == null)
            {
                pDC.RootBooking = new ResourceBookingDC
                {
                    Duration = new DateTimeSpan
                    {
                        StartDateTime = DateTime.Now.AddMinutes(15 - DateTime.Now.Minute%15)
                    }
                };
                pDC.RootBooking.Duration.EndDateTime = pDC.RootBooking.Duration.StartDateTime.AddHours(1);
                pDC.RootBooking.SequencePosition = 0;
                pDC.Frequency = ResourceBookingFrequencyType.Once;
                pDC.RepeatInterval = 1;
                pDC.SequenceEnd = pDC.RootBooking.Duration.StartDateTime.AddMonths(12).Date;
            }

            return new BookingSequenceVM(pDC);
        }
    }
}