'''
Created on 01-Apr-2021
@author: bthakur
'''
from functools import reduce

import numpy as np
import random
import inspect
import traceback
from sympy import (simplify, sympify, log, symbols, Eq, Matrix, latex, 
                   solve, Rational, diag)


from xv.km.util import latex_fraction
from xv.util import list_to_str, number_to_nth

from ..helper import BaseHelper
from xv.km.managers import BaseManager
from xv.km.kelements import KProblemTemplate
from sympy.core.expr import UnevaluatedExpr
        
# _elementary_integer_manager
# ElementaryIntegerManager
        
class ElementaryIntegerManager(BaseManager):
    '''
    ElementaryIntegerManager
    Example:
        ke = ElementaryIntegerManager()
        ke.getRandomProblem()
        ke.getRandomProblem(problem_type = 0)
        ke.getRandomProblem(problem_type = 1)
        ...
        ke.printProblem()
        ke.printAnswer()
        ke.printSolution()
    '''    
    
    def __new__(cls, *args, **kwargs):
        instance = super(ElementaryIntegerManager, cls).__new__(cls, *args, **kwargs)
        for base_class in ElementaryIntegerManager.__bases__:
            base_class.__init__(instance, *args, **kwargs)
        return instance
    
    def __init__(self, *args, **kwargs):
        self.base_helper = BaseHelper(**kwargs)
        pass
    
    
    def _TEMPLATE_WORDS_TO_NUMBERS(self, number_words_pairs, **kwargs):
        random_pairs = random.sample(number_words_pairs, 4)
        
        words_str = [f"{x[1]}" for x in random_pairs]
        words_str = list_to_str(words_str, sep = "\n")

        random_pairs_str = [f"<b>{x[1]}:</b> {x[0]:,}"  for x in random_pairs]
        random_pairs_str = list_to_str(random_pairs_str, sep = "\n")

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

        problem_s = f"""
        Write the following numbers in figures:
        {words_str}
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        {random_pairs_str}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        if len(number_words_pairs) < 100:
            number_words_pairs_str = [f"<tr><td><b>{x[1]}</b></td><td>{x[0]:,}</td></tr>"  for x in number_words_pairs]
            number_words_pairs_str = "".join(number_words_pairs_str)
            number_words_pairs_str = f"<table>{number_words_pairs_str}</table>"
    
            soln_s = f"""
            <h3>Review numbers:</h3>
            {number_words_pairs_str}
            """
            problemTemplate.add_solution(soln_s.strip(), 'text/html')
            pass
        
        answer_s = f"""
        {random_pairs_str}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    

    def _TEMPLATE_SUM_OF_NUMBERS(self, number_words_pairs, **kwargs):
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        nums_count = random.randint(2, 4)
        random_pairs = random.sample(number_words_pairs, nums_count)
        
        nums = [x[0] for x in random_pairs]
        
        num_sum = sum(nums)

        prob_str = [random.choice([f"{x[1]}", f"{x[0]:,}"]) 
                     for x in random_pairs]
        mixed_str = list_to_str(prob_str, sep = "\n")
        mixed_sum_str = list_to_str(prob_str, sep = " + ")

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

        problem_s = f"""
        Add the following numbers:
        {mixed_str}
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        

        if num_sum < 40:
            nums_str = [f"{x:,}" for x in nums]
            nums_str = list_to_str(nums_str, sep = " + ")
            symbs_str = ea_helper.nums_to_symbols_html(nums)

            soln_s = f"""
            {mixed_sum_str}
    
            = {nums_str}
    
            Let us count each of the numbers together:
            {symbs_str}

            = {num_sum:,}
            """
            problemTemplate.add_solution(soln_s.rstrip(), 'text/html')
            pass
        else:
            nums_str = ea_helper.format_numbers_to_sum_html(nums)
            
            soln_s = f"""
            We have to add the following numbers:
            {mixed_str}
            
            Let us write the numbers in proper format and add them, making the number digit in each number the same.
            If they are less, we will add zeroes in the left of the number.
            
            <div style="font-family: monospace; font-size:2rem; line-height: 1.3em;">{nums_str}</div>
            """
            problemTemplate.add_solution(soln_s.rstrip(), 'text/html')
            pass
            

        soln_s = f"""
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        {num_sum:,}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    def _TEMPLATE_MULTIPLES_OF_MULTIPLES(self, b1, b2, n3, **kwargs):
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        n2 = n3  * (b2 // b1)
        num = n2 * b1
        
        b1_zeroes = f"{b1}"[1:]
        b1_word = ea_helper.number_to_word(b1)
        b1_word = b1_word.replace("one ", "")

        b2_zeroes = f"{b2}"[1:]
        
        b2_word = ea_helper.number_to_word(b2, plural = False)
        #b2_word = b2_word.replace("one ", "")

        if n3 == 1:
            num_word = ea_helper.number_to_word(num, plural = False)
        else:
            num_word = ea_helper.number_to_word(num, plural = False)
        
        problem_s = f"""
        How many {b1_word} are there in {num_word}?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        if n2 <= 99:
            count_html_table = ea_helper.get_number_count_html_table(b1, n2)
            
            soln_s = f"""
            Let us count {b1_word} and keep adding them till we reach to {num_word}:
            {count_html_table}
            Hence, number of {b1_word} in {num_word} = {n2:,}
            """
            problemTemplate.add_solution(soln_s.strip(), 'text/html')
            pass

        if n2 <= 99:
            soln_s = f"""
            <h3>An easier way to find the same:</h3>
            """
            problemTemplate.add_solution(soln_s.strip(), 'text/html')
        else:
            soln_s = f"""
            The difference between {b1_word} and {num_word} is huge and it is difficult to count. 
            Hence, we will use another method, we will divide {num_word} by {b1_word}.
            """
            problemTemplate.add_solution(soln_s.strip(), 'text/html')
            pass
        
        num_b1_latex = latex_fraction(f"{num:,}", f"{b1:,}", 'blue', 'red')
        n2_1_latex = latex_fraction(f"{n2:,}", 1, 'blue', 'red')
        soln_s = f"""
        The number of {b1_word} in {num_word}
        
        $\\displaystyle = {num_b1_latex} $
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        if b1 != 1:
            num_b1_latex = latex_fraction(f"{num:,}", b1, 'blue', 'red')
            n2_1_latex = latex_fraction(f"{n2:,}", 1, 'blue', 'red')
            soln_s = f"""
            Cancel the equal number zeros from numerator and denominator.
            The numerator has {len(b2_zeroes)} zeros on the right side and the denominator has {len(b1_zeroes)} zeros on the right side.
            As the denominator has less zeroes on the right side, we will cancel {len(b1_zeroes)} zeroes from the both.
            
            $\\displaystyle = {n2_1_latex} $
            """
            problemTemplate.add_solution(soln_s.strip(), 'text/html')
            pass
        
        num_b1_latex = latex_fraction(f"{num:,}", b1, 'blue', 'red')
        n2_1_latex = latex_fraction(f"{n2:,}", 1, 'blue', 'red')
        soln_s = f"""
        Anything divided by 1 remains the same value.
        
        $\\displaystyle = {n2:,} $
        
        Hence, number of {b1_word} in {num_word} = {n2:,}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        {n2:,}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
        pass
    
    def _TEMPLATE_SUM_VERBAL_STATEMENTS(self, category, **kwargs):
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        result = ea_helper.get_verbal_sum(category = category)
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        {result['prob_s']}
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        {result['soln_s']}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        {result['answer_s']}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
        

    def _TEMPLATE_COMPARE_NUMBERS(self, number_words_pairs, **kwargs):
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        
        number_words_pairs = [x for x in number_words_pairs if x[0] > 9]
        
        number_words_pairs = sorted(number_words_pairs, 
                                    key = lambda x: x[0], 
                                    reverse = False)
        start_idx = random.randint(0, len(number_words_pairs) - 2)
        random_pairs = number_words_pairs[start_idx: start_idx + 2]
        
        random.shuffle(random_pairs)
        
        (n1, w1), (n2, w2) = random_pairs
        nums = [n1, n2]
        formatted_nums = ea_helper.format_numbers(nums)
        
        nums_str = "<br/>".join(formatted_nums)
        
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Solve:
        $\\displaystyle \\text{{{w1}}}  \\quad ? \\quad \\text{{{w2}}} $
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        $\\displaystyle \\text{{{w1}}}  \\quad ? \\quad \\text{{{w2}}} $

        $\\displaystyle \\implies {n1:,}  \\quad ? \\quad {n2:,} $

        
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
                
        soln_s = f"""
        Let us write the numbers in proper format, making the number digit in each number the same.
        If they are less, we will add zeroes in the left of the number.
        
        <div style="font-family: monospace; font-size:2rem; line-height: 1.3em;">{nums_str}</div>
        
        Compare each digit in both numbers from the left and find the first bigger digit.
        
        """
        problemTemplate.add_solution(soln_s.rstrip(), 'text/html')
        pass
            

        n1_word, n2_word = formatted_nums
        for idx, n1_w in enumerate(n1_word):
            n2_w = n2_word[idx]
            if n1_w == n2_w:
                continue
            idx_words = number_to_nth(idx + 1)
            if int(n1_w) > int(n2_w):
                soln_s = f"""
                In {idx_words} place, {n1_w} in the first number is bigger than {n2_w} in the second number.
                Therefore, first number is bigger.
                
                $\\displaystyle \\implies {n1:,}  \\quad > \\quad {n2:,} $
                
                $\\displaystyle \\implies {formatted_nums[0]}  \\quad > \\quad {formatted_nums[1]} $
                """ 
                answer_s = f""" $\\displaystyle {n1:,}  \\quad > \\quad {n2:,} $ """
            else:
                soln_s = f"""
                In {idx_words} place, {n1_w} in the first number is less than {n2_w} in the second number
                Therefore, first number is smaller.
                
                $\\displaystyle \\implies {formatted_nums[0]}  \\quad < \\quad {formatted_nums[1]} $
                
                $\\displaystyle \\implies {n1:,}  \\quad < \\quad {n2:,} $
                """ 

                answer_s = f""" $\\displaystyle {n1:,}  \\quad < \\quad {n2:,} $ """
                pass
            break
            pass
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        
        answer_s = f"""
        {answer_s}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
        
    def _TEMPLATE_DIFF_VERBAL_STATEMENTS(self, category, **kwargs):
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        result = ea_helper.get_verbal_diff(category = category)
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        {result['prob_s']}
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        {result['soln_s']}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        {result['answer_s']}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    

    def _TEMPLATE_PLACE_VALUES(self, category, **kwargs):
        
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        number_words_pairs = ea_helper.get_number_words_pairs(category = 'extended')
        
        number_words_pairs = [x for x in number_words_pairs
                              if x[0] >= 10]
        
        num, num_word = random.choice(number_words_pairs)
        
        uts = [1, 10, 100, 10**3, 10**6, 10**9, 10**12]
        uts.reverse()
        
        max_ut = 1
        rem = num
        for ut in uts:
            int_div = rem // ut 
            if int_div <= 0:
                continue
            max_ut = ut
            break
            pass
        
        
        max_ut_idx = uts.index(max_ut)
        random_idx = random.randint(max_ut_idx, len(uts) - 1)
        uts = uts[random_idx:]

        uts_words = ea_helper.convert_units_to_words(uts)
        uts_str = list_to_str(uts_words, last_sep = ' and')
        
        rem = num
        place_values = []
        for ut_idx, ut in enumerate(uts):
            int_div = rem // ut 
            if int_div <= 0:
                continue
            
            place_values.append([ut, int_div, uts_words[ut_idx]])
            rem = rem % ut 
            pass
        
        place_values_figures = [f"{int_div:,} * {ut:,}" 
                              for ut, int_div, ut_word  in place_values]
        place_values_figures = " + ".join(place_values_figures)
        
        place_values_words = [f"{int_div:,} {ut_word}" 
                              for ut, int_div, ut_word  in place_values]
        place_values_words = " + ".join(place_values_words)
        
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Express {num:,} in terms of {uts_str}.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        {num:,}
        
        = {place_values_figures}
        
        = {place_values_words}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        {place_values_words}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate

    def _TEMPLATE_WRITE_NUMBERS_IN_WORDS(self, number_words_pairs, **kwargs):
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        number_words_pairs = sorted(number_words_pairs, 
                                    key = lambda x: x[0], 
                                    reverse = True)
        
        if len(number_words_pairs) > 5:
            number_words_pairs = number_words_pairs[:len(number_words_pairs)//2]
        
        num, num_word = random.choice(number_words_pairs)
        num_str = ea_helper.format_numbers(num)
        
        pos_values = ea_helper.convert_number_to_pos_values(num)
        pos_values_str1, pos_values_str2 = ea_helper.convert_pos_values_to_str(pos_values)
        

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

        problem_s = f"""
        Write the number in figures:
        {num_word}
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        {num_word}
        
        Write each positional group separately.
        Make sure each positional group has three digits. If not, add zeros to the left.
        
        = {pos_values_str1}
        
        = {pos_values_str2}
        
        = {num_str}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

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

    

    def _init_problem_types(self, *args, **kwargs):
        self._append_problem_types([
            '_problem_words_to_numbers_single_digit',
            '_problem_sum_of_numbers_single_digit',
            '_problem_sum_verbal_statements_single_digit',
            '_problem_diff_verbal_statements_single_digit',

            '_problem_words_to_numbers_basic',
            '_problem_how_many_multiples',
            '_problem_words_to_numbers_double_digit',
            '_problem_words_to_numbers_triple_digit',
            
            '_problem_sum_of_numbers_basic',
            '_problem_sum_verbal_statements_basic',
            '_problem_diff_verbal_statements_basic',

            '_problem_count_multiples',
            '_problem_place_values_basic',
            '_problem_compare_numbers_basic',

            '_problem_sum_of_numbers_double_digit',
            '_problem_sum_verbal_statements_double_digit',
            '_problem_diff_verbal_statements_double_digit',

            '_problem_multiples_of_multiples_simple',
            '_problem_place_values_double_digit',
            '_problem_compare_numbers_double_digit',

            '_problem_sum_of_numbers_triple_digit',
            '_problem_sum_verbal_statements_triple_digit',
            '_problem_diff_verbal_statements_triple_digit',

            '_problem_place_values_triple_digit',
            '_problem_compare_numbers_triple_digit',

            '_problem_words_to_numbers',
            '_problem_sum_of_numbers',
            '_problem_sum_verbal_statements',
            '_problem_diff_verbal_statements',

            '_problem_write_numbers_in_words',

            '_problem_multiples_of_multiples_moderate',
            '_problem_place_values',
            '_problem_compare_numbers',

            '_problem_write_numbers_in_words_extended',

            '_problem_words_to_numbers_extended',
            '_problem_sum_of_numbers_extended',
            '_problem_sum_verbal_statements_extended',
            '_problem_diff_verbal_statements_extended',

            '_problem_multiples_of_multiples_advanced',
            '_problem_place_values_extended',
            
            '_problem_compare_numbers_extended',
            
    
            ]) 
        pass

    def _problem_words_to_numbers_single_digit(self, *args, **kwargs):
        
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        number_words_pairs = ea_helper.get_number_words_pairs(category = 'single_digit')
        return self._TEMPLATE_WORDS_TO_NUMBERS(number_words_pairs, **kwargs)
    
    def _problem_words_to_numbers_basic(self, *args, **kwargs):
        
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        number_words_pairs = ea_helper.get_number_words_pairs(category = 'basic')
        return self._TEMPLATE_WORDS_TO_NUMBERS(number_words_pairs, **kwargs)
    
    def _problem_words_to_numbers_double_digit(self, *args, **kwargs):
        
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        number_words_pairs = ea_helper.get_number_words_pairs(category = 'double_digit')
        
        return self._TEMPLATE_WORDS_TO_NUMBERS(number_words_pairs, **kwargs)
    
    def _problem_words_to_numbers_triple_digit(self, *args, **kwargs):
        
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        number_words_pairs = ea_helper.get_number_words_pairs(category = 'triple_digit')
        
        return self._TEMPLATE_WORDS_TO_NUMBERS(number_words_pairs, **kwargs)
    
    
    def _problem_words_to_numbers(self, *args, **kwargs):
        
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        number_words_pairs = ea_helper.get_number_words_pairs(category = None)
        
        
        return self._TEMPLATE_WORDS_TO_NUMBERS(number_words_pairs, **kwargs)
    
    def _problem_words_to_numbers_extended(self, *args, **kwargs):
        
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        number_words_pairs = ea_helper.get_number_words_pairs(category = 'extended')
        
        return self._TEMPLATE_WORDS_TO_NUMBERS(number_words_pairs, **kwargs)
    
    
    def _problem_how_many_multiples(self, *args, **kwargs):
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        b1 = random.choice([10, 100, 1000])
        b1_word = ea_helper.number_to_word(b1)
        b1_word = b1_word.replace("one ", "")
        n2 = random.randint(2, 10)
        num = n2 * b1
        
        count_html_table = ea_helper.get_number_count_html_table(b1, n2)

        problem_s = f"""
        How many {b1_word} are there is {num:,}?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        Let us count {b1_word} and keep adding them till we get {num:,}:
        {count_html_table}
        Hence, the number of {b1_word} in {num:,} = {n2:,}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        {count_html_table}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate

    def _problem_count_multiples(self, *args, **kwargs):
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        b1 = random.choice([10, 100, 1000])
        
        b1_zeroes = f"{b1}"[1:]
        
        b1_word = ea_helper.number_to_word(b1)
        b1_word = b1_word.replace("one ", "")
        n2 = random.randint(2, 10)
        num = n2 * b1
        
        multiples_html_tables = ea_helper.get_multiples_html_table(b1, n2)
        

        problem_s = f"""
        The height of each cell is {b1:,}, what is the total height of cells?
        {multiples_html_tables[0]}
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        Let us count {b1_word} and keep adding them:
        {multiples_html_tables[1]}
        Hence, the total height of cells = {num:,}
        
        Easier way to do it is to just leave zeroes and count the cells.
        Once we have counted them, put the zeroes back.
        {multiples_html_tables[2]}
        So, we have {n2:,} cells and if we put zeroes ({b1_zeroes}) back, we get {num:,}.
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        {num:,}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate


    def _problem_multiples_of_multiples_simple(self, *args, **kwargs):
        b1 = random.choice([1, 10, 10**2])
        b2 = b1 * random.randint(1, 10)
        n3 = random.randint(1, 10)
        return self._TEMPLATE_MULTIPLES_OF_MULTIPLES(b1, b2, n3, **kwargs)

    def _problem_multiples_of_multiples_moderate(self, *args, **kwargs):
        bases = random.sample([1, 10, 10**2, 10**3, 10**6, 10**9, 10**12], 2)
        bases.sort()
        b1, b2 = bases
        n3 = 1
        return self._TEMPLATE_MULTIPLES_OF_MULTIPLES(b1, b2, n3, **kwargs)


    def _problem_multiples_of_multiples_advanced(self, *args, **kwargs):
        bases = random.sample([1, 10, 10**2, 10**3, 10**6, 10**9, 10**12], 2)
        bases.sort()
        b1, b2 = bases
        n3 = random.randint(1, 9)
        return self._TEMPLATE_MULTIPLES_OF_MULTIPLES(b1, b2, n3, **kwargs)


    def _problem_sum_of_numbers_single_digit(self, *args, **kwargs):
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        number_words_pairs = ea_helper.get_number_words_pairs(category = 'single_digit')
        return self._TEMPLATE_SUM_OF_NUMBERS(number_words_pairs, **kwargs)
    
    
    def _problem_sum_of_numbers_basic(self, *args, **kwargs):
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        number_words_pairs = ea_helper.get_number_words_pairs(category = 'basic')
        return self._TEMPLATE_SUM_OF_NUMBERS(number_words_pairs, **kwargs)
    
    def _problem_sum_of_numbers_double_digit(self, *args, **kwargs):
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        number_words_pairs = ea_helper.get_number_words_pairs(category = 'double_digit')
        return self._TEMPLATE_SUM_OF_NUMBERS(number_words_pairs, **kwargs)
    
    def _problem_sum_of_numbers_triple_digit(self, *args, **kwargs):
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        number_words_pairs = ea_helper.get_number_words_pairs(category = 'triple_digit')
        return self._TEMPLATE_SUM_OF_NUMBERS(number_words_pairs, **kwargs)
    
    def _problem_sum_of_numbers(self, *args, **kwargs):
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        number_words_pairs = ea_helper.get_number_words_pairs(category = None)
        return self._TEMPLATE_SUM_OF_NUMBERS(number_words_pairs, **kwargs)
    
    def _problem_sum_of_numbers_extended(self, *args, **kwargs):
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        number_words_pairs = ea_helper.get_number_words_pairs(category = 'extended')
        return self._TEMPLATE_SUM_OF_NUMBERS(number_words_pairs, **kwargs)



    def _problem_sum_verbal_statements_single_digit(self, *args, **kwargs):
        category = 'single_digit'
        return self._TEMPLATE_SUM_VERBAL_STATEMENTS(category, **kwargs)

    def _problem_sum_verbal_statements_basic(self, *args, **kwargs):
        category = 'basic'
        return self._TEMPLATE_SUM_VERBAL_STATEMENTS(category, **kwargs)

    def _problem_sum_verbal_statements_double_digit(self, *args, **kwargs):
        category = 'double_digit'
        return self._TEMPLATE_SUM_VERBAL_STATEMENTS(category, **kwargs)

    def _problem_sum_verbal_statements_triple_digit(self, *args, **kwargs):
        category = 'triple_digit'
        return self._TEMPLATE_SUM_VERBAL_STATEMENTS(category, **kwargs)

    def _problem_sum_verbal_statements(self, *args, **kwargs):
        category = None
        return self._TEMPLATE_SUM_VERBAL_STATEMENTS(category, **kwargs)

    def _problem_sum_verbal_statements_extended(self, *args, **kwargs):
        category = 'extended'
        return self._TEMPLATE_SUM_VERBAL_STATEMENTS(category, **kwargs)
    
    
    def _problem_diff_verbal_statements_single_digit(self, *args, **kwargs):
        category = 'single_digit'
        return self._TEMPLATE_DIFF_VERBAL_STATEMENTS(category, **kwargs)

    def _problem_diff_verbal_statements_basic(self, *args, **kwargs):
        category = 'basic'
        return self._TEMPLATE_DIFF_VERBAL_STATEMENTS(category, **kwargs)

    def _problem_diff_verbal_statements_double_digit(self, *args, **kwargs):
        category = 'double_digit'
        return self._TEMPLATE_DIFF_VERBAL_STATEMENTS(category, **kwargs)

    def _problem_diff_verbal_statements_triple_digit(self, *args, **kwargs):
        category = 'triple_digit'
        return self._TEMPLATE_DIFF_VERBAL_STATEMENTS(category, **kwargs)

    def _problem_diff_verbal_statements(self, *args, **kwargs):
        category = None
        return self._TEMPLATE_DIFF_VERBAL_STATEMENTS(category, **kwargs)

    def _problem_diff_verbal_statements_extended(self, *args, **kwargs):
        category = 'extended'
        return self._TEMPLATE_DIFF_VERBAL_STATEMENTS(category, **kwargs)
    
    def _problem_place_values_basic(self, *args, **kwargs):
        category = 'basic'
        return self._TEMPLATE_PLACE_VALUES(category, **kwargs)
    
    def _problem_place_values_double_digit(self, *args, **kwargs):
        category = 'double_digit'
        return self._TEMPLATE_PLACE_VALUES(category, **kwargs)

    
    def _problem_place_values_triple_digit(self, *args, **kwargs):
        category = 'triple_digit'
        return self._TEMPLATE_PLACE_VALUES(category, **kwargs)

    
    def _problem_place_values(self, *args, **kwargs):
        category = None
        return self._TEMPLATE_PLACE_VALUES(category, **kwargs)

    
    def _problem_place_values_extended(self, *args, **kwargs):
        category = 'extended'
        return self._TEMPLATE_PLACE_VALUES(category, **kwargs)
    

    def _problem_compare_numbers_basic(self, *args, **kwargs):
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        number_words_pairs = ea_helper.get_number_words_pairs(category = 'basic')
        return self._TEMPLATE_COMPARE_NUMBERS(number_words_pairs, **kwargs)


    def _problem_compare_numbers_double_digit(self, *args, **kwargs):
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        number_words_pairs = ea_helper.get_number_words_pairs(category = 'double_digit')
        return self._TEMPLATE_COMPARE_NUMBERS(number_words_pairs, **kwargs)

    def _problem_compare_numbers_triple_digit(self, *args, **kwargs):
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        number_words_pairs = ea_helper.get_number_words_pairs(category = 'triple_digit')
        return self._TEMPLATE_COMPARE_NUMBERS(number_words_pairs, **kwargs)

    def _problem_compare_numbers(self, *args, **kwargs):
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        number_words_pairs = ea_helper.get_number_words_pairs(category = None)
        return self._TEMPLATE_COMPARE_NUMBERS(number_words_pairs, **kwargs)

    def _problem_compare_numbers_extended(self, *args, **kwargs):
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        number_words_pairs = ea_helper.get_number_words_pairs(category = 'extended')
        return self._TEMPLATE_COMPARE_NUMBERS(number_words_pairs, **kwargs)


    def _problem_write_numbers_in_words(self, *args, **kwargs):
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        number_words_pairs = ea_helper.get_number_words_pairs(category = None)
        return self._TEMPLATE_WRITE_NUMBERS_IN_WORDS(number_words_pairs, **kwargs)

    def _problem_write_numbers_in_words_extended(self, *args, **kwargs):
        ea_helper = self.base_helper.get_arithmetic_helper().get_elementary_integer_helper()
        number_words_pairs = ea_helper.get_number_words_pairs(category = 'extended')
        return self._TEMPLATE_WRITE_NUMBERS_IN_WORDS(number_words_pairs, **kwargs)


    def _sample(self, *args, **kwargs):
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
                