'''
Created on 4-Jan-2023

@author: b thakur

'''

import random
import inspect
import traceback

from ..helper import BaseHelper

from xv.km.managers import BaseManager
from xv.km.kelements import KProblemTemplate

from sympy import UnevaluatedExpr as ueval
from sympy import latex



# _physics_overview_manager
# PhysicsOverviewManager

class PhysicsOverviewManager(BaseManager):
    '''
    PhysicsOverviewManager
    Example:
        ke = PhysicsOverviewManager()
        ke.getRandomProblem()
        ke.getRandomProblem(problem_type = 0)
        ...
        
        ke.printProblem()
        ke.printAnswer()
        ke.printSolution()
        
        ke.printProblemTypes()
        
    '''    
    
    def __new__(cls, *args, **kwargs):
        instance = super(PhysicsOverviewManager, cls).__new__(cls, *args, **kwargs)
        for base_class in PhysicsOverviewManager.__bases__:
            base_class.__init__(instance, *args, **kwargs)
        return instance
    
    def __init__(self, *args, **kwargs):
        self.base_helper = BaseHelper(**kwargs)
        
        pass
    
    
    
    
    


    def _init_problem_types(self, *args, **kwargs):
        self._append_problem_types([
            '_problem_search_formulae',
            '_problem_useful_links',
            '_problem_introduction_technology_milestones',
            '_problem_scale_comparison',
            
            '_problem_measurement',
            '_problem_alternate_current',
            
            
            '_problem_q_a_school_physics_tarasov_tarasova',
            
            ])
        pass

    def _problem_search_formulae(self, *args, **kwargs):
        """
        parameters:
        @search: mandatory
        @url: optional

        doc_style: xv_doc
        """
        
        overview_helper = self.base_helper.get_overview_helper()
        
        search = kwargs.get('search', None)
        url = kwargs.get('url', None)

        # search is None, rerurn the link
        if search is None:
            return self._problem_all_formulae(*args, **kwargs)
        
        
        search_links = overview_helper.search_links(search, url)
        
        search_links_html = [f""" <li><a target="_blank" href="{href}">{a_text}</a></li> """ 
                             for a_text, href in search_links]
        
        search_links_html = "".join(search_links_html)
        search_links_html = f"<ol>{search_links_html}</ol>"
 
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Physics formulae related to '{search}'
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        
        soln_s = f"""
        Physics formulae related to '{search}':
        {search_links_html}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = soln_s
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
                

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

        doc_style: xv_doc
        """
        
        wl_helper = self.base_helper.get_web_link_helper()
        search_str = 'formulae'
        result = wl_helper.search(search_str)
        
        result = wl_helper.convert_links_to_strs(result)

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        if result is None:
            problemTemplate.add_problem(f"""
            No result found matching: 
                search_str = '{search_str}'
            """.strip(), 'text/html')
            return problemTemplate

        problem_s = f"""
        List of Physics formulae.
        Pass 'search' parameter to search something specific.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        
        soln_s = result['anchors_str']
        problemTemplate.add_solution(soln_s.strip(), 'text/html',
                                     add_html_line_break = False)
        
        answer_s = soln_s
        problemTemplate.add_answer(answer_s.strip(), 'text/html',
                                   add_html_line_break = False)
        
        return problemTemplate

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

        doc_style: xv_doc
        """
        
        wl_helper = self.base_helper.get_web_link_helper()
        search_str = 'useful links'
        result = wl_helper.search(search_str)
        
        result = wl_helper.convert_links_to_strs(result)

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        if result is None:
            problemTemplate.add_problem(f"""
            No result found matching: 
                search_str = '{search_str}'
            """.strip(), 'text/html')
            return problemTemplate

        problem_s = f"""
        Useful links related to Physics
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        
        soln_s = result['anchors_str']
        problemTemplate.add_solution(soln_s.strip(), 'text/html',
                                     add_html_line_break = False)
        
        answer_s = soln_s
        problemTemplate.add_answer(answer_s.strip(), 'text/html',
                                   add_html_line_break = False)
        
        return problemTemplate
                
    def _problem_introduction_technology_milestones(self, *args, **kwargs):
        """

        doc_style: xv_doc
        """
        
        wl_helper = self.base_helper.get_web_link_helper()
        search_str = 'technology milestones'
        result = wl_helper.search(search_str)
        
        result = wl_helper.convert_links_to_strs(result)

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        if result is None:
            problemTemplate.add_problem(f"""
            No result found matching: 
                search_str = '{search_str}'
            """.strip(), 'text/html')
            return problemTemplate

        problem_s = f"""
        Videos related technology milestones
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        
        soln_s = result['anchors_str']
        problemTemplate.add_solution(soln_s.strip(), 'text/html',
                                     add_html_line_break = False)
        
        answer_s = soln_s
        problemTemplate.add_answer(answer_s.strip(), 'text/html',
                                   add_html_line_break = False)
        
        return problemTemplate
                

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

        doc_style: xv_doc
        """
        
        wl_helper = self.base_helper.get_web_link_helper()
        search_str = 'scale comparison'
        result = wl_helper.search(search_str)
        
        result = wl_helper.convert_links_to_strs(result)

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        if result is None:
            problemTemplate.add_problem(f"""
            No result found matching: 
                search_str = '{search_str}'
            """.strip(), 'text/html')
            return problemTemplate

        problem_s = f"""
        Comparing scale of length
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        
        soln_s = result['anchors_str']
        problemTemplate.add_solution(soln_s.strip(), 'text/html',
                                     add_html_line_break = False)

        #https://openstax.org/books/physics/pages/23-1-the-four-fundamental-forces
        #http://hyperphysics.phy-astr.gsu.edu/hbase/Forces/funfor.html

        sTexts = [] 

        planck_length = 1.62 * 10 ** ueval(-35)
        sText = f"""
        The smallest verifiable length in the universe:
        $\\displaystyle \\text{{ planck_length }} = {latex(planck_length)} $
        """
        sTexts.append(sText.strip())
        
        range_of_weak_force = 1.0 * 10 ** ueval(-18)
        sText = f"""
        The range of weak force:
        $\\displaystyle \\text{{ range_of_weak_force }} = {latex(range_of_weak_force)} $
        """
        sTexts.append(sText.strip())
        
        range_of_strong_force = 1.0 * 10 ** ueval(-15)
        sText = f"""
        The range of strong force:
        $\\displaystyle \\text{{ range_of_strong_force }} = {latex(range_of_strong_force)} $
        """
        sTexts.append(sText.strip())
        
        size_of_nucleus = 1.0 * 10 ** ueval(-15)
        sText = f"""
        $\\displaystyle \\text{{ size_of_nucleus }} = {latex(size_of_nucleus)} $
        """
        sTexts.append(sText.strip())
        
        size_of_proton = 1.0 * 10 ** ueval(-15)
        sText = f"""
        $\\displaystyle \\text{{ size_of_proton }} = {latex(size_of_proton)} $
        """
        sTexts.append(sText.strip())
        
        size_of_neutron = 1.0 * 10 ** ueval(-15)
        sText = f"""
        $\\displaystyle \\text{{ size_of_neutron }} = {latex(size_of_neutron)} $
        """
        sTexts.append(sText.strip())
        
        size_of_atom = 1.0 * 10 ** ueval(-10)
        sText = f"""
        $\\displaystyle \\text{{ size_of_atom }} = {latex(size_of_atom)} $
        """
        sTexts.append(sText.strip())

        #https://www.khanacademy.org/science/physics/light-waves/introduction-to-light-waves/a/light-and-the-electromagnetic-spectrum
                
        wavelength_of_gamma_ray = 1.0 * 10 ** ueval(-12)
        wavelength_of_x_rays = 1.0 * 10 ** ueval(-9)
        wavelength_of_ultraviolet_ray = 4.0 * 10 ** ueval(-7)
        wavelength_of_visible_ray = 7.5 * 10 ** ueval(-7)
        wavelength_of_near_infrared_ray = 2.5 * 10 ** ueval(-7)
        wavelength_of_infrared_ray = 2.5 * 10 ** ueval(-6)
        wavelength_of_microwaves_ray = 1.0 * 10 ** ueval(-3)

        
        sText = f"""
        Higher boundary of wavelengths:
        $\\displaystyle \\text{{ wavelength_of_gamma_ray }} = {latex(wavelength_of_gamma_ray)} $
        $\\displaystyle \\text{{ wavelength_of_x_rays }} = {latex(wavelength_of_x_rays)} $
        $\\displaystyle \\text{{ wavelength_of_ultraviolet_ray }} = {latex(wavelength_of_ultraviolet_ray)} $
        $\\displaystyle \\text{{ wavelength_of_visible_ray }} = {latex(wavelength_of_visible_ray)} $
        $\\displaystyle \\text{{ wavelength_of_near_infrared_ray }} = {latex(wavelength_of_near_infrared_ray)} $
        $\\displaystyle \\text{{ wavelength_of_infrared_ray }} = {latex(wavelength_of_infrared_ray)} $
        $\\displaystyle \\text{{ wavelength_of_microwaves_ray }} = {latex(wavelength_of_microwaves_ray)} $
        """
        sTexts.append(sText.strip())
        
        

        sText = f"""
        
        One twist of a DNA molecule (10 base pairs, or $3.4 \\mathrm{{~nm}}$ ) would be $3.5756^* 10^{{\\wedge}}-2 \\mathrm{{ym}}$.
        
        UV radiation, broadly speaking, goes from $10 \\mathrm{{~nm}}$ to $400 \\mathrm{{~nm}}$ in wavelength. This would range from .105 to $4.207 \\mathrm{{ym}}$. UV radiation as long as a real-life neutrino (1 ym according to this: The Scale of the Universe $2(\\sqrt{{ }})$ would be near the limit of extreme UV radiation (10-100 nm).
        Visible light goes from 400 to $700 \\mathrm{{~nm}}$, which equates to $4.207$ to $7.361 \\mathrm{{ym}}$ on this scale.
        A red blood cell is around 7 micrometers $(\\mu \\mathrm{{m}})$ long on average. This would equate to $73.615$ yoctometers; nearly $3 / 4$ the size of a top quark $(100 \\mathrm{{ym}})$.
        
        The smallest thing we can see without any magnification would be $100 \\mu \\mathrm{{m}}$. If Earth were the size of a carbon atom, then we need magnification to see anything smaller than $1.052$ zeptometers (zm).
        
        A flea is about $1.5 \\mathrm{{~mm}}$ long. In this scale, a flea would be a little more than the size of a bottom quark ( $30 \\mathrm{{zm}})$
        
        A U.S. penny has a diameter of $1.9 \\mathrm{{~cm}}$. In this scale, that's barely twice the size of a charm quark (100 zm).
        
        A Nintendo 64 cartridge is about $11.4 \\mathrm{{~cm}}$, or $1.14$ decimeters long. This would make the cartridge about $1.199 \\mathrm{{am}}$, a little larger than an up quark or a down quark.
        
        The keyboard I used to make this comprehensive chart is $45 \\mathrm{{~cm}}$ long. This would scale to $4.732$ am.
        
        Leaving values lower than 1, we have the meter, which scales to $10.5164$ attometers if the Earth is the size of a carbon atom.
        
        The average human would stand at $1.7$ meters tall. This would scale to $17.878$ am, or a bit less than twice the size of the weak force.
        
        A Toyota Corolla is about $4.65$ meters long. This would equate to $48.901$ am, nearly five times the range of the weak force.
        
        A whale shark is about $9.7$ meters long on average. This would equate to $102.009$ am if Earth were the size of a carbon atom.
        
        The blue whale had a longest recorded length of $33.6 \\mathrm{{~m}}$. This would equate to $353.351 \\mathrm{{am}}$.
        An American football field (American football is more like rugby if you're international) is 360 feet long and 160 feet wide. This would equate to $109.728 \\mathrm{{~m}}$ by $48.768 \\mathrm{{~m}}$. That would be $512.864 \\mathrm{{am}}$ wide and $1.153 \\mathrm{{fm}}$. If Earth is the size of a carbon atom, we'd be playing football on a field painted onto a proton and we'd have to make a line for almost every 10 attometers.
        
        The Great Pyramid of Giza, which served as the grave of 4th Dynasty pharaoh Khufu, is $138.8$ meters tall and has a base length of $230.34$ meters. This would equate to a height of $1.46 \\mathrm{{fm}}$ and a base length of $2.422 \\mathrm{{fm}}$. At $2.85$ cubic femtometers, the Great Pyramid of Giza would take up more space than a proton!
        The Burj Khalifa, the tallest building in the world, is 828 meters tall. This would equate to $8.708$ fm. If you were to stack up five protons and stand on top of them, you would still be standing below the top of the Burj Khalifa.
        
        A land mile (5280 feet) would be $1.609344$ kilometers long. This would be $16.925$ femtometers on the scale we're working with. If it takes 20 minutes to walk a mile, then you'll only need a little under 19 minutes to walk across 10 protons.
        
        Mount Everest stands at 8,848 meters tall. To climb Mount Everest, you would have to climb 93.049 femtometers, or a little more than 58 protons.
        
        The Challenger Deep is $10.9$ kilometers deep. That's $114.629$ femtometers deep. This, however, ISN'T the deepest part of Earth. That honor goes to the Z-44 Chavyo oil well, which is 12,376 meters deep, or $130.151$ femtometers deep. To dig that deep, you would have to dig through 81 and a third protons.
        According to the IAAF, to run a marathon, you would have to run $42.195 \\mathrm{{~km}}$. That's about $443.74$ femtometers if the IAAF were to enact their rules on an atom-sized Earth.
        The Suez Canal, which connects the Red Sea with the Mediterranean Sea, is $193.3$ kilometers long. This is about $2.033$ picometers long, or a little more than $1 / 5$ the maximum length of a gamma ray.
        The Grand Canyon is $446 \\mathrm{{~km}}$ long, or $4.69$ picometers on a 134-picometer Earth.
        Ceres, a dwarf planet residing in the asteroid belt, has a radius of $476 \\mathrm{{~km}}$ (https://nesf2015.arc.nasa.gov/sites/default/files/downloads/pdf/05.pdf $\\lceil$ ), or a diameter of $952 \\mathrm{{~km}}$. This would make Ceres just $11.6$ femtometers larger than a gamma ray.
        
        Pluto, formerly considered a planet, has a radius of $1189.9 \\mathrm{{~km}}$, or a diameter of $2379.8 \\mathrm{{~km}}$. At 25 pm, Pluto would be a tiny bit smaller than the radius of a helium atom.
        Our moon, however, is $3474.2 \\mathrm{{~km}}$ in diameter. This would equate to $36.5 \\mathrm{{pm}}$, just a tiny bit smaller than the radius of a neon atom ( $38 \\mathrm{{pm}}$ ).
        Mercury, the smallest planet these days, has a diameter of $4879.4 \\mathrm{{~km}}$. This would put Mercury at $51.3 \\mathrm{{pm}}$, which is slightly smaller than the radius of a hydrogen atom (53 pm)
        Ganymede, the largest moon in the solar system, has a diameter of $5268.2 \\mathrm{{~km}}$. At $55.4 \\mathrm{{pm}}$ according to the atomic scale of Earth, this would make Ganymede just a tiny bit larger than the radius of a hydrogen atom.
        
        The longest river in the world, the Nile River, is 6853 kilometers long. At a scale length of $72.1$ pm, the Nile would almost travel across a neon atom, which has a diameter of $76 \\mathrm{{pm}}$.
        
        
        Earth, of course, would be 134 picometers since we had it become as large as a carbon atom.
        Jupiter, the largest planet in our solar system, has a diameter of 139,822 kilometers. This would equate to $1.47$ nanometers, or nearly $2.5$ times the diameter of a cesium atom (596 pmi
        Saturn is smaller, but its rings expand up to $136,780 \\mathrm{{~km}}$ outward, putting the diameter of the largest rings at $273,560 \\mathrm{{~km}}$. On this scale, Saturn's rings would be up to $2.877$ nanometers, which would make Saturn and its rings fit comfortably in a few base pairs of DNA.
        
        The Sun, of course, has a radius of $695,700 \\mathrm{{~km}}$, or a diameter of $1,391,400 \\mathrm{{~km}}$. This would make the sun $14.63$ nanometers in diameter, just a little longer than the shortest UV wave. Funnily enough, the sun produces UV rays, which harm the human skin.
        
        The Astronomical Unit, or the distance between the Earth and the Sun, is 149,597,870,700 meters long. That would equate to $11740.5$ times Earth's diameter, or more accurately $1.573$ $\\mu \\mathrm{{m}}$ That's almost $1 / 4$ of a way across a red blood cell.
        
        UY Scuti has a diameter of $15.886 \\mathrm{{AU}}$, or 1708 times the diameter of the sun. This would equate to $24.992 \\mu \\mathrm{{m}}$; wider than a strand of human hair.
        The orbit of Neptune has a semi-major axis of $30.110387 \\mathrm{{AU}}$. If Earth was $134 \\mathrm{{pm}}$ in diameter, than Neptune would be $47.371 \\mu \\mathrm{{m}}$ away from the sun.
        The heliopause, which can be considered the furthest extent of the solar system empirically speaking, extends $121 \\mathrm{{AU}}$ from the sun. To get to the Heliopause, one would have to go $190.361 \\mu \\mathrm{{m}}$.
        
        If light were to move for one second in a vacuum, it would have went $299,792.458 \\mathrm{{~km}}$. On scale, this would equate to $3152.738 \\mathrm{{pm}}$. One year on Earth is $365.26$ days, which means a light year is $9.460989493^* 10^{{\\wedge}} 12 \\mathrm{{~km}}$. This would equate to $99.495573073101 \\mathrm{{~mm}}$. That's almost 1 decimeter.
        
        1 parsec, which is defined as one astronomical unit subtended at an angle of 1 arcsecond (imagine a right triangle with one of the angles having a measurement of 1 arcsecond). This equates to $648000 / \\pi \\mathrm{{AU}}$, or $3.261474483$ light years. On the scale we're using, 1 parsec is $324.502 \\mathrm{{~mm}}$, or a little under the size of 3 Nintendo 64 cartridges.
        
        Proxima Centauri is the closest star to our solar system. It's $4.246$ light years away from us. This would equate to $422.458 \\mathrm{{~mm}}$, or a little under the size of 4 Nintendo 64 cartridges.
        The closest potentially habitable planet is Gliese $581 \\mathrm{{~d}}$, which is $20.37$ light years away from us. This would equate to $2.027 \\mathrm{{~m}}$; about $1.2$ times the height of the average human.
        
        Messier 15, a globular cluster, would be 175 light years diameter. This would equate to $17.412$ $\\mathrm{{m}}$ or $3.744$ Toyota Corollas.
        
        The Tarantula Nebula has a diameter of approximately 200 parsecs or $652.295$ light years. This would put its size at $64.9$ meters, which is nearly the size of 2 blue whales or 14 Toyota Corollas.
        
        Two dwarf galaxies known as the Small Magellanic Cloud and the Large Magellanic Cloud are 7000 ly and 14000 ly in diameter respectively. This would be equal to $696.469 \\mathrm{{~m}}$ and $1392.938$ $\\mathrm{{m}}$ respectively. The Small Magellanic Cloud would be 3 Pyramids of Giza (230.34m) or 299and-a-half Toyota Corollas. The Large Magellanic Cloud, on the other hand, would be 6 Pyramids of Giza or a little over 599 Toyota Corollas respectively.
        The Milky Way Galaxy has a diameter of at least 100,000 light years. This would equate to $9.95$ km on Earth's atomic scale. That's $2139.7$ Toyota Corollas.
        To get to the Andromeda Galaxy, you would have to travel 778 kiloparsecs or $2.529$ million light years. This would equate to $251.6647$ kilometers, or a little more than the driving distance from Orlando to Fort Myers (249.45 km).
        The Local Group is defined as a cluster of galaxies with a diameter of 10 million light years. This would equate to $994.956 \\mathrm{{~km}}$; a little under the distance from New York to Indianapolis $(1036 \\mathrm{{~km}})$
        
        The Virgo Supercluster a group of galactic clusters within a diameter of 33 megaparsecs (107.6 million light years). This would equate to $10,708.6$ kilometers. That's a little under the diameter of Venus.
        
        The largest known object is the Sloan Great Wall, which is about $1.38$ billion light years wide. That thing is, 1. Totally not put up by Trump, and 2. about $137,303.891 \\mathrm{{~km}}$ in scale. That's almost the size of Jupiter.
        Lastly, the observable universe has a diameter of 93 billion light years, which would equate to $9,253,088.3 \\mathrm{{~km}}$ to scale. This would equate to $6.65$ times the diameter of the sun AND a mere $6.2 \\%$ of an astronomical unit.

        """
        sTexts.append(sText.strip())
        
        sTexts = "\n\n".join(sTexts)
        problemTemplate.add_solution(sTexts.strip(), 'text/html')

        
        answer_s = soln_s
        problemTemplate.add_answer(answer_s.strip(), 'text/html',
                                     add_html_line_break = False)
        
        return problemTemplate
                


    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


    def _problem_measurement(self, *args, **kwargs):
        """
        
        """
        
        folder_path = "question_bank/physics/o_level"
        search_file_paths = [
                "measurement.txt"
            ]
        
        file_paths = self.get_q_bank_factory().search_question_bank_files(folder_path, search_file_paths)
        return self.get_q_bank_factory().PROBLEM_TEMPLATE_Q_BANK_RANDOM_QUESTION(file_paths, *args, **kwargs)





    def _problem_alternate_current(self, *args, **kwargs):
        folder_path = "comprehension/physics/electromagnetism"
        search = "alternate_current.txt"
        
        search_in_content = kwargs.get("search", None)
        file_paths = self.get_comp_factory().search_comprehension_files(folder_path,
                                                                        search_in_name = search,
                                                                        search_in_content = search_in_content)

        file_path = random.choice(file_paths)
        
        return self.get_comp_factory().PROBLEM_TEMPLATE_COMP_RANDOM_QUESTIONS(file_path, *args, **kwargs)

        
        
    def _problem_q_a_school_physics_tarasov_tarasova(self, *args, **kwargs):
        """
        
        """
        
        folder_path = "question_bank/physics"
        search_file_paths = [
                "q_a_school_physics_tarasov_tarasova.txt"
            ]
        
        file_paths = self.get_q_bank_factory().search_question_bank_files(folder_path, search_file_paths)
        return self.get_q_bank_factory().PROBLEM_TEMPLATE_Q_BANK_RANDOM_QUESTION(file_paths, *args, **kwargs)


