'''
Created on 16-Apr-2021

@author: rishi_priyansh
'''
from sympy import symbols, Eq, solve, Symbol, latex, sqrt, UnevaluatedExpr
from xv.km.ui import SvgHelper  
import matplotlib.pyplot as plt

import random
import inspect
import traceback

from ..helper import BaseHelper

from xv.km.managers import BaseManager
from xv.km.kelements import KProblemTemplate
        
class ParticlePhysicsManager(BaseManager):
    '''
    ParticlePhysicsManager
    Example:
        ke = ParticlePhysicsManager()
        ke.getRandomProblem()
        ke.getRandomProblem(problem_type = 0)
        ...
        
        ke.printProblem()
        ke.printAnswer()
        ke.printSolution()
        
        ke.printProblemTypes()
        
        reference link:
        <a target="_blank" href="https://www.youtube.com/watch?v=FoR3hq5b5yE">https://www.youtube.com/watch?v=FoR3hq5b5yE</a>
        <a target="_blank" href="https://www.youtube.com/watch?v=wf1W_ZfqYEs">https://www.youtube.com/watch?v=wf1W_ZfqYEs</a>
    '''    
    _OPR_TYPE_COUNT = 10
    
    def __new__(cls, *args, **kwargs):
        instance = super(ParticlePhysicsManager, cls).__new__(cls, *args, **kwargs)
        for base_class in ParticlePhysicsManager.__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_charge_of_a_proton',
            '_problem_charge_of_a_neutron',
            '_problem_types_of_quarks',
            '_problem_types_of_quarks_and_anti_quarks',
            '_problem_charge_of_quarks',
            '_problem_color_charge_for_strong_nuclear_force',
            '_problem_color_charge_of_particles',
            '_problem_color_charge_of_a_quark',
            '_problem_color_charge_of_a_antiquark',
            '_problem_color_charge_of_a_gluon',
            '_problem_responsible_for_electromagnetic_force',
            '_problem_responsible_for_strong_nuclear_force',
            '_problem_quark_emits_or_absorbs_a_gluon',
            '_problem_composite_particles',
            # '_problem_color_neutral_particles',
            '_problem_split_a_gluon',
            '_problem_formation_of_gluon',
            '_problem_virtual_composite_particles',
            '_problem_protons_neutron_binding_force',
            '_problem_difference_between_photons_and_gluons',
            '_problem_distance_between_charged_particles',
            '_problem_distance_between_quark_and_antiquark',
            '_problem_separate_a_quark_antiquark_pair',
            '_problem_individual_quarks',
            '_problem_individual_gluons',
            ])
        pass

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

        problem_s = f"""
        What is the charge of a proton
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        1 proton 
        = 2 up quark + 1 down quark
        = 2 * (+2/3) + 1 * (-1/3) \t\t an up quark has +2/3 charge and a down quark -1/3 
        = +1

        so 1 proton has +1 charge.
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate

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

        problem_s = f"""
        What is the charge of a neutron
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        A neutron a contains 1 up quarks and 2 down quark.
        A up quark has charge of +2/3
        A down quark has charge of -1/3

        So adding the charge
        $\\displaystyle 1 \\cdot (+\\frac{{2}}{{3}}) + 2 \\cdot (-\\frac{{1}}{{3}}) = 0$

        So neutron will have a charge of 0
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate

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

        problem_s = f"""
        What are types of quarks?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        There are 6 types of quarks.

        Up quark
        Down quark
        Charm quark
        Strange quark
        Top quark
        Bottom quark
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate

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

        problem_s = f"""
        What are types of quarks and antiquarks?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        There are 6 types of quarks.

        Up quark and Down quark
        Charm quark and Strange quark
        Top quark and Bottom quark
        
        There are 6 types of antiquarks.

        anti-Up quark and anit-Down quark
        anit-Charm quark and anit-Strange quark
        anit-Top quark and anit-Bottom quark
        
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate

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

        problem_s = f"""
        What are charges of quarks?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        An Up quark, a Charm quark, a Top quark, each has a charge of +2/3
        An Down quark, a Strange quark, a Bottom quark, each has a charge of -1/3
        
        (Add anti charges too)
        
        
        
        
        A Up quark has charge of +2/3
        A Down quark has charge of -1/3
        
        A Charm quark has charge of +2/3
        A Strange quark has charge of -1/3
        
        A Top quark has charge of +2/3
        A Bottom quark has charge of -1/3

        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate

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

        problem_s = f"""
        An electrostaic force is due to electric charge. What is responsible for strong nuclear force?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        The color charge is responsible for the strong nuclear force.

        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate

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

        problem_s = f"""
        Which particles can contain color charges?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        Quarks, antiquarks and gluons contain color charges.
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate

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

        problem_s = f"""
        What are possible color charges of quark?    
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        A quark will a single net color charge. It could be B, G, or R.
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate

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

        problem_s = f"""
        What are possible color charges of anitquark?    
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        A antiquark will a single net color charge. It could be anti-B, anti-G, or anti-R.
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate

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

        problem_s = f"""
        What are possible color charges of gluons?    
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        A gluon must have one color charge and another anti-color charge.
        (Write possible examples)
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate

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

        problem_s = f"""
        Why does electricmagnetic field exist according to particle physics.   
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        Electromagnetic foeld is basically exchange of photons between charged particles
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate

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

        problem_s = f"""
        As photons is exchanged in electomagnectic fore, so what is exchanged in strong nuclear force?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        Gluon is exchanged in strong nuclear force
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate

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

        problem_s = f"""
        What happens if a quark emits or absorbs a gluon?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        The quark changes its color. For example:
        if a quark is R and it absorbs gluon of anti-R + B it will become B
        R + anti-R + B = B
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate

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

        problem_s = f"""
        What are composite particles?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        All composite particles are made of more than one quark and are color charge neutral.
        Examples are protons and neutrons.
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate

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

        problem_s = f"""
        What are color neutral particles?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        If we count the color of the quarks and gluons then we will find same amount of
        red, blue and green. But the quark and gluons are in a quantum superposition of different possible colors.
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate

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

        problem_s = f"""
        What can gluon split into?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        A gluon will be split into a quark and an antiquark only if color is not changed.
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate

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

        problem_s = f"""
        How are gluons formed?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        When a quark and an antiquark annihilate each other and form a gluon.
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate

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

        problem_s = f"""
        What are virtual composite particles?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        A pair of quark and antiquark with same color charge. They are emitted and absorbed
        by protons and neutrons.

        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate

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

        problem_s = f"""
        What holds protons and neutrons together in a nucleus?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        The exchange of virtual composite particles between the protons and neutrons. THe virtual composite
        paritcles decay really quickly. So protons and neutron have to be really close in order to the binding force to work.
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate

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

        problem_s = f"""
        What's the difference between photons and gluons?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        Photon are chargeless particle but gluon has color charge, so it can emit and absorb other 
        gluons, allowing gluons to attract one another.
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate

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

        problem_s = f"""
        What happens if increase the distance between 2 charged particles?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        THe electromagnetic force between them decreases.
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate

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

        problem_s = f"""
        What happens if increase the distance between quark and antiquark pair?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        THe strong nuclear force does not change .
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate

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

        problem_s = f"""
        What happens if you try to separate a quark and antiquark pair?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        The energy applied to separate a quark and antiquark pair will be converted
        into creation of new quark and antiquark pair.
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate

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

        problem_s = f"""
        Why can't individual quarks exist?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        Due to strong force, all the quarks and anti-quarks must clump together to create color neutral composite 
        particle. A individual quirk or an anti-quark cannot be color neutral, thus individual quarks cannot exist.
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate

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

        problem_s = f"""
        Why can't individual gluons exist?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        An individual gluon also can't be color neutral, and an individual gluon
        also can't exist on its own, as it would never escape the attraction of other gluons.
        But, a combination of two or more gluons could be color neutral,
        and could therefore exist independently of quarks as what we call a 'glue-ball.'
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate



