using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using BeWo.Data;
using BeWo.Data.Access;
using BeWo.Data.Entities;
using BeWo.Service.DCEntityMapper;
using BeWo.Service.Plugins;
using BS.Shared;
using BS.Shared.Core;
using BS.Shared.DataContracts;
using BS.Shared.Services;
using BS.Shared.Extensions;

namespace BeWo.Report.ReportObjects
{
    public class ServicesOverviewRO : AbstractBeWoReportObject<ServicesOverviewRO>
    {
        private List<EmployeeDetail> _AllEmployees = new List<EmployeeDetail>();

        private List<ServiceDetail> _Services = new List<ServiceDetail>();

        private List<ServiceDoubleDetail> _ServicesDouble = new List<ServiceDoubleDetail>();

        public string AbsenceTimes { get; set; }

        public List<AbsenceTime> Abwesenheiten { get; set; } 

        public List<EmployeeDetail> AllEmployees
        {
            get
            {
                return this._AllEmployees;
            }

            set
            {
                this._AllEmployees = value;
            }
        }

        public string ApprovedEndDate { get; set; }

        public decimal ApprovedFLSPerMonth { get; set; }

        public decimal ApprovedFLSPerMonthTotal { get; set; }

        public decimal ApprovedFLSPerWeek { get; set; }

        public decimal ApprovedFLSPerWeekTotal { get; set; }

        public decimal ApprovedFLSTotal { get; set; }

        public string ApprovedStartDate { get; set; }

        public string ContactEmployee { get; set; }

        public string Costbearer { get; set; }

        public DateTime? CustomerBirthday { get; set; }

        public string CustomerCity { get; set; }

        public string CustomerFirstName { get; set; }

        public string CustomerLastName { get; set; }

        public string CustomerName { get; set; }

        public string CustomerPostalCode { get; set; }

        public string CustomerStreet { get; set; }

        public DateTime EndDate { get; set; }

        public decimal? FreeMinutesThisMonth { get; set; }

		public decimal MinutenGeleistetGesamt { get; set; }

		public decimal MinutenSollGesamt { get; set; }

        public string MainAttendant { get; set; }

        public string MainAttendantCommaSeperated { get; set; }

        public string Month { get; set; }

        public string ReferenceNumber { get; set; }

        public string RequestedEndDate { get; set; }

        public string RequestedStartDate { get; set; }

        public string Salutation { get; set; }

        public decimal RateFactor { get; set; }

        public List<ServiceDetail> Services
        {
            get
            {
                return this._Services;
            }

            set
            {
                this._Services = value;
            }
        }

        public List<ServiceDoubleDetail> ServicesDouble
        {
            get
            {
                return this._ServicesDouble;
            }

            set
            {
                this._ServicesDouble = value;
            }
        }

        public DateTime StartDate { get; set; }

        public SupportConceptCostBearerRelDC SupportConceptCostBearer { get; set; }

        public string TotalFLHoursMinutesString { get; set; }

        public double TotalFLM { get; set; }

        public double TotalFLMBillable { get; set; }

        public string TotalFLMPerCostBearer { get; set; }

        public double TotalFLMQualified { get; set; }

        public string TotalFLMQualifiedString { get; set; }

        public string TotalFLMString { get; set; }

        public double TotalFLMUnqualified { get; set; }

        public string TotalFLMUnqualifiedString { get; set; }

        public double TotalFLS { get; set; }

        public string TotalFLSPerCostBearer { get; set; }

        public double TotalFLSQualified { get; set; }

        public string TotalFLSQualifiedString { get; set; }

        public string TotalFLSString { get; set; }

        public double TotalFLSUnqualified { get; set; }

        public string TotalFLSUnqualifiedString { get; set; }

		public double TotalGefahreneKilometer { get; set; }

		public string TotalGefahreneKilometerString { get; set; }

        public int Year { get; set; }

		public IList<CostBearer2SupportConcept> CostBearer2SupportConceptList { get; set; }

        // private CostBearer2SupportConceptData CostBearer2SupportConceptData { get; set; }

