'''
Created on 12-Jul-2021

@author: bthakur
'''
import random
import inspect
import traceback

from sympy import (pi, latex,
                   Rational, 
                   symbols, Symbol, Function, 
                   UnevaluatedExpr,
                   Eq, dsolve, solve,
                   sqrt)
import sympy


from xv.km.util import SympyUnitSystem
from xv.km.helper import BaseEquationHelper

class LawOfProportionHelper(BaseEquationHelper):
    def __init__(self, **kwargs):
        self.verbose = kwargs.get('verbose', False)
        super().__init__(**kwargs)
        
        self.set_data_method_names(self._init_data_method_names())
        pass

    def _init_data_method_names(self):
        
        data_method_names = [
            
            '_get_force_acceleration',
            '_get_specific_heat',
            '_get_specific_latent_heat_of_evaporation',
            
            '_get_force_of_spring',
            '_get_gravitational_force',
            '_get_ideal_gas_volume',
    
            '_get_force_acceleration',
            '_get_specific_heat',
            '_get_specific_latent_heat_of_evaporation',
    
            '_get_resistance_of_wire_rho',
            '_get_resistance_of_wire_sigma',
            '_get_current_due_to_voltage',
            '_get_capacitance_and_voltage',
            
            '_get_volume_of_cuboid',
            '_get_volume_of_cylinder',
            '_get_volume_of_cone',
            '_get_volume_of_sector_of_shpere',
    
            
            '_get_surface_area_of_sector_of_shpere',
            '_get_curved_surface_area_of_cylinder',
            '_get_area_of_sector_of_circle',
            '_get_length_of_arc',
            '_get_area_of_triangle',
            '_get_area_of_rectangle',
            
            '_get_time_to_finish_work',
            '_get_discount_on_price',
            '_get_principal_time_interest',

            
            '_get_data_speed_time_distance',
            '_get_time_to_finish_work_with_units',
            
            '_get_electrostatic_force',
            ]
        return data_method_names

    def _get_data_speed_time_distance(self):
        s, t, d, k = symbols(r's, t, d, k', positive = True)

        label_dict = {
            s: "Speed",
            t: "Time",
            d: "Distance",
            k: "Constant",
        }

        ps = SympyUnitSystem()
        s_val = random.randint(2, 20)
        t_val = random.randint(2, 20)
        d_val = s_val * t_val
        k_val = 1
        
        var_values = {
            s: s_val * ps.convert_to_base_units('m/sec'),
            t: t_val * ps.convert_to_base_units('sec'),
            d: d_val * ps.convert_to_base_units('m'),
            k: k_val,
        }

        eq = Eq(d, s * t)

        lhs_symbol = d
        const_symbols = [k]
        rhs_symbols = [s, t]
        
        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': k_val,
            'eq': eq,
            }

        return data

    def _get_time_to_finish_work_with_units(self):
        d, j, w, r, k = symbols(r'd, j, w, r, k')

        label_dict = {
            d: "Days to finish jobs",
            j: "Number of jobs to do",
            w: "Number of workers",
            r: "rate of job done per day by each worker",
            k: "constant",
        }
        
        ps = SympyUnitSystem()
        r_val = random.randint(2, 10) 
        d_val = random.randint(2, 20)
        w_val = random.randint(2, 20) 
        j_val = r_val * d_val * w_val
        const = 1

        ps.ureg.define('worker = w')
        ps.ureg.define('job = j')
        
        var_values = {
            d: d_val * ps.get_quantity('day'), 
            j: j_val * ps.get_quantity('job'), 
            w: w_val * ps.get_quantity('worker'), 
            r: r_val * ps.get_quantity('job / (worker * day)'), 
            k: const,
        }

        lhs_symbol = d
        const_symbols = [k]
        rhs_symbols = [j, w, r]

        t_lhs = d
        t_const = const
        t_rhs = j / (w * r)
                                  
        eq = Eq(t_lhs, 
                UnevaluatedExpr(t_rhs)
                )
                                  
        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': t_const,
            'eq': eq,
            }

        return data
        pass

    def _get_time_to_finish_work(self):
        d, j, w, r, k = symbols(r'd, j, w, r, k')

        label_dict = {
            d: "Days to finish jobs",
            j: "Number of jobs to do",
            w: "Number of workers",
            r: "rate of job done per day by each worker",
            k: "constant",
        }
        
        r_val = random.randint(2, 10) 
        d_val = random.randint(2, 20)
        w_val = random.randint(2, 20) 
        k_val = 1
        j_val = k_val * r_val * d_val * w_val
        
        var_values = {
            d: d_val, 
            j: j_val, 
            w: w_val, 
            r: r_val, 
            k: k_val,
        }

        lhs_symbol = d
        const_symbols = [k]
        rhs_symbols = [j, w, r]

        t_lhs = d
        t_const = k_val
        t_rhs = j / ( r * w)
                                  
        eq = Eq(t_lhs, 
                UnevaluatedExpr(t_rhs)
                )
                                  
        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': t_const,
            'eq': eq,
            }

        return data
        pass

    def _get_discount_on_price(self):
        p, r, d, k = symbols(r'p, r, d, k')

        label_dict = {
            p: "Price",
            r: "Rate of discount",
            d: "Discount",
            k: "constant",
        }
        
        ps = SympyUnitSystem()
        p_val = random.randint(2, 10) * 100
        r_val = random.randint(2, 10) / 100
        k_val = 1
        d_val = k_val * p_val * r_val
        
        var_values = {
            p: p_val, 
            r: r_val, 
            d: d_val, 
            k: k_val,
        }

        lhs_symbol = d
        const_symbols = [k]
        rhs_symbols = [p, r]

        t_lhs = d
        t_const = k_val
        t_rhs = UnevaluatedExpr(p) * UnevaluatedExpr(r)
                                  
        eq = Eq(t_lhs, 
                UnevaluatedExpr(t_rhs)
                )
                                  
        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': t_const,
            'eq': eq,
            }

        return data
        pass

    def _get_principal_time_interest(self):
        
        i, p, r, t, k = symbols(r'i, p, r, t, k')

        label_dict = {
            i: "Interest",
            p: "Principal",
            r: "Rate of interest",
            t: "Time",
            k: "constant",
        }
        
        ps = SympyUnitSystem()
        p_val = random.randint(2, 10) * 100
        r_val = random.randint(2, 10) / 100
        t_val = random.randint(2, 10) 
        k_val = 1
        i_val = k_val * p_val * r_val * t_val

        var_values = {
            p: p_val, 
            r: r_val, 
            t: t_val,
            i: i_val, 
            k: k_val,
        }
        

        lhs_symbol = i
        const_symbols = [k]
        rhs_symbols = [p, r, t]

        t_lhs = i
        t_const = k_val
        t_rhs = UnevaluatedExpr(p) * UnevaluatedExpr(r) * UnevaluatedExpr(t)
                                  
        eq = Eq(t_lhs, 
                UnevaluatedExpr(t_rhs)
                )
                                  
        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': t_const,
            'eq': eq,
            }

        return data
        pass


    def _get_area_of_rectangle(self):
        a, w, h, k = symbols(r'a, w, h, k')

        label_dict = {
            a: "Area of rectangle",
            w: "Width of rectangle",
            h: "Height of rectangle",
            k: "constant",
        }
        
        ps = SympyUnitSystem()
        w_val = random.randint(2, 10) 
        h_val = random.randint(2, 10)
        k_val = 1
        a_val = k_val * w_val * h_val
        
        var_values = {
            w: w_val * ps.get_quantity('m'), 
            h: h_val * ps.get_quantity('m'), 
            a: a_val * ps.get_quantity('m ** 2'), 
            k: k_val,
        }

        lhs_symbol = a
        const_symbols = [k]
        rhs_symbols = [w, h]

        t_lhs = a
        t_const = k_val
        t_rhs = UnevaluatedExpr(w) * UnevaluatedExpr(h)
                                  
        eq = Eq(t_lhs, 
                UnevaluatedExpr(t_rhs)
                )
                                  
        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': t_const,
            'eq': eq,
            }

        return data
        pass

    def _get_area_of_triangle(self):
        a, w, h, k = symbols(r'a, w, h, k')

        label_dict = {
            a: "Area of triangle",
            w: "Width of triangle",
            h: "Height of triangle",
            k: "constant",
        }
        
        ps = SympyUnitSystem()
        w_val = random.randint(2, 10) 
        h_val = random.randint(2, 10)
        k_val = Rational(1, 2)
        a_val = k_val * w_val * h_val
        
        var_values = {
            w: w_val * ps.get_quantity('m'), 
            h: h_val * ps.get_quantity('m'), 
            a: a_val * ps.get_quantity('m ** 2'), 
            k: k_val,
        }

        lhs_symbol = a
        const_symbols = [k]
        rhs_symbols = [w, h]

        t_lhs = a
        t_const = k_val
        t_rhs = UnevaluatedExpr(w) * UnevaluatedExpr(h)
                                  
        eq = Eq(t_lhs, 
                UnevaluatedExpr(t_const) * UnevaluatedExpr(t_rhs)
                )
                                  
        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': t_const,
            'eq': eq,
            }

        return data

    def _get_length_of_arc(self):
        r, theta, l, k = symbols(r'r, \theta, l, k')

        label_dict = {
            r: "Radius of arc",
            theta: "Angle of arc",
            l: "length of arc",
            k: "constant",
        }
        
        ps = SympyUnitSystem()
        r_val = random.randint(1, 10) 
        theta_val = Rational(1, random.randint(1, 8)) * 2 * pi
        k_val = 1
        l_val = k_val * r_val * sympy.N(theta_val)

        
        var_values = {
            theta: theta_val * ps.get_quantity(r'radian'), 
            r: r_val * ps.get_quantity(r'm'),
            l: l_val * ps.get_quantity(r'm'), 
            k: k_val,
        }

        lhs_symbol = l
        const_symbols = [k]
        rhs_symbols = [theta, r]

        t_lhs = l
        t_const = k_val
        t_rhs = UnevaluatedExpr(r) * UnevaluatedExpr(theta)
                                  
        eq = Eq(t_lhs, 
                UnevaluatedExpr(t_rhs)
                )
                                  
        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': t_const,
            'eq': eq,
            }

        return data
        pass


    def _get_area_of_sector_of_circle(self):
        r, theta, a, k = symbols(r'r, \theta, a, k')

        label_dict = {
            r: "Radius of sector",
            theta: "Angle of sector",
            a: "Area of sector",
            k: "constant",
        }
        
        ps = SympyUnitSystem()
        r_val = random.randint(1, 10) 
        theta_val = Rational(1, random.randint(1, 8)) * 2 * pi
        k_val = Rational(1, 2)
        a_val = k_val * sympy.N(theta_val) * r_val**2

        
        var_values = {
            theta: theta_val * ps.get_quantity(r'radian'), 
            r: r_val * ps.get_quantity(r'm'),
            a: a_val * ps.get_quantity(r'm**2'), 
            k: k_val,
        }

        lhs_symbol = a
        const_symbols = [k]
        rhs_symbols = [theta, r]

        t_lhs = a
        t_const = k_val
        t_rhs = theta * r**2
                                  
        eq = Eq(t_lhs, 
                UnevaluatedExpr(t_const) * UnevaluatedExpr(t_rhs)
                )
                                  
        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': t_const,
            'eq': eq,
            }

        return data
        pass
    
    
    def _get_surface_area_of_sector_of_shpere(self):
        r, phi, A, k = symbols(r'r, \phi, A, k')

        ps = SympyUnitSystem()
        r_val = random.randint(1, 10) 
        phi_val = Rational(1, random.randint(1, 10)) * 4 * pi
        k_val = 1
        A_val = k_val * sympy.N(phi_val) * r_val**2
        
        label_dict = {
            r: "Radius of sector of sphere",
            phi: "Solid angle of sector of sphere",
            A: "Surface area of sector of sphere",
            k: "constant",
        }
        
        
        var_values = {
            phi: phi_val * ps.get_quantity(r'radian'), 
            r: r_val * ps.get_quantity(r'm'),
            A: A_val * ps.get_quantity(r'm**2'), 
            k: k_val,
        }

        lhs_symbol = A
        const_symbols = [k]
        rhs_symbols = [phi, r]

        t_lhs = A
        t_const = k_val
        t_rhs = phi * r**2
                                  
        eq = Eq(t_lhs, UnevaluatedExpr(t_rhs))
                                  
        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': t_const,
            'eq': eq,
            }

        return data
        pass

    def _get_curved_surface_area_of_cylinder(self):
        a, c, r, l, h, k = symbols(r'a, c, r, l, h, k')

        ps = SympyUnitSystem()
        r_val = random.randint(1, 10) 
        c_val = 2 * pi * r_val
        h_val = random.randint(1, 20)

        k_val = 1
        a_val = k_val * c_val * h_val
        c_func = 2 * pi * r

        label_dict = {
            a: f"Curved surface area of cylinder",
            r: "Radius of base of cylinder",
            c: f"Circumference of base of cylinder (${latex(c_func)}$)",
            h: "Height of cylinder",
            k: "constant",
        }
        
        
        var_values = {
            a: a_val * ps.get_quantity(r'm**2'),
            r: r_val * ps.get_quantity(r'm'),
            c: 2 * pi * r,
            h: h_val * ps.get_quantity(r'm'),
            k: k_val,
        }

        lhs_symbol = a
        const_symbols = [k]
        rhs_symbols = [c, h]

        t_lhs = a
        t_const = k_val
        t_rhs = c * h
        t_rhs_standard = UnevaluatedExpr(c_func) * UnevaluatedExpr(h)
                                  
        eq = Eq(t_lhs, UnevaluatedExpr(t_rhs))
        
        standard_eq = Eq(t_lhs, 
                         UnevaluatedExpr(t_rhs_standard)
                         )
                                  
        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': t_const,
            'eq': eq,
            'standard_eq': standard_eq,
            }

        return data
        pass


    def _get_volume_of_sector_of_shpere(self):
        r, phi, V, k = symbols(r'r, \phi, V, k')

        label_dict = {
            r: "Radius of sector of sphere",
            phi: "Solid angle of sector of sphere",
            V: "Volume of sector of sphere",
            k: "constant",
        }
        
        ps = SympyUnitSystem()
        r_val = random.randint(1, 10) 
        phi_val = Rational(1, random.randint(1, 10)) * 4 * pi
        k_val = Rational(1, 3)
        V_val = k_val * sympy.N(phi_val) * r_val**3

        
        var_values = {
            phi: phi_val * ps.get_quantity(r'radian'), 
            r: r_val * ps.get_quantity(r'm'),
            V: V_val * ps.get_quantity(r'm**3'), 
            k: k_val,
        }

        lhs_symbol = V
        const_symbols = [k]
        rhs_symbols = [phi, r]

        t_lhs = V
        t_const = k_val
        t_rhs = phi * r**3
                                  
        eq = Eq(t_lhs, 
                UnevaluatedExpr(t_const) * UnevaluatedExpr(t_rhs))
                                  
        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': t_const,
            'eq': eq,
            }

        return data
        pass

    def _get_volume_of_cylinder(self):
        V, r, B, h, k = symbols(r'V, r, B, h, k')

        ps = SympyUnitSystem()
        r_val = random.randint(1, 10) 
        B_val = pi * r_val**2
        h_val = random.randint(1, 20)

        k_val = 1
        V_val = k_val * B_val * h_val
        B_func = pi * r**2

        label_dict = {
            V: f"Volume of cylinder",
            r: "Radius of base of cylinder",
            B: f"Area of base of cylinder (${latex(B_func)}$)",
            h: "Height of cylinder",
            k: "constant",
        }
        
        
        var_values = {
            V: V_val * ps.get_quantity(r'm**3'),
            r: r_val * ps.get_quantity(r'm'),
            B: B_val,
            h: h_val * ps.get_quantity(r'm'),
            k: k_val,
        }

        lhs_symbol = V
        const_symbols = [k]
        rhs_symbols = [B, h]

        t_lhs = V
        t_const = k_val
        t_rhs = B * h
        t_rhs_standard = UnevaluatedExpr(B_func) * UnevaluatedExpr(h)
                                  
        eq = Eq(t_lhs, t_rhs)
        standard_eq = Eq(t_lhs, t_rhs_standard)
                                  
        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': t_const,
            'eq': eq,
            'standard_eq': standard_eq,
            }

        return data
        pass

    def _get_volume_of_cuboid(self):
        V, l, w, h, k = symbols(r'V, l, w, h, k')

        label_dict = {
            V: f"Volume of cuboid",
            l: "Length of cuboid",
            w: "Width of cuboid",
            h: "Height of cuboid",
            k: "constant",
        }
        
        ps = SympyUnitSystem()
        l_val = random.randint(1, 10) 
        w_val = random.randint(1, 10) 
        h_val = random.randint(1, 20)

        k_val = 1
        V_val = k_val * l_val * w_val * h_val
        
        var_values = {
            V: V_val * ps.get_quantity(r'm**3'),
            l: l_val * ps.get_quantity(r'm'),
            w: w_val * ps.get_quantity(r'm'),
            h: h_val * ps.get_quantity(r'm'),
            k: k_val,
        }

        lhs_symbol = V
        const_symbols = [k]
        rhs_symbols = [l, w, h]

        t_lhs = V
        t_const = k_val
        t_rhs = UnevaluatedExpr(l) * UnevaluatedExpr(w) * UnevaluatedExpr(h)

                                  
        eq = Eq(t_lhs, t_rhs)
                                  
        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': t_const,
            'eq': eq,
            }

        return data
        pass


    def _get_ideal_gas_volume(self):
        P, V, n, R, T = symbols(r'P, V, n, R, T')

        label_dict = {
            V: "Volume of ideal gas",
            n: "Number of moles of ideal gas",
            P: "External pressure on of ideal gas",
            T: "Temperature of ideal gas",
            R: "Ideal Gas Constant",
        }

        ps = SympyUnitSystem()
        R_val = ps.convert_to_base_units('molar_gas_constant')
        P_val = random.randint(2, 20)
        n_val = random.randint(2, 20)
        T_val = random.randint(273, 350)
        V_val = (n_val * R_val.magnitude * T_val) / P_val
        
        var_values = {
            V: V_val * ps.get_quantity('m ** 3'),
            n: n_val * ps.get_quantity('mole'),
            P: P_val * ps.get_quantity('pascal'),
            T: T_val * ps.get_quantity('kelvin'),
            R: R_val, 
        }

        lhs_symbol = V
        const_symbols = [R]
        rhs_symbols = [n, P, T]

        t_lhs = V
        t_const = R
        t_rhs = n * T / P
                                  
        eq = Eq(t_lhs, 
                UnevaluatedExpr(t_const) * UnevaluatedExpr(t_rhs))

        standard_eq = Eq(P * V, 
                         UnevaluatedExpr(n) * 
                         UnevaluatedExpr(R * T))
        
                     
        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': t_const,
            'eq': eq,
            'standard_eq': standard_eq,
            }

        return data
        pass


    def _get_force_acceleration(self):
        F, m, a = symbols(r'F, m, a')

        label_dict = {
            F: "Force on mass",
            m: "Mass",
            a: "Change in speed or acceleration of mass",
        }
        
        ps = SympyUnitSystem()
        m_val = random.randint(2, 10) 
        a_val = random.randint(2, 10) 
        F_val = m_val * a_val
        
        var_values = {
            F: F_val * ps.get_quantity('newton'), 
            m: m_val * ps.get_quantity('kg'), 
            a: a_val * ps.get_quantity('m/second**2'), 
        }

        lhs_symbol = F
        const_symbols = [m]
        rhs_symbols = [a]

                                  
        t_lhs = F
        t_const = m
        t_rhs = a

        eq = Eq(t_lhs, 
                UnevaluatedExpr(t_const) * UnevaluatedExpr(t_rhs))
                                  
                                  
        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': t_const,
            'eq': eq,
            }

        return data
        pass

    def _get_force_of_spring(self):
        F, k, x = symbols(r'F, k, x')

        label_dict = {
            F: "Force of spring due to stretching or compression",
            k: "Spring constant",
            x: "Length of stretching or compression of spring",
        }
        
        ps = SympyUnitSystem()
        x_val = random.randint(2, 20) / 100
        k_val = random.randint(2, 20) / 100
        F_val = k_val * x_val
        
        var_values = {
            F: F_val * ps.get_quantity('newton'), 
            k: k_val * ps.get_quantity('newton/m'), 
            x: x_val * ps.get_quantity('m'), 
        }

        lhs_symbol = F
        const_symbols = [k]
        rhs_symbols = [x]

        t_lhs = F
        t_const = k
        t_rhs = x
                                  
        eq = Eq(t_lhs, 
                UnevaluatedExpr(t_const) * UnevaluatedExpr(t_rhs))
                                  
        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': t_const,
            'eq': eq,
            }

        return data
        pass


    def _get_gravitational_force(self):
        F, G, m1, m2, r = symbols(r'F, G, m_1, m_2, r')

        label_dict = {
            F: "Gravitational Force",
            G: "Gravitational Constant",
            m1: "First mass",
            m2: "Second mass",
            r: "Distance between masses",
        }

        ps = SympyUnitSystem()
        G_val = ps.convert_to_base_units('newtonian_constant_of_gravitation')
        m1_val = random.randint(2, 20)
        m2_val = random.randint(2, 20)
        r_val = random.randint(2, 20)
        F_val = (G_val.magnitude * m1_val * m2_val) / (r_val**2)
        
        var_values = {
            F: F_val * ps.get_quantity('newton'),
            G: G_val,
            m1: m1_val * ps.convert_to_base_units('kg'),
            m2: m2_val * ps.convert_to_base_units('kg'),
            r: r_val * ps.convert_to_base_units('m'),
        }

        lhs_symbol = F
        const_symbols = [G]
        rhs_symbols = [m1, m2,  r]

        t_lhs = F
        t_const = G
        t_rhs = m1 * m2 * 1/r**2
                                  
        eq = Eq(t_lhs, 
                UnevaluatedExpr(t_const) * UnevaluatedExpr(t_rhs))
                                  
        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': t_const,
            'eq': eq,
            }

        return data
        pass


    def _get_resistance_of_wire_rho(self):
        R, rho, L, A = symbols(r'R, \rho, L, A')

        label_dict = {
            R: f"Resistance of conducting wire",
            L: "Length of conducting wire",
            A: "Cross section area of conducting wire",
            rho: "Resistivity of conducting wire",
        }

        ps = SympyUnitSystem()
        rho_val = random.randint(1, 20) * 10**(-8)
        L_val = random.randint(1, 20)
        A_val = random.randint(1, 20) / 10000

        R_val = rho_val * L_val / A_val

        var_values = {
            R: R_val * ps.get_quantity(r'ohm'),
            L: L_val * ps.get_quantity(r'm'),
            A: A_val * ps.get_quantity(r'm**2'),
            rho: rho_val * ps.get_quantity(r'ohm * m'),
        }
        
        lhs_symbol = R
        const_symbols = [rho]
        rhs_symbols = [L, A]

        t_lhs = R
        t_const = rho
        t_rhs = L * 1/A

        eq = Eq(t_lhs, 
                UnevaluatedExpr(t_const) * UnevaluatedExpr(t_rhs))
                                  
        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': t_const,
            'eq': eq,
            }

        return data
        pass

    def _get_resistance_of_wire_sigma(self):
        R, sigma, L, A = symbols(r'R, \sigma, L, A')

        label_dict = {
            R: f"Resistance of conducting wire",
            L: "Length of conducting wire",
            A: "Cross section area of conducting wire",
            sigma: "Conductivity of conducting wire",
        }

        ps = SympyUnitSystem()
        sigma_val = random.randint(1, 20) * 10**(7)
        L_val = random.randint(1, 20)
        A_val = random.randint(1, 20) / 10000

        R_val = (1/sigma_val) * L_val / A_val

        var_values = {
            R: R_val * ps.get_quantity(r'ohm'),
            L: L_val * ps.get_quantity(r'm'),
            A: A_val * ps.get_quantity(r'm**2'),
            sigma: sigma_val * ps.get_quantity(r'1/(ohm * m)'),
        }
        
        lhs_symbol = R
        const_symbols = [sigma]
        rhs_symbols = [L, A]

        t_lhs = R
        t_const = 1/sigma
        t_rhs = L * 1/A

        eq = Eq(t_lhs, 
                UnevaluatedExpr(t_const) * UnevaluatedExpr(t_rhs))
                                  
        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': t_const,
            'eq': eq,
            }

        return data
        pass
    

    def _get_current_due_to_voltage(self):
        V, I, R = symbols(r'V, I, R')

        label_dict = {
            V: "Voltage Source in the circuit",
            I: "Current through the circuit",
            R: f"Resistance of the circuit",
        }

        ps = SympyUnitSystem()
        I_val = random.randint(1, 20)
        R_val = random.randint(1, 20) / 100
        V_val = I_val * R_val

        var_values = {
            V: V_val * ps.get_quantity(r'volt'),
            R: R_val * ps.get_quantity(r'ohm'),
            I: I_val * ps.get_quantity(r'ampere'),
        }
        
        lhs_symbol = I
        const_symbols = [R]
        rhs_symbols = [V]

        t_lhs = I
        t_const = 1/R
        t_rhs = V

        eq = Eq(t_lhs, 
                UnevaluatedExpr(t_const) * UnevaluatedExpr(t_rhs))
                                  
                                  
        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': t_const,
            'eq': eq,
            }

        return data

        pass


    def _get_capacitance_and_voltage(self):
        V, Q, C = symbols(r'V, Q, C')

        label_dict = {
            V: "Voltage across capacitor",
            Q: "Charge on each plate of capacitor",
            C: f"Capacitance of capacitor",
        }

        ps = SympyUnitSystem()
        V_val = random.randint(1, 20)
        C_val = random.randint(1, 20) * 10**(-6) 
        Q_val = C_val * V_val

        var_values = {
            Q: Q_val * ps.get_quantity(r'coulombs'),
            C: C_val * ps.get_quantity(r'faraday'),
            V: V_val * ps.get_quantity(r'volt'),
        }
        
        lhs_symbol = Q
        const_symbols = [C]
        rhs_symbols = [V]

        t_lhs = Q
        t_const = C
        t_rhs = V

        eq = Eq(t_lhs, 
                UnevaluatedExpr(t_const) * UnevaluatedExpr(t_rhs))
                                  
        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': t_const,
            'eq': eq,
            }

        return data

        pass

    def _get_specific_heat(self):

        deltaQ = Symbol(r'\Delta Q')
        deltaT = Symbol(r'\Delta T')
        m, c = symbols(r'm, c')

        label_dict = {
            deltaQ: "Change in heat",
            m: "Mass of the matter",
            c: "Specific heat of the matter",
            deltaT: "Change in temperature",
            
        }

        ps = SympyUnitSystem()
        m_val = random.randint(1, 20)
        c_val = random.randint(1, 20) * 10**(3) 
        deltaT_val = random.randint(1, 20)
        deltaQ_val = m_val * c_val * deltaT_val

        var_values = {
            deltaQ: deltaQ_val * ps.get_quantity(r'joule'),
            c: c_val * ps.get_quantity(r'joule/(kg*kelvin)'),
            m: m_val * ps.get_quantity(r'kg'),
            deltaT: deltaT_val * ps.get_quantity(r'kelvin'),
        }
        
        lhs_symbol = deltaQ
        const_symbols = [c]
        rhs_symbols = [m, deltaT]

        t_lhs = deltaQ
        t_const = c
        t_rhs = UnevaluatedExpr(m) * UnevaluatedExpr(deltaT)

        eq = Eq(t_lhs, 
                UnevaluatedExpr(t_const) * UnevaluatedExpr(t_rhs))
                                  
        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': t_const,
            'eq': eq,
            }

        return data
        pass

    def _get_specific_latent_heat_of_evaporation(self):

        deltaQ = Symbol(r'\Delta Q')
        m, L = symbols(r'm, L')

        label_dict = {
            deltaQ: "Change in heat",
            m: "Mass of the matter",
            L: "Specific latent heat of evaporation of the matter",
            
        }

        ps = SympyUnitSystem()
        m_val = random.randint(1, 20)
        L_val = random.randint(1, 20) * 10**(3) 
        deltaQ_val = m_val * L_val

        var_values = {
            deltaQ: deltaQ_val * ps.get_quantity(r'joule'),
            L: L_val * ps.get_quantity(r'joule/kg'),
            m: m_val * ps.get_quantity(r'kg'),
        }
        
        lhs_symbol = deltaQ
        const_symbols = [L]
        rhs_symbols = [m]
        
        t_lhs = deltaQ
        t_const = L
        t_rhs = m

        eq = Eq(t_lhs, 
                UnevaluatedExpr(t_const) * UnevaluatedExpr(t_rhs))

                                  
        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': t_const,
            'eq': eq,
            }

        return data

        pass

    def _get_volume_of_cone(self):
        V, r, B, h, k = symbols(r'V, r, B, h, k', positive = True)

        ps = SympyUnitSystem()
        r_val = random.randint(1, 10) 
        B_val = pi * r_val**2
        h_val = random.randint(1, 20)

        k_val = Rational(1, 3)
        V_val = k_val * B_val * h_val
        B_func = pi * r**2

        '''
        B_func = pi * r**2
        B: f"Area of base of cone (${latex(B_func)}$)",
        standard_eq = Eq(t_lhs, 
                         UnevaluatedExpr(t_const) * 
                         UnevaluatedExpr(t_rhs_standard)
                         )
            'standard_eq': standard_eq,
        '''
        
        label_dict = {
            V: f"Volume of cone",
            r: "Radius of base of cone",
            B: f"Area of base of cone (${latex(B_func)}$)",
            h: "Height of cone",
            k: "constant",
        }
        
        var_values = {
            V: V_val * ps.get_quantity(r'm**3'),
            r: r_val * ps.get_quantity(r'm'),
            B: pi * r**2,
            h: h_val * ps.get_quantity(r'm'),
            k: k_val,
        }

        lhs_symbol = V
        const_symbols = [k]
        rhs_symbols = [B, h]

        t_lhs = V
        t_const = k_val
        t_rhs = B * h
        t_rhs_standard = UnevaluatedExpr(B_func) * UnevaluatedExpr(h)
                                  
        eq = Eq(t_lhs, 
                UnevaluatedExpr(t_const) * UnevaluatedExpr(t_rhs))
                                  
        standard_eq = Eq(t_lhs, 
                         UnevaluatedExpr(t_const) * 
                         UnevaluatedExpr(t_rhs_standard)
                         )

        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': t_const,
            'eq': eq,
            'standard_eq': standard_eq,
            }

        return data
        pass



    def _get_electrostatic_force(self):
        epsilon = Symbol(u'\U000003F5_0')
        F, q1, q2, r = symbols('F, q_1, q_2, r')

        label_dict = {F: 'Force', 
                      q1: 'First Charge', 
                      q2: 'Second Charge', 
                      r: 'Distance between charges', 
                      epsilon: 'Vacuum Permitivity',
                      }          

        ps = SympyUnitSystem()
        epsilon_val = ps.convert_to_base_units('vacuum_permittivity')
        epsilon_val = epsilon_val.magnitude * ps.get_quantity(
            'coulombs**2 /(newton metre**2)')
        
        
        q1_val = random.randint(2, 20)
        q2_val = random.randint(2, 20)
        r_val = random.randint(2, 20)
        pi_val = sympy.N(pi)
        F_val = (q1_val * q2_val)/(4 * pi_val * epsilon_val.magnitude * r_val**2)
        
        var_values = {
            F: F_val * ps.get_quantity('newton'),
            q1: q1_val * ps.get_quantity('coulomb'),
            q2: q2_val * ps.get_quantity('coulomb'),
            r: r_val * ps.get_quantity('m'),
            epsilon: epsilon_val,
        }

        lhs_symbol = F
        const_symbols = [epsilon]
        rhs_symbols = [q1, q2,  r]

        t_const = 1 / (4 * pi * epsilon)
        
        eq = Eq(F, UnevaluatedExpr(t_const) * 
                       UnevaluatedExpr(q1 * q2 /r**2))
                                  
        data = {
            'prop_symbols': [lhs_symbol, const_symbols, rhs_symbols],
            'label_dict': label_dict,
            'var_values': var_values,
            'constant_value': t_const,
            'eq': eq,
            }

        return data
        pass


    pass
#class LawOfProportionHelper:
