using System;
using System.Collections;
using System.ComponentModel;
using BS.Shared.Core;
using BS.Shared.Services;
using BeWo.Data.Access;
using BeWo.Data.Entities;
using DevExpress.XtraReports.UI;
using BeWo.Report.ReportObjects;
using BeWo.Report;
using System.Collections.Generic;

namespace BeWo.ZMDLengerichReports
{
    public partial class Stundenzettel : DevExpress.XtraReports.UI.XtraReport, IBeWoReport<ServicesOverviewRO>
    {
        public Stundenzettel()
        {
            InitializeComponent();
        }

        public void SetReportDataSource(ServicesOverviewRO pRO)
        {
            CalculateFLSSollIstThisMonth(pRO);
            //CalculateFLSSollIstTotal(pRO);


            if (pRO.Services != null)
            {
                List<ServicesOverviewRO.ServiceDetail> servicesBillable = new List<ServicesOverviewRO.ServiceDetail>();

                foreach (ServicesOverviewRO.ServiceDetail s in pRO.Services)
                {
					if (s.IsBillable)
					{
						s.Minutes = s.Minutes*(double)pRO.RateFactor;
						servicesBillable.Add(s);
					}
                }

                pRO.Services = servicesBillable;
            }

            this.bindingSource1.DataSource = pRO;
        }

        public void CalculateFLSSollIstTotal(ServicesOverviewRO pRO)
        {
            double totalFLMBillable = pRO.TotalFLMBillable * (double)pRO.RateFactor;

            decimal flmSoll = 0;

            DateTime startHP = pRO.StartDate;

            if (!String.IsNullOrEmpty(pRO.ApprovedStartDate))
            {
                DateTime.TryParse(pRO.ApprovedStartDate, out startHP);
            }
            else
            {
                if (!String.IsNullOrEmpty(pRO.RequestedStartDate))
                {
                    DateTime.TryParse(pRO.RequestedStartDate, out startHP);
                }
            }

            TimeSpan ts = pRO.StartDate.Subtract(startHP);

            decimal flsPerWeek = pRO.ApprovedFLSPerWeek;
            int months = (int)Math.Round(ts.TotalDays / 30);


            decimal flmSollBisEndeInsgesamtNachAlterBerechnung = 0;
            int daysPassed = 0;

            ts = pRO.EndDate.Subtract(startHP);

            daysPassed = ts.Days + 1;

            flmSollBisEndeInsgesamtNachAlterBerechnung = ((daysPassed / 7m) * flsPerWeek) * 60;

            if (!pRO.FreeMinutesThisMonth.HasValue)
                pRO.FreeMinutesThisMonth = 0;
            decimal minutenIstGesamt = flmSollBisEndeInsgesamtNachAlterBerechnung - pRO.FreeMinutesThisMonth.Value;

            flmSoll = (flsPerWeek * 4.34m * 60) * months;


            decimal minutenLetztenMonat = minutenIstGesamt - (decimal)totalFLMBillable;

            pRO.FreeMinutesThisMonth = flmSoll - minutenLetztenMonat;


        }