		public static List<ServicesOverviewRO> Create(int pMonth, int pYear, long orgaOid, long empOid, int startDay, int endDay, long? serviceCategoryOid = null, bool disableEmptySupportConcepts = true)
        {
            var roList = new List<ServicesOverviewRO>();

	        List<Customer> customers = null;
			
			ApplicationUser loggedInUser = null;
	        
	        if (LoggedInUserOperationContextExt.Current != null && LoggedInUserOperationContextExt.Current.User != null)
	        {
				loggedInUser = LoggedInUserOperationContextExt.Current.User;


	        }
	        else
	        {
				loggedInUser = SessionFacade.LoggedInUser;
	        }

			if (loggedInUser != null && loggedInUser.Employee != null)
	        {

		        if (!HasRight(loggedInUser, UserRightType.CustomerView_View))
		        {
			        customers = new List<Customer>();
			        foreach (var e2c in loggedInUser.Employee.Employee2CustomerList)
			        {
				        customers.Add(e2c.Customer);
			        }
		        }
	        }

	        if (customers == null)
	        {
				customers = DAOFactory.GenericDAO.GetAllActive<Customer>().OrderBy(ob => ob.Person.LastName + ", " + ob.Person.FirstName).ToList();    
	        }
	        

            if (startDay > endDay)
            {
                int temp = startDay;
                startDay = endDay;
                endDay = temp;
            }
            var pSpan = new DateTimeSpan();
            pSpan.StartDateTime = new DateTime(pYear, pMonth, startDay);
            pSpan.EndDateTime = pSpan.StartDateTime.AddDays(endDay - startDay + 1).AddTicks(-1);

            // IList<Customer> customers = DAOFactory.SearchDAO.GetAllCustomerWithServiceRecordsInSpan(pSpan).OrderBy(ob => ob.Person.LastName + ", " + ob.Person.FirstName).ToList();
            foreach (Customer customer in customers)
            {
                ServicesOverviewRO ro = Create(customer, pSpan, disableEmptySupportConcepts, orgaOid, empOid, serviceCategoryOid);
                if (ro != null)
                {
                    roList.Add(ro);
                }
            }
			
            return roList;
            // return DAOFactory.SearchDAO.FindSupportConceptsInSpan(pSpan).OrderBy(ob => ob.Customer.Person.LastName + ", " + ob.Customer.Person.FirstName).Select(
            // sc => Create(sc.Customer.Oid.Value, pMonth, pYear, true)).ToList();
        }

		
		private static bool HasRight(ApplicationUser user, UserRightType right)
		{
			return GetGrantedRights(user).Contains(right);
		
		}

		public static List<UserRightType> GetGrantedRights(ApplicationUser user)
		{
			var rights = new List<UserRightType>();
			foreach (var ug in user.UserGroups)
			{
				foreach (var rr in ug.Rights)
				{
					rights.Add(rr.RightType);
				}
			}

			return rights;
		}

        public static ServicesOverviewRO Create(long pCustomerOid, int pMonth, int pYear, bool disableEmptySupportConcepts, long orgaOid, long empOid, int start, int end, long? serviceCategoryOid = null)
        {
            var pSpan = new DateTimeSpan();
            if (start > end)
            {
                int temp = start;
                start = end;
                end = temp;
            }
            pSpan.StartDateTime = new DateTime(pYear, pMonth, start);
            pSpan.EndDateTime = pSpan.StartDateTime.AddDays(end - start + 1).AddTicks(-1);

            var lCustomer = DAOFactory.GenericDAO.LoadByID<Customer>(pCustomerOid);
            return Create(lCustomer, pSpan, disableEmptySupportConcepts, orgaOid, empOid, serviceCategoryOid);
        }

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

                    IList<ServiceRecord> allServiceRecords = c2s.ServiceRecords;

                    decimal flmSoll = 0;
                    int daysPassed = 0;

                    TimeSpan ts = this.EndDate.Subtract(this.SupportConceptCostBearer.StartDate.Value);

                    daysPassed = ts.Days + 1;

					var calc = PluginLoader.FindClass<Calculations>(c2s.CostBearer.ID) ?? Calculations.GetInstance(c2s.CostBearer.ID);
                    decimal? flsnullable = calc.GetApprovedHoursPerWeekAverage(this.SupportConceptCostBearer, false);
                    //decimal? flsnullable = calc.GetApprovedHoursPerWeek(this.SupportConceptCostBearer, span.StartDateTime, false);

                    decimal fls = 0;
                    if (flsnullable.HasValue)
                        fls = flsnullable.Value;
                    // decimal fls = CostRateCalculationService.GetApprovedFLSPerWeek(this.CostBearer2SupportConceptData);

                    flmSoll = ((daysPassed / 7m) * fls) * 60;

                    decimal minutenIst = 0;
                    
