class TimelineUtilities {

    static Map<Duration, List<DateDurationKey>> createMonthDateEntries(TimeSpan span, Duration timeBarDuration)
    {
        Map<Duration, List<DateDurationKey>> toReturn = new HashMap<>();
        List<DateDurationKey> currentWeekDateEntries = null;
        List<DateDurationKey> lastWeekDateEntries = null;

        Calendar startTimeCal = getStartCalendar(span);
        Calendar endTimeCal = getEndCalendar(span);

        // Set the first month's start day to the first of the month, regardless
        // of incoming day
        if (startTimeCal.get(Calendar.DAY_OF_MONTH) > 1)
        {
            startTimeCal.set(Calendar.DAY_OF_MONTH, 1);
        }

        // If the end month's day is not #1, go to the next month.
        if (endTimeCal.get(Calendar.DAY_OF_MONTH) > 1)
        {
            endTimeCal.set(Calendar.DAY_OF_MONTH, 1);
            endTimeCal.add(Calendar.MONTH, 1);
        }

        int totalDaysInDateDurationKey = countDays(startTimeCal, endTimeCal);

        GregorianCalendar nextStart = new GregorianCalendar();
        nextStart.setTime(startTimeCal.getTime());

        List<DateDurationKey> monthDates = new ArrayList<>();
        while (totalDaysInDateDurationKey > 0)
        {
            Set<DateDurationKey> weekDates = new HashSet<>();
            GregorianCalendar currentStart = new GregorianCalendar();
            currentStart.setTime(nextStart.getTime());

            // Get the number of days in the month
            int daysInCurrentMonth = currentStart.getActualMaximum(Calendar.DAY_OF_MONTH);
            if (daysInCurrentMonth < totalDaysInDateDurationKey)
            {
                nextStart.add(Calendar.DATE, daysInCurrentMonth);
            }
            else
            {
                nextStart.add(Calendar.DATE, totalDaysInDateDurationKey);
            }

            /* Since all month intervals will start with the 1st day of the
             * month and end with the first day of the next month, the last and
             * first weeks are the same. This code will check each months group
             * of weeks sequentially and remove weeks that repeat EX: if weeks
             * are created for 1 Jan 2007 to 1 Feb 2007, and then 1 Feb 2007 and
             * 1 Mar 2007 =>the 1 Jan - 1 Feb weeks are: (31Dec06-7Jan07)
             * (7Jan07-14Jan07) (14Jan07-21Jan07) (21Jan07-28Jan07)
             * (28Jan07-4Feb07) =>the 1 Feb - 1 Mar weeks are: (28Jan07-4Feb07)
             * (4Feb07-11Feb07) (11Feb07-18Feb07) (18Feb07-25Feb07)
             * (25Feb07-4Mar07) In this example, the first week of the second
             * group is removed since it is the same as the last week of the
             * first group */
            if (lastWeekDateEntries == null)
            {
                lastWeekDateEntries = new ArrayList<>(createWeekDateEntries(
                        TimeSpan.get(currentStart.getTime(), nextStart.getTime()), toReturn, timeBarDuration));
                weekDates.addAll(lastWeekDateEntries);
            }
            else
            {
                currentWeekDateEntries = createWeekDateEntries(TimeSpan.get(currentStart.getTime(), nextStart.getTime()),
                        toReturn, timeBarDuration);
                for (DateDurationKey lastWeekKey : lastWeekDateEntries)
                {
                    if (currentWeekDateEntries.contains(lastWeekKey))
                    {
                        currentWeekDateEntries.remove(lastWeekKey);
                    }
                }
                weekDates.addAll(currentWeekDateEntries);
                lastWeekDateEntries = currentWeekDateEntries;
            }

            GregorianCalendar actualEndDay = (GregorianCalendar)nextStart.clone();

            monthDates.add(new DateDurationKey(currentStart.getTime(), actualEndDay.getTime(), Months.ONE, weekDates));

            totalDaysInDateDurationKey -= daysInCurrentMonth;
        }
        toReturn.put(Months.ONE, monthDates);
        return toReturn;
    }

    private  TimelineUtilities();

}