        public void CalculateFLSSollIstThisMonth(ServicesOverviewRO ro)
        {
            if (ro.SupportConceptCostBearer != null && ro.SupportConceptCostBearer.CostBearer2SupportConceptOid != null)
            {
                if (ro.SupportConceptCostBearer.StartDate != null)
                {
                    CostBearer2SupportConcept c2s =
                        DAOFactory.GenericDAO.LoadByID<CostBearer2SupportConcept>(
                            ro.SupportConceptCostBearer.CostBearer2SupportConceptOid.Value);

                    var calc = Calculations.GetInstance(c2s.CostBearer.ID);
                    DateTime startHilfeplan = ro.SupportConceptCostBearer.StartDate.Value;
                    DateTime startAuswerteMonat = ro.StartDate;

                    decimal flmSollLetztenMonat = 0;
                    decimal flmSollDiesenMonat = 0;
                    decimal flmIst = 0;
                    int daysPassed = 0;

                    
                    TimeSpan ts;
                    if (startAuswerteMonat > startHilfeplan)
                        ts = ro.EndDate.Subtract(startAuswerteMonat);
                    else
                        ts = ro.EndDate.Subtract(startHilfeplan);
                    DateTime startFuerAbsenceDays = startAuswerteMonat;
                    if (startAuswerteMonat < startHilfeplan && startHilfeplan.Day > 1)
                        startFuerAbsenceDays = startHilfeplan;
                    daysPassed = ts.Days + 1;

                    DateTime endeAuswerteMonats = startAuswerteMonat.AddMonths(1);
                    endeAuswerteMonats = new DateTime(endeAuswerteMonats.Year, endeAuswerteMonats.Month, 1);
	                bool berechneAlteMethode = startAuswerteMonat < new DateTime(2013, 3, 1);


	                int abcenceDays = 0;
					decimal abcenceMaxMinutes = 0;

					if (berechneAlteMethode)
					{
						abcenceDays = GetAbsenceDaysInRange(ro.SupportConceptCostBearer.SupportConcept.Customer.AbsenceTimes,
						                                    startFuerAbsenceDays, endeAuswerteMonats, ro.ApprovedFLSPerWeek);
						abcenceMaxMinutes = GetAbsenceMaxMinutesInRange(ro.SupportConceptCostBearer.SupportConcept.Customer.AbsenceTimes,
						                                                startFuerAbsenceDays, endeAuswerteMonats, ro.ApprovedFLSPerWeek);
					}
	                ro.ApprovedFLSPerMonth = ro.ApprovedFLSPerWeek * 4.34m * 60m;
                    daysPassed -= abcenceDays;
                    if ((startHilfeplan.Day > 1 && startHilfeplan > startAuswerteMonat) || abcenceDays > 0) //Bin im erstenMonat && Hilfeplan fängt mitten im Monat an
                    {
                        ro.ApprovedFLSPerMonth = ro.ApprovedFLSPerWeek * (daysPassed / 7m) * 60m;

                    }
                    ro.ApprovedFLSPerMonth += abcenceMaxMinutes;

                    if (ro.ApprovedFLSPerMonth < 0)
                        ro.ApprovedFLSPerMonth = 0;

                    DateTime startIterator = startHilfeplan;
                    while (startIterator < ro.EndDate)
                    {
                        decimal flsSollPerWeekThisMonth = calc.GetApprovedHoursPerWeek(ro.SupportConceptCostBearer, startIterator, false) ?? 0;

                        decimal flmSollThisMonth = flsSollPerWeekThisMonth * 4.34m * 60m;

                        DateTime endeDesMonats = startIterator.AddMonths(1);
                        endeDesMonats = new DateTime(endeDesMonats.Year, endeDesMonats.Month, 1);
                        daysPassed = endeDesMonats.Subtract(startIterator).Days;

                        DateTime nextstart = startIterator.AddMonths(1);
                        nextstart = new DateTime(nextstart.Year, nextstart.Month, 1);
						berechneAlteMethode = startIterator < new DateTime(2013, 3, 1);
	                    abcenceDays = 0;
						if (berechneAlteMethode)
						{
							abcenceDays = GetAbsenceDaysInRange(ro.SupportConceptCostBearer.SupportConcept.Customer.AbsenceTimes,
							                                    startIterator, nextstart, flsSollPerWeekThisMonth);
							daysPassed -= abcenceDays;
						}



	                    if (startIterator.Day > 1 || abcenceDays > 0) //Bin im erstenMonat && Hilfeplan fängt mitten im Monat an
                        {
                            flmSollThisMonth = flsSollPerWeekThisMonth * (daysPassed / 7m) * 60m;
                        }

						if (berechneAlteMethode)	
							flmSollThisMonth += GetAbsenceMaxMinutesInRange(ro.SupportConceptCostBearer.SupportConcept.Customer.AbsenceTimes, startIterator, nextstart, flsSollPerWeekThisMonth);



                        if (startIterator < ro.StartDate)
                            flmSollLetztenMonat += flmSollThisMonth;
                        else
                        {
                            flmSollDiesenMonat = flmSollThisMonth;
                        }


                        startIterator = nextstart;
                    }



                    // Berechne FLM Ist bis Ende des Monats vom Quittierungsbeleg
                    IList<ServiceRecord> allServiceRecords = c2s.ServiceRecords;
                    decimal minutenIst = 0;

                    DateTime end = ro.EndDate.Date.AddDays(1);

                    Dictionary<long, bool> groupBookingDict = new Dictionary<long, bool>();
                    foreach (var item in allServiceRecords)
                    {
                        if (!item.GroupOid.HasValue || !groupBookingDict.ContainsKey(item.GroupOid.Value))
                        {
                            if (item.Start != null)
                            {
                                if (item.Start >= ro.SupportConceptCostBearer.StartDate.Value && item.Start.Value < end)
                                {
                                    if (item.ServiceDescription != null &&
                                        item.ServiceDescription.ServiceCategory != null &&
                                        item.ServiceDescription.ServiceCategory.IsBillable)
                                    {
                                        minutenIst += (item.RoundedDuration *
                                                       item.ServiceDescription.ServiceCategory.Percentage) / 100;

                                        if (item.GroupOid.HasValue)
                                            groupBookingDict.Add(item.GroupOid.Value, true);
                                    }
                                }
                            }
                        }
                    }
                    minutenIst *= ro.RateFactor;

                    decimal minutenBisLetztenMonat = minutenIst - ((decimal)ro.TotalFLMBillable * ro.RateFactor);

                    ro.FreeMinutesThisMonth = flmSollLetztenMonat - minutenBisLetztenMonat;
                }
            }

        }

