public void GeneratesValidSchedulesToCoverAllWorkingDaysInMonth()
        {
            var monthlyScheduleGenerator = new NaiveMonthlyScheduleGenerator(People);

            var schedules = monthlyScheduleGenerator.Generate();

            Assert.Equal(WorkdaysInMonth.Count() * 2, schedules.Count());
        }
        public IEnumerable <Schedule> Generate()
        {
            var selectedWorkPatterns = _validWorkPatternsToChooseFrom
                                       .Where(workPattern => workPattern.Count(flag => flag == 1) == 1)
                                       .Select(workPattern => new WorkPatternRepresentation(workPattern))
                                       .ToList();

            var monthlyPatterns = CombineWeeklyPatternsIntoMonthlyOnes(selectedWorkPatterns);

            var schedulePatternGenerator = new SchedulePatternGenerator(monthlyPatterns, _shifts);
            var schedulePatterns         = schedulePatternGenerator.GenerateAll();

            var schedules = new List <Schedule>();

            for (var personIndex = 0; personIndex < _people.Count(); personIndex += 1)
            {
                for (var workdayIndex = 0; workdayIndex < WorkdaysInMonth.Count(); workdayIndex += 1)
                {
                    var currentDaySchedule = schedulePatterns.ElementAt(personIndex).ElementAt(workdayIndex);
                    if (currentDaySchedule.StartsWith("1"))
                    {
                        var workday = WorkdaysInMonth.ElementAt(workdayIndex);
                        var shift   = (WorkShift)Enum.Parse(typeof(WorkShift), currentDaySchedule.Split(",").Skip(1).First());

                        var schedule = new Schedule
                        {
                            Employee  = _people.ElementAt(personIndex),
                            StartTime = new DateTime(workday.Year, workday.Month, workday.Day),
                            EndTime   = new DateTime(workday.Year, workday.Month, workday.Day)
                        };

                        if (WorkShift.Morning == shift)
                        {
                            schedule.StartTime = schedule.StartTime.AddHours(9);
                        }
                        else
                        {
                            schedule.StartTime = schedule.StartTime.AddHours(13);
                        }

                        schedule.EndTime = schedule.StartTime.AddHours(4);

                        schedules.Add(schedule);
                    }
                }
            }

            // NOT GOOD: I'm not making sure the resulting schedules don't include duplicates
            // (e.g. more than 2 schedules on one and the same day)
            return(schedules);
        }
        private IEnumerable <WorkPatternRepresentation> CombineWeeklyPatternsIntoMonthlyOnes(
            List <WorkPatternRepresentation> weeklyPatterns)
        {
            DaysInMonth.ToString();
            WorkdaysInMonth.ToString();

            var patternValidator = new WorkPatternValidator(new List <BusinessRule>());
            var monthlyPatterns  = new List <WorkPatternRepresentation>();
            var random           = new Random();

            foreach (var weeklyPattern in weeklyPatterns)
            {
                var monthlyPattern = weeklyPattern;
                // just consider 5 weekly patterns will cover the month
                // (normally, we should find the first multiple of 5 larger than WorkDaysInMonth)
                // TODO the Times() extension method would be useful here
                for (var count = 0; count < 5; count += 1)
                {
                    var randomIndex       = random.Next(0, weeklyPatterns.Count);
                    var randomNextPattern = weeklyPatterns.ElementAt(randomIndex);

                    var candidateForExtendedPattern = new WorkPatternRepresentation(
                        monthlyPattern.Concat(randomNextPattern));

                    while (!patternValidator.Validate(candidateForExtendedPattern))
                    {
                        randomIndex       = random.Next(0, weeklyPatterns.Count);
                        randomNextPattern = weeklyPatterns.ElementAt(randomIndex);

                        candidateForExtendedPattern = new WorkPatternRepresentation(
                            monthlyPattern.Concat(randomNextPattern));
                    }

                    // TODO as a safety measure, the above loop should be forcefully
                    // exited if it has been looping for a large number of times

                    monthlyPattern = candidateForExtendedPattern;
                }

                monthlyPatterns.Add(monthlyPattern);
            }

            return(monthlyPatterns);
        }