using System;
using BeWo.Report;
using BeWo.Report.ReportObjects;
using BeWo.Data.Entities;
using BeWo.Data.Access;
using System.Collections.Generic;
using BS.Shared.Core;
using BeWo.Service.ServiceImplementations;

namespace BeWo.WohnhelferRemscheidReports
{
    public partial class Mitarbeiterstundenkonto : DevExpress.XtraReports.UI.XtraReport, IBeWoReport<QueryRO>
    {
        
        public Mitarbeiterstundenkonto()
        {
            InitializeComponent();
        }

        public void SetReportDataSource(QueryRO pRO)
        {
            InitDataSource(pRO);
            this.bindingSource1.DataSource = pRO;
        }

        private void InitDataSource(QueryRO ro)
        {
            IList<Employee> employees = DAOFactory.GenericDAO.GetAllActiveAndArchived<Employee>();
            Dictionary<long, Employee> empDict = new Dictionary<long, Employee>();
            foreach (var item in employees)
            {
                empDict.Add(item.Oid.Value, item);
            }
            decimal sollGesamt = 0;
            decimal relationGesamt = 0;
            decimal gesamtGesamt = 0;
            decimal flsSollGesamt = 0;
            decimal flsPlusMinusGesamt = 0;
            decimal flsIstGesamt = 0;


            foreach (BeWo.Report.ReportObjects.QueryRO.Row mitarbeiterRow in ro.Rows)
            {
                long oid = 0;
                if (Int64.TryParse(mitarbeiterRow.Field1.ToString(), out oid))
                {
                    if (empDict.ContainsKey(oid))
                    {
                        Employee emp = empDict[oid];

                        mitarbeiterRow.Field2 = String.Format("{0}, {1}", emp.Person.LastName, emp.Person.FirstName);

                        decimal summeStundenGesamt = 0;
                        decimal anzahlMonate = 0;
                        decimal sollProWoche = 0;
                        decimal sollProMonat = 0;
                        var vertrag = emp.GetValidContractForDate(DateTime.Now);
                        if (vertrag != null && vertrag.WeeklyTotalHours.HasValue)
                        {
                            sollProWoche = vertrag.WeeklyTotalHours.Value;
                               
                            sollProMonat = ((365m / 7m) / 12m) * sollProWoche;
                        }
                        mitarbeiterRow.Field3 = String.Format("{0:0.00}", sollProWoche);
                        mitarbeiterRow.Field4 = String.Format("{0:0.00}", sollProMonat);

                        List<ServiceRecord> records = DAOFactory.SearchDAO.FindServiceRecords(emp.Oid, null);
                        records = AnalysisServiceImp.FilterActiveServiceRecords(records) as List<ServiceRecord>;


                        records.Sort((a, b) => a.Start.Value.CompareTo(b.Start.Value));

                        int aktuellerMonat = 0;
                        
                        decimal kontoStand = 0;
                        decimal abrechenbarImMonat = 0;
                        decimal nichtabrechenbarImMonat = 0;

                        mitarbeiterRow.ChildRows1 = new List<QueryRO.Row>();
                        QueryRO.Row aktuelleMonatsRow = null;

                        Contract aktuellerVertag = null;
                        foreach (var item in records)
                        {
                            DateTime dt = item.Start.Value.Date;
                            dt = new DateTime(dt.Year, dt.Month, 1);

                            int monat = dt.Year*100 + dt.Month;

                            while (aktuellerMonat < monat)
                            {
                                //Monatswechsel
                                //letzter Monat mit Werten aktualisieren
                                if (aktuellerMonat < 100000)
                                    aktuellerMonat = monat;
                                else
                                {
                                    String monatStr = String.Format("{0}", aktuellerMonat);
                                    int year = Int32.Parse(monatStr.Substring(0, 4));
                                    int month = Int32.Parse(monatStr.Substring(4, 2));
                                    dt = new DateTime(year, month, 1);
                                    dt = dt.AddMonths(1);

                                    aktuellerMonat = dt.Year * 100 + dt.Month; ;
                                }
                                if (aktuelleMonatsRow != null)
                                {
                                    aktuelleMonatsRow.Field2 = String.Format("{0:0.00}", (abrechenbarImMonat + nichtabrechenbarImMonat) / 60);
                                    aktuelleMonatsRow.Field3 = String.Format("{0:0.00}", kontoStand / 60);
                                    aktuelleMonatsRow.Field4 = String.Format("{0:0.00}", abrechenbarImMonat / 60);
                                    aktuelleMonatsRow.Field5 = String.Format("{0:0.00}", nichtabrechenbarImMonat / 60);
                                }

                                aktuellerVertag = emp.GetValidContractForDate(dt);
                                sollProWoche = 0;
                                if (aktuellerVertag != null)
                                {
                                    if (aktuellerVertag.WeeklyTotalHours.HasValue)
                                    {
                                        sollProWoche = aktuellerVertag.WeeklyTotalHours.Value;
                                    }
                                }
                                sollProMonat = ((365m / 7m) / 12m) * sollProWoche;
                                kontoStand += (sollProMonat * 60);


                                abrechenbarImMonat = 0;
                                nichtabrechenbarImMonat = 0;
                                
                                aktuelleMonatsRow = CreateMonatsRow(dt);
                                aktuelleMonatsRow.Field2 = String.Format("{0:0.00}", kontoStand / 60);
                                dt = dt.AddMonths(1);
                                
                                mitarbeiterRow.ChildRows1.Add(aktuelleMonatsRow);

                                anzahlMonate ++;
                                if (aktuellerMonat < monat)
                                {
                                    aktuelleMonatsRow.Field2 = String.Format("{0:0.00}", (abrechenbarImMonat + nichtabrechenbarImMonat) / 60);
                                    aktuelleMonatsRow.Field3 = String.Format("{0:0.00}", kontoStand / 60);
                                    aktuelleMonatsRow.Field4 = String.Format("{0:0.00}", 0);
                                    aktuelleMonatsRow.Field5 = String.Format("{0:0.00}", 0);
                                }
                            }
                            if (item.ServiceDescription != null &&
                                item.ServiceDescription.ServiceCategory != null &&
                                item.ServiceDescription.ServiceCategory.IsBillable)
                                abrechenbarImMonat += item.RoundedDuration;
                            else
                                nichtabrechenbarImMonat += item.RoundedDuration;

                            QueryRO.Row serviceRecordRow = new QueryRO.Row();
                            DateTime end = item.Start.Value.AddMinutes((double)item.RoundedDuration);
                            serviceRecordRow.Field1 = String.Format("{0:dd/MM/yyyy} ({1}-{2})", item.Start, item.Start.Value.ToShortTimeString(), end.ToShortTimeString());
                            serviceRecordRow.Field2 = String.Format("{0:0.00}", item.RoundedDuration);
                            serviceRecordRow.Field3 = String.Format("{0:0.00}", item.RoundedDuration / 60);
                            serviceRecordRow.Field4 = item.ServiceDescription.Name;
                            serviceRecordRow.Field5 = item.ServiceDescription.ServiceCategory.Abbreviation;

                            aktuelleMonatsRow.ChildRows2.Add(serviceRecordRow);
                            kontoStand -= item.RoundedDuration;

                            summeStundenGesamt += item.RoundedDuration;
                        }
                        if (aktuelleMonatsRow != null)
                        {
                            aktuelleMonatsRow.Field2 = String.Format("{0:0.00}", (abrechenbarImMonat + nichtabrechenbarImMonat) / 60);
                            aktuelleMonatsRow.Field3 = String.Format("{0:0.00}", kontoStand / 60);
                            aktuelleMonatsRow.Field4 = String.Format("{0:0.00}", abrechenbarImMonat / 60);
                            aktuelleMonatsRow.Field5 = String.Format("{0:0.00}", nichtabrechenbarImMonat / 60);
                        }

                        mitarbeiterRow.Field5 = String.Format("{0:0.00}", summeStundenGesamt / 60);
						if (anzahlMonate != 0)
							mitarbeiterRow.Field6 = String.Format("{0:0.00}", (summeStundenGesamt / anzahlMonate) / 60);
						else
							mitarbeiterRow.Field6 = "0";
                    }
                }

            }
            
        }