		private decimal GetAbsenceMaxMinutesInRange(List<BS.Shared.DataContracts.AbsenceTimeDC> absenceTimes, DateTime start, DateTime end, decimal flsPerWeek)
		{
			decimal flsPerDay = flsPerWeek / 7;
			decimal maxMinutes = 0;
			if (absenceTimes != null)
			{
				foreach (var item in absenceTimes)
				{
					decimal tage = 0;
					decimal maxMinutesPerDay = 0;

					if (item.Reason.BillableMinutes.HasValue && item.Reason.BillableMinutes.Value > 0 && item.Reason.BillableMinutes < (flsPerWeek * 60))
					{
						int daysInMonth = DateTime.DaysInMonth(start.Year, start.Month);
						maxMinutesPerDay = (item.Reason.BillableMinutes.Value * 4.34m) / daysInMonth;

						DateTimeSpan span = new DateTimeSpan();

						span.StartDate = start;

						if (item.Start.HasValue && item.Start.Value > span.StartDate)
						{
							span.StartDate = item.Start.Value;
						}
						span.EndDate = end;
						if (item.End.HasValue && item.End.Value.Date.AddDays(1) < span.EndDate)
						{
							span.EndDate = item.End.Value.Date.AddDays(1);
						}
						if (span.EndDate >= start && span.StartDate < end)
						{
							tage += (decimal)span.GetTimeSpan().TotalHours;
						}
					}
					tage /= 24;
					maxMinutes += (maxMinutesPerDay * tage);
					//}
				}
			}

			return maxMinutes;
		}

		private int GetAbsenceDaysInRange(List<BS.Shared.DataContracts.AbsenceTimeDC> absenceTimes, DateTime start, DateTime end, decimal flsPerWeek)
		{
			decimal tage = 0;
			if (absenceTimes != null)
			{
				foreach (var item in absenceTimes)
				{
					//if (!String.IsNullOrEmpty(item.AbsenceReason.Description) && (item.AbsenceReason.Description.ToLower().IndexOf("urlaub") >= 0
					//                                                              || item.AbsenceReason.Description.ToLower().IndexOf("krank") >= 0))
					//{
					if (item.Reason.BillableMinutes.HasValue && item.Reason.BillableMinutes.Value > 0 && item.Reason.BillableMinutes < (flsPerWeek * 60))
					{

						DateTimeSpan span = new DateTimeSpan();

						span.StartDate = start;

						if (item.Start.HasValue && item.Start.Value > span.StartDate)
						{
							span.StartDate = item.Start.Value;
						}
						span.EndDate = end;
						if (item.End.HasValue && item.End.Value.Date.AddDays(1) < span.EndDate)
						{
							span.EndDate = item.End.Value.Date.AddDays(1);
						}
						if (span.EndDate >= start && span.StartDate < end)
						{
							tage += (decimal)span.GetTimeSpan().TotalHours;
						}
					}
					//}
				}
			}
			tage /= 24;
			return (int)tage;
		}
	}
}
