using System; using System.Collections.Generic; using System.ComponentModel; using System.Globalization; using System.Linq; using BeWo.Controls.Controls.Calendar; using BS.Shared; using BS.Shared.Core; using BS.Shared.DataContracts; using BS.Shared.DataContracts.Compact; using BS.Shared.Extensions; namespace BeWo.ViewModel { public class BookingSequenceVM : AbstractDCMapperVM { public static string PropertyName_ChangedElements = "ChangedElements"; public static string PropertyName_Employee = "Employee"; public static string PropertyName_Frequency = "Frequency"; public static string PropertyName_Notice = "Notice"; public static string PropertyName_RepeatInterval = "RepeatInterval"; public static string PropertyName_Resource = "Resource"; public static string PropertyName_RootAppointment = "RootAppointment"; public static string PropertyName_SequenceEnd = "SequenceEnd"; private readonly Dictionary _ChangedElements = new Dictionary(); private readonly List _PossibleFrequencies = new List { new FrequencyTranslation { Frequency = ResourceBookingFrequencyType.Once, Translation = "Einmalig" }, new FrequencyTranslation { Frequency = ResourceBookingFrequencyType.Daily, Translation = "jeden Tag" }, new FrequencyTranslation { Frequency = ResourceBookingFrequencyType.Weekly }, new FrequencyTranslation { Frequency = ResourceBookingFrequencyType.Monthly }, new FrequencyTranslation { Frequency = ResourceBookingFrequencyType.MonthlyOnFirstDay }, new FrequencyTranslation { Frequency = ResourceBookingFrequencyType.MonthlyOnLastDay }, }; private Dictionary _AppointmentsInSpan = new Dictionary(); private CompactEmployeeDC _Employee; private ResourceBookingFrequencyType _Frequency; private bool _NeedsRecalculation = true; private string _Notice; private int _RepeatInterval = 1; private ResourceDC _Resource; private Appointment _RootAppointment; private DateTime _SequenceEnd; private DateTimeSpan _SpanToConsider; public BookingSequenceVM(BookingSequenceDC pDC) : base(pDC, pDC.SequenceOid == null) { } public List AppointmentsInSpan { get { if (_NeedsRecalculation && _SpanToConsider != null) { Dictionary lBak = _AppointmentsInSpan; _AppointmentsInSpan = CalculateAppointmentsFromSequence(_SpanToConsider); if (lBak.Count > 0) { foreach (int lPos in lBak.Keys) { if (_AppointmentsInSpan.ContainsKey(lPos) && _AppointmentsInSpan[lPos] != null) { lBak[lPos].Duration = _AppointmentsInSpan[lPos].Duration; lBak[lPos].Notice = _AppointmentsInSpan[lPos].Notice; lBak[lPos].Text = _AppointmentsInSpan[lPos].Text; _AppointmentsInSpan[lPos] = lBak[lPos]; } } } _NeedsRecalculation = false; } return _AppointmentsInSpan.Values.ToList(); } } public Dictionary ChangedElements { get { return _ChangedElements; } } public CompactEmployeeDC Employee { get { return _Employee; } set { if (AreDifferent(_Employee, value)) { _Employee = value; // StoreDirtyInformation(AreDifferent(DataContract.Employee, value), PropertyName_Employee); FirePropertyChanged(PropertyName_Employee); } } } public ResourceBookingFrequencyType Frequency { get { return _Frequency; } set { if (AreDifferent(_Frequency, value)) { _NeedsRecalculation = true; _Frequency = value; StoreDirtyInformation(AreDifferent(DataContract.Frequency, value), PropertyName_Frequency); FirePropertyChanged(PropertyName_Frequency); } } } public string Notice { get { return _Notice; } set { if (AreDifferent(_Notice, value)) { _Notice = value; StoreDirtyInformation(AreDifferent(DataContract.Notice, value), PropertyName_Notice); FirePropertyChanged(PropertyName_Notice); } } } public List PossibleFrequencies { get { return _PossibleFrequencies; } } public int RepeatInterval { get { return _RepeatInterval; } set { if (AreDifferent(_RepeatInterval, value)) { _NeedsRecalculation = true; _RepeatInterval = value; StoreDirtyInformation(AreDifferent(DataContract.RepeatInterval, value), PropertyName_RepeatInterval); FirePropertyChanged(PropertyName_RepeatInterval); } } } public ResourceDC Resource { get { return _Resource; } set { _Resource = value; RootAppointment.Index = (int) value.ResourceOid.Value; RootAppointment.Brush = value.GetBrush(); foreach (var iChanged in _ChangedElements) { iChanged.Value.Index = (int) value.ResourceOid.Value; iChanged.Value.Brush = value.GetBrush(); } FirePropertyChanged(PropertyName_Resource); } } public Appointment RootAppointment { get { return _RootAppointment; } set { if (AreDifferent(_RootAppointment, value)) { _RootAppointment = value; StoreDirtyInformation(!AreEqual(DataContract.RootBooking, _RootAppointment), PropertyName_RootAppointment); FirePropertyChanged(PropertyName_RootAppointment); _RootAppointment.PropertyChanged += _RootAppointment_PropertyChanged; _RootAppointment.Duration.PropertyChanged += Duration_PropertyChanged; _RootAppointment.Duration.SynchEndDate = true; } } } public DateTime SequenceEnd { get { return _SequenceEnd; } set { if (AreDifferent(_SequenceEnd, value)) { value = value.Date.AddHours(23).AddMinutes(59); _SequenceEnd = value; StoreDirtyInformation(AreDifferent(DataContract.SequenceEnd, value), PropertyName_SequenceEnd); FirePropertyChanged(PropertyName_SequenceEnd); } } } public DateTimeSpan SpanToConsider { get { return _SpanToConsider; } set { if (AreDifferent(_SpanToConsider, value)) { _SpanToConsider = value; _NeedsRecalculation = true; } } } private bool IsChangedElementsDirty { get { if (DataContract.ChangedElements.Count != _ChangedElements.Count) { return true; } if ( DataContract.ChangedElements.Count( dc => !_ChangedElements.ContainsKey(dc.SequencePosition) || !AreEqual(dc, _ChangedElements[dc.SequencePosition])) > 0) { return true; } return false; } } public Dictionary CalculateAppointmentsFromSequence(DateTimeSpan pSpanToConsider) { var lResult = new Dictionary(); DateTime lCurrentStart = RootAppointment.Duration.StartDateTime; DateTime lCurrentEnd = RootAppointment.Duration.EndDateTime; int lCurrentPostion = 0; int lCurrentSequencePosition = 0; if (RootAppointment.Duration.Overlaps(pSpanToConsider)) { lResult.Add(0, _RootAppointment); } lCurrentStart = Next(lCurrentStart, _Frequency); lCurrentEnd = Next(lCurrentEnd, _Frequency); if (_Frequency != ResourceBookingFrequencyType.Once) { while (lCurrentStart <= pSpanToConsider.EndDateTime && lCurrentStart <= _SequenceEnd) { lCurrentPostion++; if (lCurrentPostion%_RepeatInterval == 0) { lCurrentSequencePosition++; if (_ChangedElements.ContainsKey(lCurrentSequencePosition)) { if (_ChangedElements[lCurrentSequencePosition] != null && _ChangedElements[lCurrentSequencePosition].Duration.Overlaps(pSpanToConsider)) { lResult.Add(lCurrentSequencePosition, _ChangedElements[lCurrentSequencePosition]); } } else if (new DateTimeSpan { StartDateTime = lCurrentStart, EndDateTime = lCurrentEnd }.Overlaps(pSpanToConsider)) { var app = new Appointment(); var dts = new DateTimeSpan(); dts.StartDateTime = lCurrentStart; dts.EndDateTime = lCurrentEnd; app.Duration = dts; app.Notice = RootAppointment.Notice; app.Index = RootAppointment.Index; app.Brush = _Resource.GetBrush(); app.Tag = RootAppointment.Tag; string text = RootAppointment.Text; if (text.LastIndexOf("\n") > 0) { text = text.Substring(0, text.LastIndexOf("\n") + 1); text += dts.ToString(); } app.Text = text; lResult.Add(lCurrentSequencePosition, app); } } lCurrentStart = Next(lCurrentStart, _Frequency); lCurrentEnd = Next(lCurrentEnd, _Frequency); } } return lResult; } public void ChangeElement(int pSequencePosition, Appointment pAppointment) { _ChangedElements[pSequencePosition] = pAppointment; StoreDirtyInformation(IsChangedElementsDirty, PropertyName_ChangedElements); } public void ClearChanged() { _NeedsRecalculation = true; _ChangedElements.Clear(); StoreDirtyInformation(IsChangedElementsDirty, PropertyName_ChangedElements); } public void DeleteElement(int pSequencePosition) { _ChangedElements[pSequencePosition] = null; if (_AppointmentsInSpan.ContainsKey(pSequencePosition)) { _AppointmentsInSpan.Remove(pSequencePosition); } StoreDirtyInformation(IsChangedElementsDirty, PropertyName_ChangedElements); } public Appointment GetAppointment(int pSequencePostion) { if (_AppointmentsInSpan.ContainsKey(pSequencePostion)) { return _AppointmentsInSpan[pSequencePostion]; } return null; } public int GetSequencePosition(Appointment pAppointment) { foreach (var iPair in _AppointmentsInSpan) { if (iPair.Value == pAppointment) { return iPair.Key; } } return -1; } public DateTimeSpan GetSequenceSpan() { return new DateTimeSpan { StartDateTime = RootAppointment.Duration.StartDateTime, EndDateTime = SequenceEnd }; } public void UpdatePossibleFrequencies(DateTime pStartDate) { DateTimeFormatInfo lDateInfo = DateTimeFormatInfo.CurrentInfo; _PossibleFrequencies.Single(f => f.Frequency == ResourceBookingFrequencyType.Weekly).Translation = "jeden " + lDateInfo.GetDayName(pStartDate.DayOfWeek); _PossibleFrequencies.Single(f => f.Frequency == ResourceBookingFrequencyType.Monthly).Translation = "jeden " + pStartDate.Day + "ten des Monats"; _PossibleFrequencies.Single(f => f.Frequency == ResourceBookingFrequencyType.MonthlyOnFirstDay).Translation = "jeden " + pStartDate.GetWeekdayOccurence(true) + ". " + lDateInfo.GetShortestDayName(pStartDate.DayOfWeek) + ". des Monats"; _PossibleFrequencies.Single(f => f.Frequency == ResourceBookingFrequencyType.MonthlyOnLastDay).Translation = "jeden " + pStartDate.GetWeekdayOccurence(false) + ". letzten " + lDateInfo.GetShortestDayName(pStartDate.DayOfWeek) + ". des Monats"; } protected override void InitByDataContract(BookingSequenceDC pDataContract) { string text = string.Empty; if (pDataContract.RootBooking.Employee != null) { text = pDataContract.RootBooking.Employee.FirstName + " " + pDataContract.RootBooking.Employee.LastName + ":\n"; } if (pDataContract.Resource != null) { text += pDataContract.Resource.Name + "\n"; } if (!String.IsNullOrEmpty(pDataContract.RootBooking.Notice)) { text += "\n"; text += pDataContract.RootBooking.Notice; text += "\n"; } text += "\n"; if (pDataContract.RootBooking.Duration.StartDate.Date == pDataContract.RootBooking.Duration.EndDate.Date) { // return StartDateTime.ToMyDateTimeString() + " " + StartDateTime.ToShortTimeString() + " - " + EndDateTime.ToMyDateTimeString() + " " + EndDateTime.ToShortTimeString(); text += String.Format("{0:ddd, dd.MM.yy HH:mm} - {1:HH:mm}", pDataContract.RootBooking.Duration.StartDateTime, pDataContract.RootBooking.Duration.EndDateTime); // text += DataContract.RootBooking.Duration.ToString(); } else { text += pDataContract.RootBooking.Duration.ToString(); } RootAppointment = new Appointment { Duration = pDataContract.RootBooking.Duration, Notice = pDataContract.RootBooking.Notice, Text = text, Tag = pDataContract.RootBooking.Employee, }; if (pDataContract.Resource != null) { RootAppointment.Index = (int) pDataContract.Resource.ResourceOid.Value; RootAppointment.Brush = pDataContract.Resource.GetBrush(); } if (pDataContract.ChangedElements == null) { pDataContract.ChangedElements = new List(); } foreach (ResourceBookingDC iBooking in pDataContract.ChangedElements) { if (!_ChangedElements.ContainsKey(iBooking.SequencePosition)) { _ChangedElements.Add( iBooking.SequencePosition, iBooking.IsDeleted ? null : new Appointment { Duration = iBooking.Duration.Clone(), Notice = iBooking.Notice, Index = RootAppointment.Index, Brush = RootAppointment.Brush, Tag = iBooking.Employee }); } } _Frequency = pDataContract.Frequency; _RepeatInterval = pDataContract.RepeatInterval; _SequenceEnd = pDataContract.SequenceEnd; _Resource = pDataContract.Resource; _Notice = pDataContract.Notice; _Employee = pDataContract.Employee; UpdatePossibleFrequencies(_RootAppointment.Duration.StartDateTime); } protected override BookingSequenceDC MapToDataContract(BookingSequenceDC pDataContract, bool doCommit) { pDataContract.Frequency = _Frequency; pDataContract.RepeatInterval = _RepeatInterval; pDataContract.Notice = _Notice; pDataContract.Resource = _Resource; pDataContract.SequenceEnd = _SequenceEnd; pDataContract.Employee = RootAppointment.Tag as CompactEmployeeDC; pDataContract.RootBooking.Duration = RootAppointment.Duration.Clone(); pDataContract.RootBooking.Notice = RootAppointment.Notice; pDataContract.RootBooking.Employee = RootAppointment.Tag as CompactEmployeeDC; if (_Frequency == ResourceBookingFrequencyType.Once) { pDataContract.SequenceEnd = pDataContract.RootBooking.Duration.EndDateTime; } pDataContract.ChangedElements.RemoveRange(dc => !_ChangedElements.ContainsKey(dc.SequencePosition)); foreach (ResourceBookingDC iDC in pDataContract.ChangedElements) { if (_ChangedElements[iDC.SequencePosition] != null) { iDC.Duration = _ChangedElements[iDC.SequencePosition].Duration.Clone(); iDC.Notice = _ChangedElements[iDC.SequencePosition].Notice; iDC.Employee = _ChangedElements[iDC.SequencePosition].Tag as CompactEmployeeDC; } else { iDC.IsDeleted = true; } } foreach ( var iEntry in _ChangedElements.Where( entry => pDataContract.ChangedElements.SingleOrDefault(dc => dc.SequencePosition == entry.Key) == null)) { if (iEntry.Value == null) { pDataContract.ChangedElements.Add( new ResourceBookingDC { SequencePosition = iEntry.Key, IsDeleted = true, Duration = null }); } else { pDataContract.ChangedElements.Add( new ResourceBookingDC { SequencePosition = iEntry.Key, IsDeleted = false, Duration = iEntry.Value.Duration.Clone(), Notice = iEntry.Value.Notice, Employee = iEntry.Value.Tag as CompactEmployeeDC }); } } return pDataContract; } private bool AreEqual(ResourceBookingDC x, Appointment y) { NullCompareResult lResult = Utils.NullCompare(x, y); return lResult.BothNotNull ? x.Duration.StartDateTime == y.Duration.StartDateTime && x.Duration.EndDateTime == y.Duration.EndDateTime && x.Notice == y.Notice : lResult.Different; } private void Duration_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == DateTimeSpan.PropertyName_StartDate) { UpdatePossibleFrequencies(_RootAppointment.Duration.StartDateTime); } } private DateTime Next(DateTime pDate, ResourceBookingFrequencyType pFrequency) { switch (pFrequency) { case ResourceBookingFrequencyType.Daily: return pDate.AddDays(1); case ResourceBookingFrequencyType.Weekly: return pDate.AddDays(7); case ResourceBookingFrequencyType.Monthly: return pDate.AddMonths(1); case ResourceBookingFrequencyType.MonthlyOnFirstDay: return pDate.AddMonthsDayDependent(1, true); case ResourceBookingFrequencyType.MonthlyOnLastDay: return pDate.AddMonthsDayDependent(1, false); default: return pDate; } } private void _RootAppointment_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == Appointment.PropertyName_Duration) { UpdatePossibleFrequencies(_RootAppointment.Duration.StartDateTime); } StoreDirtyInformation(!AreEqual(DataContract.RootBooking, _RootAppointment), PropertyName_RootAppointment); } } }