                    DateTime end = this.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 >= this.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);
                                    }
                                }
                            }
                        }
                    }

					this.MinutenGeleistetGesamt = minutenIst;
					this.MinutenSollGesamt = flmSoll;
                    this.FreeMinutesThisMonth = flmSoll - minutenIst;
                }
            }
        }

        private static ServicesOverviewRO Create(Customer customer, DateTimeSpan span, bool disableEmptySupportConcepts, long orgaOid, long empOid, long? serviceCategoryOid = null)
        {
            // IList<ServiceRecord> lServiceRecords = pServiceRecords;
            // if (lServiceRecords == null)
            IList<ServiceRecord> lServiceRecords = DAOFactory.SearchDAO.FindCustomerServiceRecords(customer.Oid.Value, span, null, null);

			
            var lResult = new ServicesOverviewRO();
            lResult.Abwesenheiten = new List<AbsenceTime>();
			lResult.CostBearer2SupportConceptList = new List<CostBearer2SupportConcept>();
            lResult.Month = ReportHelper.GetMonthName(span.StartDateTime.Month);
            lResult.Year = span.StartDateTime.Year;
            lResult.StartDate = span.StartDate;
            lResult.EndDate = span.EndDate;

            lResult.CustomerFirstName = customer.Person.FirstName;
            lResult.CustomerLastName = customer.Person.LastName;
            lResult.CustomerBirthday = customer.Person.DateOfBirth;

            lResult.CustomerName = customer.Person.FirstName + " " + customer.Person.LastName;

            if (customer.Person.Address != null)
            {
                lResult.CustomerStreet = customer.Person.Address.Street;
                lResult.CustomerPostalCode = customer.Person.Address.PostalCode;
                lResult.CustomerCity = customer.Person.Address.Town;
            }

			foreach (var item in customer.Employee2CustomerList)
			{
				foreach (var valueEntry in item.ValueList)
				{
					if (valueEntry.Entry.SystemEntryID != null && valueEntry.Entry.SystemEntryID.Value == SystemEntryID.EmployeeRoleMainAttendant)
					{
						var empName = item.Employee.Person.FirstName + " " + item.Employee.Person.LastName;
                        var empName2 = string.Format("{0}, {1}", item.Employee.Person.LastName, item.Employee.Person.FirstName);

                        if (String.IsNullOrEmpty(lResult.MainAttendantCommaSeperated))
					    {
                            lResult.MainAttendantCommaSeperated = empName2;
					    }
                        else if (!lResult.MainAttendantCommaSeperated.Contains(empName2))
                        {
                            lResult.MainAttendantCommaSeperated += empName2;
                        }

						if (String.IsNullOrEmpty(lResult.MainAttendant))
						{
						    lResult.MainAttendant = empName;
						}
						else
						{
							if (!lResult.MainAttendant.Contains(empName))
							{
								lResult.MainAttendant += ", " + empName;
							}
						}

					}
				}
			}

            var flmBillablePerCostBearer = new Dictionary<string, double>();
            var flmNotBillableServiceDescAbbr = new Dictionary<string, double>();
            var flmPerEmployee = new Dictionary<Person, double>();
			Dictionary<Person, Employee> personPerEmployee = new Dictionary<Person, Employee>();
            double flmNotBillable = 0;
            double flmBillable = 0;

            double flmQualified = 0;
            double flmUnqualified = 0;

            var allServices = new List<ServiceDetail>();

            var cb2scOid2Count = new Dictionary<long, int>();
            var cb2scOid2FLSApprovedPerWeek = new Dictionary<long, decimal>();
            var cb2scOid2FLSApprovedTotal = new Dictionary<long, decimal>();
            var cb2scOid2RefNumber = new Dictionary<long, string>();

            // Dictionary<long, CostBearer2SupportConceptData> cb2scOid2Data = new Dictionary<long, CostBearer2SupportConceptData>();
            var cb2scs = new Dictionary<long, SupportConceptCostBearerRelDC>();
            var groupBookingDict = new Dictionary<long, ServiceRecord>();

            foreach (var iSr in lServiceRecords)
            {
	            lResult.TotalGefahreneKilometer += Convert.ToDouble(iSr.DistanceInMeter);

                bool cont = !(empOid != 0 && iSr.EmployeeOid != null && iSr.EmployeeOid != empOid);
				
                CostBearer2SupportConcept cb2sc = null;
                if (cont)
                {
                    cb2sc = iSr.CostBearer2SupportConcept;
                }

                if (cb2sc == null)
                {
                    cont = false;
                }
                else if (cont && orgaOid != 0 && cb2sc.CostBearer.Organisation != null && cb2sc.CostBearer.Organisation.Oid.Value != orgaOid)
                {
                    cont = false;
                }

                if (cont)
                {
                    if (cb2sc.SupportConcept.IsActive == ActivationTypeId.Deleted)
                    {
                        cont = false;
                    }
                }

                if (cont && iSr.GroupOid != null && groupBookingDict.ContainsKey(iSr.GroupOid.Value))
                {
                    cont = false;
                }
                if (cont && serviceCategoryOid.HasValue &&
                    iSr.ServiceDescription.ServiceCategory.Oid != serviceCategoryOid)
                    cont = false;

                if (cont)
                {
                    lResult.ApprovedStartDate = cb2sc.ApprovedStartDate != null
                                                    ? String.Format("{0:dd.MM.yyyy}", cb2sc.ApprovedStartDate.Value)
                                                    : string.Empty;
                    lResult.ApprovedEndDate = cb2sc.ApprovedEndDate != null
                                                  ? String.Format("{0:dd.MM.yyyy}", cb2sc.ApprovedEndDate.Value)
                                                  : string.Empty;

                    lResult.RequestedStartDate = cb2sc.RequestedStartDate != null
                                                     ? String.Format("{0:dd.MM.yyyy}", cb2sc.RequestedStartDate.Value)
                                                     : string.Empty;
                    lResult.RequestedEndDate = cb2sc.RequestedEndDate != null
                                                   ? String.Format("{0:dd.MM.yyyy}", cb2sc.RequestedEndDate.Value)
                                                   : string.Empty;

                    int count = 0;
                    if (cb2scOid2Count.ContainsKey(cb2sc.Oid.Value))
                    {
                        count = cb2scOid2Count[cb2sc.Oid.Value];
                        cb2scOid2Count.Remove(cb2sc.Oid.Value);
                    }
                    else
                    {
	                    lResult.CostBearer2SupportConceptList.Add(cb2sc);
                    }

                    count++;
                    cb2scOid2Count.Add(cb2sc.Oid.Value, count);

                    if (!cb2scOid2FLSApprovedPerWeek.ContainsKey(cb2sc.Oid.Value))
                    {
                        var cb2scDC = cb2sc.MapToNewDC();

            

                        if (cb2sc.CostBearer != null)
                        {

                            if (String.IsNullOrEmpty(lResult.Costbearer))
                                lResult.Costbearer = cb2sc.CostBearer.Organisation.Name;

                            DateTime? start = cb2sc.ApprovedStartDate;
                            if (!start.HasValue)
                                start = cb2sc.RequestedStartDate;
                            DateTime? end = cb2sc.ApprovedEndDate;
                            if (!end.HasValue)
                                end = cb2sc.RequestedEndDate;
                            if (start.HasValue && end.HasValue)
                            {
                                var relDC = cb2sc.MapToNewDC();

                                var rateFactorsInSpanList = relDC.CostBearer.CostRatePeriods.GetSpans(CostRatePeriodType.RateFactor,
                                                                                          start.Value.Date, end.Value.Date).ToList();
                                if (rateFactorsInSpanList.Count > 0)
                                {
                                    var crv = rateFactorsInSpanList.Last().Key;
                                    if (crv != null && crv.CostRateValue.HasValue)
                                    {
                                        lResult.RateFactor = crv.CostRateValue.Value;
                                        lResult.RateFactor = (lResult.RateFactor + 100)/100;
                                    }
                                }
                            }
                        }

						var calc = PluginLoader.FindClass<Calculations>(cb2sc.CostBearer.ID) ?? Calculations.GetInstance(cb2sc.CostBearer.ID);
                        
                        DateTime sdt = span.StartDateTime;
                        if (sdt < cb2scDC.StartDate)
                            sdt = cb2scDC.StartDate.Value;
                        decimal? fls = calc.GetApprovedHoursPerWeek(cb2scDC, sdt, false);
                        //decimal? fls = calc.GetApprovedHoursPerWeekAverage(cb2scDC, false);
                        decimal? flsTotal = calc.GetApprovedHoursTotal(cb2scDC, false);
                        if (!fls.HasValue)
                            fls = 0;
                        if (!flsTotal.HasValue)
                            flsTotal = 0;
                        

                        // decimal fls = CostRateCalculationService.GetApprovedFLSPerWeek(data);
                        // decimal flsTotal = CostRateCalculationService.GetApprovedFLSTotal(data);

                        
                        if (cb2scDC.GetApprovedDuration().HasValue)
                        {
                            foreach (var scap in cb2scDC.ApprovalPeriodList)
                            {
                                if (sdt.InBetween(scap.Span, true))
                                {
									
                                    lResult.ApprovedFLSPerWeekTotal +=
                                        calc.GetApprovedHoursPerWeek(scap, cb2scDC.CostBearer.CostRatePeriods) ?? 0;
                                }
                            }
                            
                        }

                        
                        cb2scOid2FLSApprovedPerWeek.Add(cb2sc.Oid.Value, fls.Value);
                        cb2scOid2FLSApprovedTotal.Add(cb2sc.Oid.Value, flsTotal.Value);

                        // cb2scOid2Data.Add(cb2sc.Oid.Value, data);
                        cb2scs.Add(cb2sc.Oid.Value, cb2scDC);
                    }

                    if (!cb2scOid2RefNumber.ContainsKey(cb2sc.Oid.Value) && !String.IsNullOrEmpty(cb2sc.CustomerReferenceNumber))
                    {
                        cb2scOid2RefNumber.Add(cb2sc.Oid.Value, cb2sc.CustomerReferenceNumber);
                    }

                    ServiceDetail sd = new ServiceDetail
                                       {
                                           CostBearer = iSr.CostBearer2SupportConcept != null && iSr.CostBearer2SupportConcept.CostBearer.Organisation != null
                                                            ? iSr.CostBearer2SupportConcept.CostBearer.Organisation.Name
                                                            : string.Empty, 
                                           StartDate = iSr.Start.Value
                                       };
	                
					sd.ServiceRecordOid = iSr.Oid.Value;

					sd.GefahreneKilometer = iSr.DistanceInMeter.HasValue ? (Convert.ToDouble(iSr.DistanceInMeter)).ToString("0.##") : string.Empty;

                    decimal roundedDur = iSr.RoundedDuration;
                    if (iSr.ServiceDescription != null && iSr.ServiceDescription.ServiceCategory != null && iSr.ServiceDescription.ServiceCategory.Percentage != 100)
                    {
                        roundedDur = (roundedDur * iSr.ServiceDescription.ServiceCategory.Percentage) / 100;
                    }

                    if (iSr.Employee.IsQualified == null || iSr.Employee.IsQualified.Value)
                    {
                        sd.MinutesQualified = Convert.ToDouble(roundedDur);
                        sd.Minutes = sd.MinutesQualified;
                    }
                    else
                    {
                        sd.MinutesUnqualified = Convert.ToDouble(roundedDur);
                        sd.Minutes = sd.MinutesUnqualified;
                    }

                    if (iSr.GroupEmployeeCount != null)
                    {
                        sd.EmployeeCount = iSr.GroupEmployeeCount.Value;
                    }
                    else
                    {
                        sd.EmployeeCount = 1;
                    }

                    if (iSr.GroupPersonCount != null)
                    {
                        sd.CustomerCount = iSr.GroupPersonCount.Value;
                    }
                    else
                    {
                        sd.CustomerCount = 1;
                    }

                    sd.GroupRoundedDuration = iSr.GroupRoundedDuration;
                    if (iSr.GroupRoundedDuration != null)
                    {
                        sd.GroupMinutes = (double)iSr.GroupRoundedDuration.Value;
                    }
                    else
                    {
                        sd.GroupMinutes = sd.Minutes;
                    }

                    if (iSr.GroupOid != null)
                    {
                        sd.IsGroup = true;
                        groupBookingDict.Add(iSr.GroupOid.Value, iSr);
                    }

                    sd.MinutesDateTime = DateTime.Now.Date.AddMinutes(sd.Minutes);

                    sd.EndDate = sd.StartDate.AddMinutes(sd.GroupMinutes);
	                sd.EndDateNotRounded = iSr.End.Value;

                    if (sd.StartDate.Second == 0)
                    {
                        sd.TimeRangeString = String.Format("{0} - {1}", sd.StartDate.ToShortTimeString(), sd.EndDate.ToShortTimeString());

                        sd.StartDateMinutes = sd.StartDate;
                        sd.EndDateMinutes = sd.EndDate;
                    }

                    
                    sd.StartDateString = iSr.Start.Value.ToShortDateString();

                    sd.KW = GetKW(sd.StartDate);

                    flmQualified += sd.MinutesQualified;
                    flmUnqualified += sd.MinutesUnqualified;

                    sd.FLSQualified = sd.MinutesQualified / 60;
                    sd.FLSUnqualified = sd.MinutesUnqualified / 60;

                    sd.FLSQualifiedString = String.Format("{0:0.##}", sd.FLSQualified);
                    sd.FLSQualifiedString = sd.FLSQualifiedString.Replace(".", ",");

                    sd.FLSUnqualifiedString = String.Format("{0:0.##}", sd.FLSUnqualified);
                    sd.FLSUnqualifiedString = sd.FLSUnqualifiedString.Replace(".", ",");

                    string employeeAbbr = iSr.Employee.Person.Abbreviation;
                    string employeeFullName = iSr.Employee.Person.FirstName + " " + iSr.Employee.Person.LastName;

                    if (employeeAbbr == null || employeeAbbr.Length == 0)
                    {
                        employeeAbbr = iSr.Employee.Person.FirstName.Substring(0, 1) + ". " + iSr.Employee.Person.LastName;
                    }

                    sd.EmployeeAbbr = employeeAbbr;
                    sd.EmployeeFullname = employeeFullName;
                    sd.EmployeeNameCommaSeparated = string.Format("{0}, {1}", iSr.Employee.Person.LastName, iSr.Employee.Person.FirstName);

                    sd.Notice = iSr.Notice;
                    if (iSr.ServiceDescription != null)
                    {
                        sd.ServiceDescription = iSr.ServiceDescription.Name;
                        sd.ServiceCategory = iSr.ServiceDescription.ServiceCategory.Name;
                        sd.ServiceCategoryAbbr = iSr.ServiceDescription.ServiceCategory.Abbreviation;
                        if (sd.ServiceCategoryAbbr == null || sd.ServiceCategoryAbbr.Length == 0)
                        {
                            sd.ServiceCategoryAbbr = iSr.ServiceDescription.ServiceCategory.Name;
                        }
                    }

                    double flm = 0;
                    if (iSr.ServiceDescription.ServiceCategory.IsBillable)
                    {
                        if (flmBillablePerCostBearer.ContainsKey(sd.CostBearer))
                        {
                            flm = flmBillablePerCostBearer[sd.CostBearer];
                        }

                        flm += sd.MinutesQualified + sd.MinutesUnqualified;
                        flmBillablePerCostBearer[sd.CostBearer] = flm;

                        flmBillable += sd.MinutesQualified + sd.MinutesUnqualified;

                        sd.IsBillable = true;
                    }
                    else
                    {
                        sd.CostBearer = string.Empty;
                        if (flmNotBillableServiceDescAbbr.ContainsKey(sd.ServiceCategoryAbbr))
                        {
                            flm = flmNotBillableServiceDescAbbr[sd.ServiceCategoryAbbr];
                        }

                        flm += sd.MinutesQualified + sd.MinutesUnqualified;
                        flmNotBillableServiceDescAbbr[sd.ServiceCategoryAbbr] = flm;
                        flmNotBillable += sd.MinutesQualified + sd.MinutesUnqualified;
                        sd.IsBillable = false;
                    }

                    flm = 0;

                    if (iSr.ServiceDescription.ServiceCategory.Name.IndexOf("Negativ") < 0)
                    {
                        if (flmPerEmployee.ContainsKey(iSr.Employee.Person))
                        {
                            flm = flmPerEmployee[iSr.Employee.Person];
                        }
						else
						{
							personPerEmployee[iSr.Employee.Person] = iSr.Employee;
						}
                        flm += sd.MinutesQualified + sd.MinutesUnqualified;

                        flmPerEmployee[iSr.Employee.Person] = flm;
                    }

                    allServices.Add(sd);
                }
            }

            if (disableEmptySupportConcepts && allServices.Count == 0)
            {
                return null;
            }

            int max = 0;
            long oidWithMaxCount = 0;

            foreach (var key in cb2scOid2Count.Keys)
            {
                int count = cb2scOid2Count[key];
                if (count > max)
                {
                    oidWithMaxCount = key;
                    max = count;
                }
            }

	        if (oidWithMaxCount != 0)
	        {
		        if (cb2scOid2FLSApprovedPerWeek.ContainsKey(oidWithMaxCount))
		        {
			        lResult.ApprovedFLSPerWeek = cb2scOid2FLSApprovedPerWeek[oidWithMaxCount];
		        }

		        if (cb2scOid2FLSApprovedTotal.ContainsKey(oidWithMaxCount))
		        {
			        lResult.ApprovedFLSTotal = cb2scOid2FLSApprovedTotal[oidWithMaxCount];
		        }

		        if (cb2scOid2RefNumber.ContainsKey(oidWithMaxCount))
		        {
			        lResult.ReferenceNumber = cb2scOid2RefNumber[oidWithMaxCount];
		        }
	        }
	        if (cb2scOid2Count.Count == 0)
	        {
		        foreach (var sc in customer.SupportConcepts.Where(s => s.IsActive == ActivationTypeId.Active))
		        {
			        foreach (var c2s in sc.CostBearer2SupportConceptList)
			        {
				        if (orgaOid == 0 ||
				            (c2s.CostBearer.Organisation != null && c2s.CostBearer.Organisation.Oid.Value == orgaOid))
				        {
					        if (c2s.StartDate < span.EndDate && c2s.EndDate >= span.StartDate)
					        {
								

								lResult.ApprovedStartDate = c2s.ApprovedStartDate != null
									? String.Format("{0:dd.MM.yyyy}", c2s.ApprovedStartDate.Value)
							        : string.Empty;
								lResult.ApprovedEndDate = c2s.ApprovedEndDate != null
									? String.Format("{0:dd.MM.yyyy}", c2s.ApprovedEndDate.Value)
							        : string.Empty;

								lResult.RequestedStartDate = c2s.RequestedStartDate != null
									? String.Format("{0:dd.MM.yyyy}", c2s.RequestedStartDate.Value)
							        : string.Empty;
								lResult.RequestedEndDate = c2s.RequestedEndDate != null
									? String.Format("{0:dd.MM.yyyy}", c2s.RequestedEndDate.Value)
							        : string.Empty;

								var cb2scDC = c2s.MapToNewDC();
								var calc = PluginLoader.FindClass<Calculations>(c2s.CostBearer.ID) ?? Calculations.GetInstance(c2s.CostBearer.ID);

								DateTime sdt = span.StartDateTime;
								if (sdt < cb2scDC.StartDate)
									sdt = cb2scDC.StartDate.Value;
								
						        lResult.ApprovedFLSPerWeek = calc.GetApprovedHoursPerWeek(cb2scDC, sdt, false) ?? 0;
						        lResult.ApprovedFLSTotal = calc.GetApprovedHoursTotal(cb2scDC, false) ?? 0;
						        lResult.ReferenceNumber = c2s.CustomerReferenceNumber;
					        }
				        }
                
                    
			        }
		        }
				
	        }
            int days = DateTime.DaysInMonth(span.StartDateTime.Year, span.StartDateTime.Month);
            lResult.ApprovedFLSPerMonth = (lResult.ApprovedFLSPerWeek / 7) * days;

            lResult.ApprovedFLSPerMonthTotal = (lResult.ApprovedFLSPerWeekTotal / 7) * days;
            

            lResult.AbsenceTimes = string.Empty;

            if (lResult.RateFactor < 1)
                lResult.RateFactor = 1;

            if (customer.AbsenceTimes != null)
            {
                StringBuilder sb = new StringBuilder();
                
                foreach (AbsenceTime at in customer.AbsenceTimes)
                {
                    if (at.AbsenceSpan != null)
                    {
                        bool cont = !(at.Start != null && at.Start > span.EndDateTime);

                        if (cont && at.End != null && at.End < span.StartDateTime)
                        {
                            cont = false;
                        }

                        if (cont)
                        {
							lResult.Abwesenheiten.Add(at);
                            if (sb.Length > 0)
                            {
                                sb.Append("; ");
                            }

                            sb.Append(at.AbsenceReason.Description);
                            sb.Append(": ");
                            if (at.Start.HasValue)
                            {
                                sb.Append(string.Format("{0:00}", at.Start.Value.Day));
                                sb.Append(".");
                                sb.Append(string.Format("{0:00}", at.Start.Value.Month));
                                sb.Append(".");
                                sb.Append(at.Start.Value.Year.ToString().Substring(2));

                                sb.Append(" - ");

                                if (at.End.HasValue)
                                {
                                    sb.Append(string.Format("{0:00}", at.End.Value.Day));
                                    sb.Append(".");
                                    sb.Append(string.Format("{0:00}", at.End.Value.Month));
                                    sb.Append(".");
                                    sb.Append(at.End.Value.Year.ToString().Substring(2));
                                }
                                else
                                {
                                    sb.Append("...");
                                }
                            }
                        }
                    }
                }

                if (sb.Length > 0)
                {
                    lResult.AbsenceTimes = sb.ToString();
                }
            }

            lResult.TotalFLSPerCostBearer = string.Empty;
            lResult.TotalFLMPerCostBearer = string.Empty;

            foreach (string cb in flmBillablePerCostBearer.Keys)
            {
                if (lResult.TotalFLSPerCostBearer.Length > 0)
                {
                    lResult.TotalFLSPerCostBearer += ", ";
                }

                lResult.TotalFLSPerCostBearer += cb + ": " + String.Format("{0:0.##}", flmBillablePerCostBearer[cb] / 60).Replace(".", ",") + " FLS";

                if (lResult.TotalFLMPerCostBearer.Length > 0)
                {
                    lResult.TotalFLMPerCostBearer += ", ";
                }

                lResult.TotalFLMPerCostBearer += cb + ": " + String.Format("{0:0.##}", flmBillablePerCostBearer[cb]).Replace(".", ",") + " FLM";
            }

            foreach (string abbr in flmNotBillableServiceDescAbbr.Keys)
            {
                if (lResult.TotalFLSPerCostBearer.Length > 0)
                {
                    lResult.TotalFLSPerCostBearer += ", ";
                }

                lResult.TotalFLSPerCostBearer += abbr + ": " + String.Format("{0:0.##}", flmNotBillableServiceDescAbbr[abbr] / 60).Replace(".", ",") + " FLS";

                if (lResult.TotalFLMPerCostBearer.Length > 0)
                {
                    lResult.TotalFLMPerCostBearer += ", ";
                }

                lResult.TotalFLMPerCostBearer += abbr + ": " + String.Format("{0:0.##}", flmNotBillableServiceDescAbbr[abbr]).Replace(".", ",") + " FLM";
            }

            lResult.TotalFLSPerCostBearer = "Gesamt: " + lResult.TotalFLSPerCostBearer;
            lResult.TotalFLMPerCostBearer = "Gesamt: " + lResult.TotalFLMPerCostBearer;

            foreach (Person p in flmPerEmployee.Keys)
            {
                EmployeeDetail detail = new EmployeeDetail();

                detail.EmployeeName = p.FirstName.Substring(0, 1) + ". " + p.LastName;
                detail.TotalFLM = flmPerEmployee[p];

                detail.TotalFLS = detail.TotalFLM / 60;
                detail.TotalFLSString = String.Format("{0:0.##}", detail.TotalFLS).Replace(".", ",");
				
				if (personPerEmployee.ContainsKey(p))
				{
					detail.Employee = personPerEmployee[p];
				}

                lResult._AllEmployees.Add(detail);
            }

            allServices.Sort((x, y) =>
            {
	            var c = x.StartDate.CompareTo(y.StartDate);
	            if (c != 0)
	            {
		            return c;
	            }
	            return x.ServiceRecordOid.CompareTo(y.ServiceRecordOid);
            });

            int i = 0;

            foreach (var iSD in allServices)
            {
                lResult._Services.Add(iSD);
                ServiceDoubleDetail sdd = new ServiceDoubleDetail();
                sdd.CostBearer = iSD.CostBearer;
                sdd.EmployeeName = iSD.EmployeeAbbr;
                sdd.Minutes = iSD.MinutesQualified + iSD.MinutesUnqualified;
                sdd.CustomerCount = iSD.CustomerCount;
                sdd.FLS = sdd.Minutes / 60;

                sdd.FLSString = String.Format("{0:0.##}", sdd.FLS);
                sdd.FLSString = sdd.FLSString.Replace(".", ",");

                sdd.ServiceCategoryAbbr = iSD.ServiceCategoryAbbr;
                sdd.ServiceCategory = iSD.ServiceCategory;
                sdd.ServiceDescription = iSD.ServiceDescription;

                sdd.StartDate = iSD.StartDate;

                sdd.IsBillable = iSD.IsBillable;

                if (i < (allServices.Count / (float)2))
                {
                    lResult._ServicesDouble.Add(sdd);
                }
                else
                {
                    sdd = lResult._ServicesDouble[i - lResult._ServicesDouble.Count];
                    sdd.CostBearer2 = iSD.CostBearer;
                    sdd.EmployeeName2 = iSD.EmployeeAbbr;
                    sdd.Minutes2 = iSD.MinutesQualified + iSD.MinutesUnqualified;
                    sdd.CustomerCount2 = iSD.CustomerCount;
                    sdd.FLS2 = sdd.Minutes2 / 60;
                    sdd.FLSString2 = String.Format("{0:0.##}", sdd.FLS2);
                    sdd.FLSString2 = sdd.FLSString2.Replace(".", ",");

                    sdd.ServiceCategoryAbbr2 = iSD.ServiceCategoryAbbr;
                    sdd.ServiceCategory2 = iSD.ServiceCategory;
                    sdd.ServiceDescription2 = iSD.ServiceDescription;

                    sdd.StartDate2 = iSD.StartDate;

                    sdd.IsBillable2 = iSD.IsBillable;
                }

                i++;
            }

            lResult.TotalFLMQualified = flmQualified;
            lResult.TotalFLMUnqualified = flmUnqualified;

            lResult.TotalFLSQualified = flmQualified / 60;
            lResult.TotalFLSUnqualified = flmUnqualified / 60;

            lResult.TotalFLM = flmQualified + flmUnqualified;

            lResult.TotalFLS = lResult.TotalFLM / 60;

            lResult.TotalFLMBillable = flmBillable;

            DateTime dt = DateTime.Now.Date.AddMinutes(lResult.TotalFLMBillable);
            TimeSpan tspan = dt.Subtract(DateTime.Now.Date);

            double d = tspan.TotalHours;

            d = Math.Floor(d);

            lResult.TotalFLHoursMinutesString = String.Format("{0}:{1:00}", d, tspan.Minutes);

            lResult.TotalFLMQualifiedString = String.Format("{0:0.##}", flmQualified).Replace(".", ",");
            lResult.TotalFLMUnqualifiedString = String.Format("{0:0.##}", flmUnqualified).Replace(".", ",");

            lResult.TotalFLSQualifiedString = String.Format("{0:0.##}", lResult.TotalFLSQualified).Replace(".", ",");
            lResult.TotalFLSUnqualifiedString = String.Format("{0:0.##}", lResult.TotalFLSUnqualified).Replace(".", ",");

            lResult.TotalFLMString = String.Format("{0:0.##}", lResult.TotalFLM).Replace(".", ",");
            lResult.TotalFLSString = String.Format("{0:0.##}", lResult.TotalFLS).Replace(".", ",");

	        lResult.TotalGefahreneKilometerString = String.Format("{0:0.##}", lResult.TotalGefahreneKilometer);

            // if (cb2scOid2Data.Count == 1)
            // {
            // lResult.CostBearer2SupportConceptData = cb2scOid2Data.Values.First();
            // }
            if (cb2scs.Count == 1)
            {
                lResult.SupportConceptCostBearer = cb2scs.Values.First();
            }

            return lResult;
        }

	    public static void CreateGoalList(ServiceDetail sd)
	    {
		    var serviceRecord = DAOFactory.GenericDAO.LoadByID<ServiceRecord>(sd.ServiceRecordOid);

		    var srDc = MapperFactory.ServiceRecordDC_ServiceRecord.MapToNewDC(serviceRecord);
		    
			sd.GoalList = String.Empty;
			if (srDc.Goals != null && srDc.Goals.Count > 0)
			{

				foreach (var goal in srDc.Goals)
				{
					if (sd.GoalList.Length > 0)
						sd.GoalList += ", ";
					sd.GoalList += goal.TypeDescription;
				}
			}
	    }

        private static int GetKW(DateTime actualDate)
        {
            Calendar objCal = CultureInfo.CurrentCulture.Calendar;
            int weekofyear = objCal.GetWeekOfYear(actualDate, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);

            return weekofyear;
        }

        public class EmployeeDetail
        {
            public string EmployeeName { get; set; }

            public double TotalFLM { get; set; }

            public double TotalFLS { get; set; }

            public string TotalFLSString { get; set; }

			public Employee Employee { get; set; }
        }

        public class ServiceDetail
        {
			public long ServiceRecordOid { get; set; }

            public string CostBearer { get; set; }

            public int CustomerCount { get; set; }

            public string EmployeeAbbr { get; set; }

            public int EmployeeCount { get; set; }

            public string EmployeeFullname { get; set; }

            public string EmployeeNameCommaSeparated { get; set; }

            public DateTime EndDate { get; set; }

            public DateTime? EndDateMinutes { get; set; }

            public double FLSQualified { get; set; }

            public string FLSQualifiedString { get; set; }

            public double FLSUnqualified { get; set; }

            public string FLSUnqualifiedString { get; set; }

            public double GroupMinutes { get; set; }

            public decimal? GroupRoundedDuration { get; set; }

            public bool IsBillable { get; set; }

            public bool IsGroup { get; set; }

            public int KW { get; set; }

            public double Minutes { get; set; }

            public DateTime MinutesDateTime { get; set; }

            public double MinutesQualified { get; set; }

            public double MinutesUnqualified { get; set; }

            public string Notice { get; set; }

            public string ServiceCategory { get; set; }

            public string ServiceCategoryAbbr { get; set; }

            public string ServiceDescription { get; set; }

            public DateTime StartDate { get; set; }

            public DateTime? StartDateMinutes { get; set; }

            public string StartDateString { get; set; }

            public string TimeRangeString { get; set; }

			public DateTime EndDateNotRounded { get; set; }

			public string GefahreneKilometer { get; set; }

			//Wird aus Performancegründen nicht automatisch gesetzt. Kann bei Bedarf in den Kundenreports erstellt werden
			public string GoalList { get; set; }
        }

        public class ServiceDoubleDetail
        {
            public string CostBearer { get; set; }

            public string CostBearer2 { get; set; }

            public string EmployeeName { get; set; }

            public string EmployeeName2 { get; set; }

            public double FLS { get; set; }

            public double FLS2 { get; set; }

            public string FLSString { get; set; }

            public string FLSString2 { get; set; }

            public bool IsBillable { get; set; }

            public bool IsBillable2 { get; set; }

            public double Minutes { get; set; }

            public double Minutes2 { get; set; }

            public string ServiceCategory { get; set; }

            public string ServiceCategory2 { get; set; }

            public string ServiceCategoryAbbr { get; set; }

            public string ServiceCategoryAbbr2 { get; set; }

            public string ServiceDescription { get; set; }

            public string ServiceDescription2 { get; set; }

            public DateTime StartDate { get; set; }

            public DateTime StartDate2 { get; set; }

            public int CustomerCount { get; set; }

            public int CustomerCount2 { get; set; }
        }

		
	}
}