        private QueryRO.Row CreateMonatsRow(DateTime dt)
        {
            QueryRO.Row row = new QueryRO.Row();

            row.Field1 = String.Format("{0:MMM yyyy}", dt);

            row.ChildRows2 = new List<QueryRO.Row>();

            return row;
        }

        


        private bool IstFeiertag(DateTime start)
        {
            List<DateTime> feiertage = GetFeiertage(start.Year);

            foreach (var dateTime in feiertage)
            {
                if (start == dateTime)
                    return true;
            }
            return false;
        }

        private List<DateTime> GetFeiertage(int year)
        {
            List<DateTime> list = new List<DateTime>();
            list.Add(new DateTime(year, 1, 1)); // "Neujahr"));
            //list.Add(new DateTime(year, 1, 6)); // , "Heilige Drei Könige"));
            list.Add(new DateTime(year, 5, 1)); // , "Tag der Arbeit"));
            //list.Add(new DateTime(year, 8, 15)); // , "Mariä Himmelfahrt"));
            list.Add(new DateTime(year, 10, 3)); // , "Tag der dt. Einheit"));
            //list.Add(new DateTime(year, 10, 31)); // , "Reformationstag"));
            list.Add(new DateTime(year, 11, 1)); // , "Allerheiligen "));
            list.Add(new DateTime(year, 12, 24)); // , "Heilig Abend"));
            list.Add(new DateTime(year, 12, 25)); // , "1. Weihnachtstag"));
            list.Add(new DateTime(year, 12, 26)); // , "2. Weihnachtstag"));
            DateTime osterSonntag = GetOsterSonntag(year);
            //list.Add(osterSonntag); // , "Ostersonntag"));
            //list.Add(osterSonntag.AddDays(-3)); // , "Gründonnerstag"));
            list.Add(osterSonntag.AddDays(-48)); // , "Rosenmonatg"));
            list.Add(osterSonntag.AddDays(-2)); // , "Karfreitag"));
            list.Add(osterSonntag.AddDays(1)); // , "Ostermontag"));
            list.Add(osterSonntag.AddDays(39)); // , "Christi Himmelfahrt"));
            //list.Add(osterSonntag.AddDays(49)); // , "Pfingstsonntag"));
            list.Add(osterSonntag.AddDays(50)); // , "Pfingstmontag"));
            list.Add(osterSonntag.AddDays(60)); // , "Fronleichnam"));

            return list;
        }

        private DateTime GetOsterSonntag(int year)
        {

            int g, h, c, j, l, i;

            g = year % 19;
            c = year / 100;
            h = ((c - (c / 4)) - (((8 * c) + 13) / 25) + (19 * g) + 15) % 30;
            i = h - (h / 28) * (1 - (29 / (h + 1)) * ((21 - g) / 11));
            j = (year + (year / 4) + i + 2 - c + (c / 4)) % 7;

            l = i - j;
            int month = (int)(3 + ((l + 40) / 44));
            int day = (int)(l + 28 - 31 * (month / 4));

            return new DateTime(year, month, day);

        }
    }
}
