'''
Created on 07-Jan-2021

@author: bthakur
'''
import random
import operator
import datetime
import calendar

from sympy import (symbols, latex, simplify, Eq, sympify,
                   pi, Rational,
                   sin, cos, tan,
                   csc, sec, cot
                   )


from xv.km.util import latex_fraction

from xv.km.kelements import KPrintElement
        
from ..helper import BaseHelper
from xv.km.managers import BaseManager
from xv.km.kelements import KProblemTemplate

        
class CalendarManager(BaseManager):
    '''
    CalendarManager
    Example:
        ke = CalendarManager()
        ke.getRandomProblem()
        ke.getRandomProblem(problem_type = 0)
        ...
        
        ke.printProblem()
        ke.printAnswer()
        ke.printSolution()
        
        ke.printProblemTypes()

        
    '''    
    _OPR_TYPE_COUNT = 10
    
    def __new__(cls, *args, **kwargs):
        instance = super(CalendarManager, cls).__new__(cls, *args, **kwargs)
        for base_class in CalendarManager.__bases__:
            base_class.__init__(instance, *args, **kwargs)
        return instance
    
    def __init__(self, *args, **kwargs):
        self.base_helper = BaseHelper(**kwargs)
        self.calendar_helper = self.base_helper.get_common_helper().get_calendar_helper()
        pass

    def _init_problem_types(self, *args, **kwargs):
        self._append_problem_types([
            '_problem_solar_and_calendar_years',
            '_problem_gregorian_calendar',
            '_problem_print_calendar_month',
            '_problem_print_calendar_year',
            '_problem_calculate_days_in_month_range',
            '_problem_calculate_days_in_given_months_advanced',
            '_problem_calculate_days_in_date_range',
            '_problem_calculate_days_in_date_range_advanced',
            '_problem_find_day_of_week',
            '_problem_count_weekday_in_date_range',
            ])
        pass

    def _problem_solar_and_calendar_years(self, *args, **kwargs):
        """
        Questions related Solar and calendar years


        Minimum Grade: 3
        Maximum Grade: 9


        Examples
        --------
        from xv.math.temporal import CalendarManager
        ke = CalendarManager()
        ke.getRandomProblem(problem_type = '_problem_solar_and_calendar_years')


        doc_style: xv_doc
        """


        cal_helper = self.calendar_helper


        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        1. Which calendar used by most of the world?
        2. How many days a Gregorian calendar will have?
        3. What is a solar year?
        4. What is a leap year?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        1. Which calendar used by most of the world?
        The Gregorian calendar is a solar dating system used by most of the world. 
        
        2. How many days a Gregorian calendar will have?
        It has 365 days in non-leap years and 366 days in leap years.

        3. What is a solar year?
        The earth completes one round around the Sun in roughly 
        365 days, 5 hours, 48 minutes, and 46 seconds.  
        It is called a solar year.
        
        We use 365 days for a year and we call it a calendar year. 
        
        4. What is a leap year?
        The earth completes one round around the Sun in roughly 
        365 days, 5 hours, 48 minutes, and 46 seconds.  
        It is called a solar year.
        
        We use 365 days for a year and we call it a calendar year. 
        
        But as it is shorter by 5 hours, 48 minutes, and 46 seconds. 
        So, once in every four years, we use 366 days for that year. 
        We call this year as leap year and others as non-leap years.
        
        The calendar year must be divisible by 4 to be a leap year.
        
        The rule for century years is different. 
        Only one in four century years is a leap year. 
        The century year must be divisible by 400 to be a leap year.
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = soln_s
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate

    def _problem_gregorian_calendar(self, *args, **kwargs):
        """
        Questions related to Gregorian calendar 


        Minimum Grade: 3
        Maximum Grade: 9


        Examples
        --------
        from xv.math.temporal import CalendarManager
        ke = CalendarManager()
        ke.getRandomProblem(problem_type = '_problem_gregorian_calendar')


        doc_style: xv_doc
        """

        cal_helper = self.calendar_helper


        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        1. How many months are there in a Gregorian calendar?
        2. How many months are having 31 days in a Gregorian calendar?
        3. How many months are having 30 days in a Gregorian calendar?
        4. How many months are less than 30 days in a Gregorian calendar?
        
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        1. How many months are there in a Gregorian calendar?
        12 months:
            January - 31 days
            February - 28 days in a non-leap year and 29 days in leap years
            March - 31 days
            April - 30 days
            May - 31 days
            June - 30 days
            July - 31 days
            August - 31 days
            September - 30 days
            October - 31 days
            November - 30 days
            December - 31 days
        
        2. How many months are having 31 days in a Gregorian calendar?
        7 months:
            January - 31 days
            March - 31 days
            May - 31 days
            July - 31 days
            August - 31 days
            October - 31 days
            December - 31 days
        
        3. How many months are having 30 days in a Gregorian calendar?
        4 months:
            April - 30 days
            June - 30 days
            September - 30 days
            November - 30 days
        
        4. How many months are less than 30 days in a Gregorian calendar?
        1 month: February - 28 days in a non-leap year and 29 days in leap years
        
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = soln_s
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    def _problem_print_calendar_month(self, *args, **kwargs):
        """
        Print calendar for a given month and year with Python calendar module


        Minimum Grade: 3


        Optional parameters
        ========    ====================
        params      default
        --------    --------------------
        year        random int
        month       random int 
        ========    ====================
                    
    
        Examples
        --------
        from xv.math.temporal import CalendarManager
        ke = CalendarManager()
        ke.getRandomProblem(problem_type = '_problem_print_calendar_month')
        ke.getRandomProblem(problem_type = '_problem_print_calendar_month', year = 2021)
        ke.getRandomProblem(problem_type = '_problem_print_calendar_month', year = 2021, month = 1)


        doc_style: xv_doc
        """

        cal_helper = self.calendar_helper


        now = datetime.datetime.now()

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        random_year = random.choice(list(range(1900, now.year)))
        random_month = random.choice(list(range(1, 12)))
        
        year = kwargs.get('year', random.choice([now.year, random_year]) )
        month = kwargs.get('month', random.choice([now.month, random_month]) )

        leap_year = cal_helper.is_leap_year(year)
        months = cal_helper.get_months(leap_year = leap_year)
        
        month_name = list(months.keys())[month - 1]
        calendar_str = calendar.month(year, month)

        problem_s = f"""
        Print calendar of {month_name} {year}
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        <pre>{calendar_str}</pre>
        import calendar
        
        # initializing the year and month
        # month starts from 1, not zero
        year = {year}
        month = {month}
        
        # printing the calendar
        print(calendar.month(year, month))
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        <pre>{calendar_str}</pre>
        """
        problemTemplate.add_answer (answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    def _problem_print_calendar_year(self, *args, **kwargs):
        """
        Print calendar for a given year with Python calendar module


        Minimum Grade: 3


        Optional parameters
        ========    ====================
        params      default
        --------    --------------------
        year        random int
        ========    ====================
                    
    
        Examples
        --------
        from xv.math.temporal import CalendarManager
        ke = CalendarManager()
        ke.getRandomProblem(problem_type = '_problem_print_calendar_year')
        ke.getRandomProblem(problem_type = '_problem_print_calendar_year', year = 2021)


        doc_style: xv_doc
        """


        cal_helper = self.calendar_helper


        now = datetime.datetime.now()

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        random_year = random.choice(list(range(1900, now.year)))
        year = kwargs.get('year', random.choice([now.year, random_year]) )
        calendar_str = calendar.calendar(year)

        problem_s = f"""
        Print calendar of year {year}
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        <pre>{calendar_str}</pre>
        import calendar
        
        # initializing the year and month
        # month starts from 1, not zero
        year = {year}
        
        # printing the calendar
        print(calendar.calendar(year))
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        <pre>{calendar_str}</pre>
        """
        problemTemplate.add_answer (answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    
    def _problem_calculate_days_in_month_range(self, *args, **kwargs):
        """
        Calculate number of days in a given month range of a leap or non-leap year.
        The knowledge of leap and non-leap years is also required.


        Minimum Grade: 4
        Maximum Grade: 9


        Examples
        --------
        from xv.math.temporal import CalendarManager
        ke = CalendarManager()
        ke.getRandomProblem(problem_type = '_problem_calculate_days_in_month_range')


        doc_style: xv_doc
        """

        cal_helper = self.calendar_helper



        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        leap_year = random.choice([True, False])
        if leap_year:
            leap_year_str = "in a leap year"
        else:
            leap_year_str = "in a non-leap year"
            
        ops = [(operator.lt, "less than"),
               (operator.le, "less than or equal to"),
               (operator.eq, "equal to"),
               (operator.ne, "not equal to"),
               (operator.ge, "greater than or equal to"),
               (operator.gt, "greater than"),
            ]    
        
        while True:
            op = random.choice(ops)
            days = random.choice([31, 30, 29, 28])
            months = cal_helper.get_months(leap_year = leap_year, 
                                                    days = days,
                                                    op = op[0])
            if len(months) > 0:
                break
        
        months_str = ", ".join(list(months.keys()))
        month_days_str = " + ".join([str(v) for v in months.values()])

        problem_s = f"""
        How many total number of days are in the following months {leap_year_str}:
        {months_str}
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        Total number of days are in the following months {leap_year_str}:
        {months_str}
        
        = ${month_days_str}$
        
        = ${sympify(month_days_str)}$
        
        <pre>{calendar.calendar(cal_helper.get_recent_year(leap_year = leap_year))}</pre>
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        ${sympify(month_days_str)}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate

    def _problem_calculate_days_in_given_months_advanced(self, *args, **kwargs):
        """
        Calculate number of days in a given month range of a given year.
        The knowledge of leap and non-leap years is also required.


        Minimum Grade: 4
        Maximum Grade: 9


        Examples
        --------
        from xv.math.temporal import CalendarManager
        ke = CalendarManager()
        ke.getRandomProblem(problem_type = '_problem_calculate_days_in_given_months_advanced')


        doc_style: xv_doc
        """
        cal_helper = self.calendar_helper


        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        year_set1 = random.choice(list(range(1, 3000)))
        year_set2 = random.choice(list(range(1, 750))) * 4
        year_set3 = random.choice(list(range(1, 30))) * 100
        
        year = random.choice([year_set1, year_set2, year_set3])
        leap_year_str = f"in year {year}"
        
        leap_year = cal_helper.is_leap_year(year)
            
        ops = [(operator.lt, "less than"),
               (operator.le, "less than or equal to"),
               (operator.eq, "equal to"),
               (operator.ne, "not equal to"),
               (operator.ge, "greater than or equal to"),
               (operator.gt, "greater than"),
            ]    
        
        while True:
            op = random.choice(ops)
            days = random.choice([31, 30, 29, 28])
            months = cal_helper.get_months(leap_year = leap_year, 
                                                    days = days,
                                                    op = op[0])
            if len(months) > 0:
                break
        
        months_str = ", ".join(list(months.keys()))
        month_days_str = " + ".join([str(v) for v in months.values()])

        leap_year_logic = cal_helper.is_leap_year_logic(year)
        if not 'February' in months.keys():
            leap_year_logic = ''

        problem_s = f"""
        How many total number of days are in the following months {leap_year_str}:
        {months_str}
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        {leap_year_logic}
        
        Total number of days are in the following months {leap_year_str}:
        {months_str}
        
        = ${month_days_str}$
        
        = ${sympify(month_days_str)}$

        <pre>{calendar.calendar(year)}</pre>
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        ${sympify(month_days_str)}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    def _problem_calculate_days_in_date_range(self, *args, **kwargs):
        """
        Calculate number of days in a given date range of same year.
        The knowledge of leap and non-leap years is also required.


        Minimum Grade: 4
        Maximum Grade: 9


        Examples
        --------
        from xv.math.temporal import CalendarManager
        ke = CalendarManager()
        ke.getRandomProblem(problem_type = '_problem_calculate_days_in_date_range')


        doc_style: xv_doc
        """
        cal_helper = self.calendar_helper


        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        d1 = cal_helper.get_random_date()
        d2 = cal_helper.get_random_date()
        d2 = datetime.date(d1.year, d2.month, d2.day)
        if d1 > d2:
            dtemp1 = d1
            d1 = d2
            d2 = dtemp1

        d1_str = cal_helper.date_to_str(d1)
        d2_str = cal_helper.date_to_str(d2)
        
        d1_end = datetime.date(d1.year, d1.month, 
                               calendar.monthrange(d1.year, d1.month)[-1])
        
        delta = d2 - d1
        total_days = delta.days + 1
        
                
        problem_s = f"""
        Find the number of days between {d1_str} and {d2_str}, including both dates.
        
        Date format: YYYY-MM-DD
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        month_names = cal_helper.get_month_names()
        months = list(range(d1.month + 1, d2.month))
        
        full_month_values_str = ""
        full_month_values = []
        if len(months) > 0:
            full_month_values = []
            full_month_days_str = []
            for i in months:
                fmd = calendar.monthrange(d1.year, i)[-1]
                full_month_values.append(str(fmd))
                full_month_days_str.append(f"{month_names[i-1]:15} {d1.year} = ${fmd}$ ")
                pass
            
            full_month_days_str = "\n".join(full_month_days_str)
        else:
            full_month_days_str = ""
            pass
            
        if d1.month != d2.month:
            
            term3 = f"{(d1_end - d1).days + 1}"
            term4 = f"{d2.day}"
            
            full_month_values.insert(0, term3)
            full_month_values.append(term4)
            full_month_values_str = " + ".join(full_month_values)
            
            soln_s = f"""
            Month wise days between {d1_str} and {d2_str}:
            
            {d1.day} to {d1_end.day} {month_names[d1.month-1]:15} {d1.year} = $ ({d1_end.day} - {d1.day}) + 1 = {term3}$ 
            {full_month_days_str}
            Up to {d2.day} {month_names[d2.month-1]:15} {d2.year} = ${term4}$ 
            
            $= {full_month_values_str}$
            $= {total_days}$
            """
            problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        if d1.month != d2.month:
            soln_s = f"""
            The number of days between {d1_str} and {d2_str} 
            $= {total_days}$
            """
        else:
            soln_s = f"""
            The number of days between {d1_str} and {d2_str} 
            $= ({d2.day} - {d1.day}) + 1$
            $= {total_days}$
            """
            
        problemTemplate.add_solution(soln_s.strip(), 'text/html')


        soln_s = f"""
        <pre>{calendar.calendar(d1.year)}</pre>
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        if d1.year != d2.year:
            soln_s = f"""
            <pre>{calendar.calendar(d2.year)}</pre>
            """
            problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        
        answer_s = f"""
        {total_days}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate

    def _problem_calculate_days_in_date_range_advanced(self, *args, **kwargs):
        """
        Calculate number of days in a given date range.
        The knowledge of leap and non-leap years is also required.


        Minimum Grade: 4
        Maximum Grade: 9


        Examples
        --------
        from xv.math.temporal import CalendarManager
        ke = CalendarManager()
        ke.getRandomProblem(problem_type = '_problem_calculate_days_in_date_range_advanced')


        doc_style: xv_doc
        """
        cal_helper = self.calendar_helper


        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        d1 = cal_helper.get_random_date()
        d2 = d1 + datetime.timedelta(days = random.randint(7, 730))

        d1_str = cal_helper.date_to_str(d1)
        d2_str = cal_helper.date_to_str(d2)
        
        d1_end = datetime.date(d1.year, 12, 31)
        d2_start = datetime.date(d2.year, 1, 1)
        delta = d2 - d1
        total_days = delta.days + 1
        
        full_years = list(range(d1.year + 1, d2.year))
        
        leap_full_years = []
        non_leap_full_years = []
        for y in full_years:
            if calendar.isleap(y):
                leap_full_years.append(str(y))
            else:
                non_leap_full_years.append(str(y))
                
        leap_full_years_str = ", ".join(leap_full_years)
        non_leap_full_years_str = ", ".join(non_leap_full_years)
                
        problem_s = f"""
        Find the number of days between {d1_str} and {d2_str}.
        
        Date format: YYYY-MM-DD
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        term1 = ""
        if len(leap_full_years) > 0:
            term1 = f"{365 * len(leap_full_years)}"
            soln_s = f"""
            Days of full leap years 
            = days of years {leap_full_years_str}
            = $366 * {len(leap_full_years)}$
            = ${term1}$
            """
            problemTemplate.add_solution(soln_s.strip(), 'text/html')
            
        term2 = ""
        if len(non_leap_full_years) > 0:
            term2 = f"{365 * len(non_leap_full_years)}"
            soln_s = f"""
            Days of full non-leap years 
            = days of years {non_leap_full_years_str}
            = $365 * {len(non_leap_full_years)}$
            = ${term2}$
            """
            problemTemplate.add_solution(soln_s.strip(), 'text/html')
            
        term3 = ""
        term4 = ""
        if d1.year != d2.year:
            term3 = f"{(d1_end - d1).days}"
            term4 = f"{(d2 - d2_start).days}"
            soln_s = f"""
            Days between {d1_str} and {d1_end} = ${term3}$ 
            Days between {d2_start} and {d2_str} = ${term4}$ 
            """
            problemTemplate.add_solution(soln_s.strip(), 'text/html')
            
        term5 = ""
        if d1.year == d2.year:
            term5 = f"{delta.days}"
        
        terms = [term1, term2, term3, term4, term5]  
        terms = [term for term in terms if term]  
        terms_str = " + ".join(terms)
        
        soln_s = f"""
        The number of days between {d1_str} and {d2_str} 
        $= {terms_str}$
        $= {total_days}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        soln_s = f"""
        <pre>{calendar.calendar(d1.year)}</pre>
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        if d1.year != d2.year:
            soln_s = f"""
            <pre>{calendar.calendar(d2.year)}</pre>
            """
            problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        
        answer_s = f"""
        {total_days}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate

    def _problem_find_day_of_week(self, *args, **kwargs):
        """
        _problem_find_day_of_week


        Minimum Grade: 3

        doc_style: xv_doc
        """
        cal_helper = self.calendar_helper


        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        d1 = cal_helper.get_random_date()
        days = random.randint(10, 30)
        if random.choice([True, False]):
            days = days + random.randint(1, 3) * 365 
            pass
        d2 = d1 + datetime.timedelta(days = days)
        
        d1_str = cal_helper.date_to_str(d1)
        d2_str = cal_helper.date_to_str(d2)
        
        d1_weekday = calendar.day_name[d1.weekday()]
        d2_weekday = calendar.day_name[d2.weekday()]

            
        problem_s = f"""
        If {d1_str} is {d1_weekday}. What day of the week {d2_str} is?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        {d1_str} = {d1_weekday}

        Days between {d1_str} and {d2_str} 
        = {days} days
        = {days // 7} week {days % 7} days
        
        {d2_str} 
        = {d1_weekday} + {days % 7} days
        =  {d2_weekday}
        
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        {d2_weekday}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate



    def _problem_find_weekday_of_a_date(self, *args, **kwargs):
        """
        Find week day of a given date.
        The knowledge of leap and non-leap years is also required.


        Minimum Grade: 5
        Maximum Grade: 9


        Examples
        --------
        from xv.math.temporal import CalendarManager
        ke = CalendarManager()
        ke.getRandomProblem(problem_type = '_problem_find_weekday_of_a_date')

        doc_style: xv_doc
        """
        cal_helper = self.calendar_helper


        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        d1 = cal_helper.get_random_date()
        d2 = d1 + datetime.timedelta(days = random.randint(7, 730))
        
        d1_str = cal_helper.date_to_str(d1)
        d2_str = cal_helper.date_to_str(d2)
        
        delta = d2 - d1
        addl_days = delta.days 
        addl_week_days = addl_days % 7
        
        d1_weekday = calendar.day_name[d1.weekday()]
        d2_weekday = calendar.day_name[d2.weekday()]
                
        problem_s = f"""
        If {d1_str} is {d1_weekday}, which week day is {d2_str}?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        The number of days from {d1_str} to {d2_str} = ${addl_days}$
        
        The additional week days 
        = remainder of ${Rational(addl_days, 7)}$
        = ${addl_week_days}$
        
        Week day {addl_week_days} days after ${d1_weekday}$, {d1_str}
        = ${d2_weekday}$, {d2_str}
        
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        soln_s = f"""
        <pre>{calendar.calendar(d1.year)}</pre>
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        if d1.year != d2.year:
            soln_s = f"""
            <pre>{calendar.calendar(d2.year)}</pre>
            """
            problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        
        answer_s = f"""
        {d2_weekday}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate


    def _problem_count_weekday_in_date_range(self, *args, **kwargs):
        """
        Count the numbers of a given week day in a given date range.
        The knowledge of leap and non-leap years is also required.


        Minimum Grade: 5
        Maximum Grade: 9


        Examples
        --------
        from xv.math.temporal import CalendarManager
        ke = CalendarManager()
        ke.getRandomProblem(problem_type = '_problem_count_weekday_in_date_range')


        doc_style: xv_doc
        """
        cal_helper = self.calendar_helper


        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        d1 = cal_helper.get_random_date()
        d2 = d1 + datetime.timedelta(days = random.randint(7, 730))
        
        d1_str = cal_helper.date_to_str(d1)
        d2_str = cal_helper.date_to_str(d2)
        
        d1_weekday = calendar.day_name[d1.weekday()]
        
        desired_weekday_index = random.randint(0, 6)
        desired_weekday = calendar.day_name[desired_weekday_index]  
         
        first_desired_date = d1
        while True:
            if first_desired_date.weekday() == desired_weekday_index:    
                break
            first_desired_date = first_desired_date + datetime.timedelta(days=1)

        first_desired_date_str = cal_helper.date_to_str(first_desired_date)

        delta = d2 - first_desired_date
        addl_days = delta.days
        addl_desired_weekdays = addl_days // 7
            
        problem_s = f"""
        If {d1_str} is {d1_weekday}. How many {desired_weekday} are between {d1_str} and {d2_str}?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        The first {desired_weekday} = {first_desired_date_str}
        
        The number of days from {first_desired_date_str} to {d2_str} = ${addl_days}$
        
        The additional week days 
        = quotent of ${Rational(addl_days, 7)}$
        = ${addl_desired_weekdays}$
        
        Number of {desired_weekday}s are between {d1_str} and {d2_str}?
        = ${addl_desired_weekdays} + 1$
        = ${addl_desired_weekdays + 1}$
        
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        soln_s = f"""
        <pre>{calendar.calendar(d1.year)}</pre>
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        if d1.year != d2.year:
            soln_s = f"""
            <pre>{calendar.calendar(d2.year)}</pre>
            """
            problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        
        answer_s = f"""
        {addl_desired_weekdays + 1}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate

