'''
Created on 16-Apr-2021

@author: bthakur
'''
import os 
import numpy as np
import random
import inspect
import traceback

from xv.km.ui import SvgHelper         
        
from ..helper import BaseHelper
from xv.km.managers import BaseManager
from xv.km.kelements import KProblemTemplate

        
class GraphManager(BaseManager):
    '''
    Plotting Graphs 
    Example:
        ke = GraphManager()
        ke
        
        ke.printProblemTypes()
        
        ke.getRandomProblem()
        ke.getRandomProblem(problem_type = 0)
        ke.getRandomProblem(problem_type = 1)
        ...
        
        ke.printProblem()
        ke.printAnswer()
        ke.printSolution()
        
        ke.printLength(2, 5, 3, -1)
        ke.printMovementLengths()        
        
        
    '''    
    def __new__(cls, *args, **kwargs):
        instance = super(GraphManager, cls).__new__(cls, *args, **kwargs)
        for base_class in GraphManager.__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_draw_graph',
                '_problem_relation_graph',
                '_problem_counting_system',
                '_problem_make_coffee',
                '_problem_food_chain',
                '_problem_organize_couples',
                '_problem_tournament_draw',
             ])
        pass

    def _problem_draw_graph(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = '_draw_graph'
        
        statement = f"""Draw a graph using the terms from the video:"""
        expr_s = "<a href = 'https://www.youtube.com/watch?v=8IlzKri08kk'>Introduction to Cells: The Grand Cell Tour</a>"
        problemTemplate.add_problem(statement)
        problemTemplate.add_problem(expr_s.strip(), 'text/html')

        custom_code = f"""
            import networkx as nx
            
            g = nx.Graph()
            g.add_edge('cell', 'ameoba')
            g.add_edge('cell', 'animal cells')
            g.add_edge('animal cells', 'multicellular')
            g.add_edge('ameoba', 'unicellular')
            g.add_edge('cell', 'genetic information')
            g.add_edge('genetic information', 'DNA')
            g.add_edge('cell', 'function')
            g.add_edge('function', 'organelles')
            g.add_edge('cell', 'eukaryotic')
            g.add_edge('cell', 'prokaryotic')
            g.add_edge('prokaryotic', 'cell membrane')
            g.add_edge('prokaryotic', 'bacteria')
            
            fig = plt.figure(num=None, 
                   figsize=(20, 20), 
                   dpi=80, 
                   facecolor='c', 
                   edgecolor='k')
            
            nx.draw_networkx(g, 
                             node_size=700, 
                             font_size=10, 
                             node_color='yellow')
            
            plt.gca().margins(0.3) 
            #plt.savefig("cells.png", format="PNG")

        """
                
        svgHelper = SvgHelper()
        svg_str, plot_code = svgHelper.get_svg_data(custom_code, 
                                                    strip_lines = True)


        problemTemplate.add_solution(plot_code)
        problemTemplate.add_solution(svg_str, 'text/svg')
        problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate
        pass
    
    def _problem_relation_graph(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = '_draw_graph'
        
        statement = f"""
        Draw a graph of your relation and friends
        """
        problemTemplate.add_problem(statement.strip(), 'text/html')

        custom_code = f"""
            import matplotlib.pyplot as plt
            import networkx as nx
            
            #G = nx.Graph()
            G = nx.DiGraph()
            
            nodes = ['Fam', 'GF', 'GM', 'F', 'M', 'S', 'D', 'C']
            labels = {{node:node for node in nodes}}
            labels['Fam'] = 'Family'
            labels['GF'] = 'Grandfather'
            labels['GM'] = 'Grandmother'
            labels['F'] = 'Father'
            labels['M'] = 'Mother'
            labels['S'] = 'Son'
            labels['D'] = 'Daughter'
            labels['C'] = 'Cousin'
            
            G.add_nodes_from(nodes)
            
            edges = [['Fam','F'],
                     ['Fam','M'],
                     ['F','GF'],
                     ['F','GM'],
                     ['M','S'],
                     ['M','D'],
                     ['F','C'],
                    ]
            
            edge_labels = {{('F','GF'):'Son Father',
                           ('F','GM'):'Son Mother-in-law',
                          }}
            
            G.add_edges_from(edges)
            pos = nx.spring_layout(G)
            
            #plt.figure()   
            fig = plt.figure(num=None,
            figsize=(10, 6))
            
            nx.draw(G,
                    pos,
                    edge_color='black',
                    width=1,
                    linewidths=1,
                    node_size=500,
                    node_color='pink',
                    alpha=0.9,
                    labels = labels, 
                   )
            
            
            nx.draw_networkx_edge_labels(G,
                                         pos,
                                         edge_labels = edge_labels,
                                         font_color = 'red'
                                        )
            plt.axis('off')
            
            #plt.gca().margins(0.3)
            #plt.savefig("cells.png", format="PNG")
            
            #plt.show()

        """
                
        svgHelper = SvgHelper()
        svg_str, plot_code = svgHelper.get_svg_data(custom_code, 
                                                    strip_lines = True)


        problemTemplate.add_solution(plot_code)
        problemTemplate.add_solution(svg_str, 'text/svg')
        problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate
        pass
    
    def _problem_counting_system(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = '_draw_graph'
        
        statement = f"""
        Draw a graph of number system
        """
        problemTemplate.add_problem(statement.strip(), 'text/html')

        custom_code = f"""
            import networkx as nx
            
            g = nx.Graph()
            g.add_edge('one', 'thousand = $10^3$')
            g.add_edge('thousand = $10^3$', 'million = $10^6$')

            g.add_edge('one', 'milli = $10^{{-3}}$')
            g.add_edge('milli = $10^{{-3}}$', 'million = $10^{{-6}}$')
            
            fig = plt.figure(num=None, 
                   figsize=(20, 20), 
                   dpi=80, 
                   facecolor='c', 
                   edgecolor='k')
            
            nx.draw_networkx(g, 
                             node_size=700, 
                             font_size=20, 
                             node_color='yellow')
            
            plt.gca().margins(0.3) 
            #plt.savefig("cells.png", format="PNG")

        """
                
        svgHelper = SvgHelper()
        svg_str, plot_code = svgHelper.get_svg_data(custom_code, 
                                                    strip_lines = True)


        problemTemplate.add_solution(plot_code)
        problemTemplate.add_solution(svg_str, 'text/svg')
        problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate
        pass
    
    def _problem_make_coffee(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = '_draw_graph'
        
        statement = f"""
        Draw a graph to make coffee
        """
        problemTemplate.add_problem(statement.strip(), 'text/html')

        custom_code = f"""
            import networkx as nx
            
            g = nx.Graph()
            g.add_edge('coffee', 'coffee powder')
            g.add_edge('coffee powder', 'mix with water')
            
            fig = plt.figure(num=None, 
                   figsize=(20, 20), 
                   dpi=80, 
                   facecolor='c', 
                   edgecolor='k')
            
            nx.draw_networkx(g, 
                             node_size=700, 
                             font_size=20, 
                             node_color='yellow')
            
            plt.gca().margins(0.3) 
            #plt.savefig("cells.png", format="PNG")

        """
                
        svgHelper = SvgHelper()
        svg_str, plot_code = svgHelper.get_svg_data(custom_code, 
                                                    strip_lines = True)


        problemTemplate.add_solution(plot_code)
        problemTemplate.add_solution(svg_str, 'text/svg')
        problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate
        pass
    
    def _problem_food_chain(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = '_draw_graph'
        
        statement = f"""
        Draw a food chain
        """
        problemTemplate.add_problem(statement.strip(), 'text/html')

        custom_code = f"""
            import networkx as nx
            
            g = nx.Graph()
            g.add_edge('sunlight', 'plant')
            g.add_edge('water', 'plant')
            g.add_edge('air nutrient', 'plant')
            g.add_edge('air carbon dioxide', 'plant')
            g.add_edge('soil nutrient', 'plant')
            g.add_edge('plant', 'food')
            
            fig = plt.figure(num=None, 
                   figsize=(20, 20), 
                   dpi=80, 
                   facecolor='c', 
                   edgecolor='k')
            
            nx.draw_networkx(g, 
                             node_size=700, 
                             font_size=20, 
                             node_color='yellow')
            
            plt.gca().margins(0.3) 
            #plt.savefig("cells.png", format="PNG")

        """
                
        svgHelper = SvgHelper()
        svg_str, plot_code = svgHelper.get_svg_data(custom_code, 
                                                    strip_lines = True)


        problemTemplate.add_solution(plot_code)
        problemTemplate.add_solution(svg_str, 'text/svg')
        problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate
        pass

    def _problem_organize_couples(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = '_draw_graph'
        
        statement = f"""
        Draw a graph of number system
        """
        problemTemplate.add_problem(statement.strip(), 'text/html')

        custom_code = f"""
            import networkx as nx
            
            g = nx.Graph()
            g.add_edge('one', 'thousand = $10^3$')
            g.add_edge('thousand = $10^3$', 'million = $10^6$')

            g.add_edge('one', 'milli = $10^{{-3}}$')
            g.add_edge('milli = $10^{{-3}}$', 'million = $10^{{-6}}$')
            
            fig = plt.figure(num=None, 
                   figsize=(20, 20), 
                   dpi=80, 
                   facecolor='c', 
                   edgecolor='k')
            
            nx.draw_networkx(g, 
                             node_size=700, 
                             font_size=20, 
                             node_color='yellow')
            
            plt.gca().margins(0.3) 
            #plt.savefig("cells.png", format="PNG")

        """
                
        svgHelper = SvgHelper()
        svg_str, plot_code = svgHelper.get_svg_data(custom_code, 
                                                    strip_lines = True)


        problemTemplate.add_solution(plot_code)
        problemTemplate.add_solution(svg_str, 'text/svg')
        problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate
        pass


    def _problem_tournament_draw(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = '_draw_graph'
        
        n = 2 ** random.randint(3, 7)
        
        statement = f"""
        Draw a tournament draw of {n} players
        """
        problemTemplate.add_problem(statement.strip(), 'text/html')

        custom_code = f"""
import networkx as nx

def _get_label(edge_level, node_idx):
    label = str(edge_level) + "_{{" + str(node_idx) + "}}"
    return f"${{label}}$"
    pass

G = nx.Graph()

n = 16
nodes = []
edges = []
edge_level = 0

while n > 0:
    
    for i in range(0, n, 2):
        nd1 = _get_label(edge_level, i)
        if n == 1:
            nd2 = None
        else:
            nd2 = _get_label(edge_level, i+1)
            
        G.add_node(nd1)
        if not nd2 is None:
            G.add_node(nd2)
        
        if edge_level > 0:
            pre_node1_1 = _get_label(edge_level-1, i*2 )
            pre_node1_2 = _get_label(edge_level-1, i*2 + 1 )

            G.add_edge(pre_node1_1, nd1)
            G.add_edge(pre_node1_2, nd1)

            if not nd2 is None:
                pre_node2_1 = _get_label(edge_level-1, (i+1)*2 )
                pre_node2_2 = _get_label(edge_level-1, (i+1)*2 + 1 )
                
                G.add_edge(pre_node2_1, nd2)
                G.add_edge(pre_node2_2, nd2)
                pass
            
            pass 
        #if edge_level > 0
        
        pass 
    #for i in range(0, n, 2):
    
    n = n // 2
    edge_level = edge_level + 1

    if edge_level >6:
        break
    pass

labels = {{node:node for node in G.nodes()}}
G.add_nodes_from(nodes)

G.add_edges_from(edges)
pos = nx.spring_layout(G)

fig = plt.figure(num=None, figsize=(10, 6))

nx.draw(G,
        pos,
        edge_color='black',
        width=1,
        linewidths=1,
        node_size=1500,
        node_color='pink',
        alpha=0.9,
        labels = labels, 
        font_size = 20
       )

plt.axis('off')

#plt.gca().margins(0.3)
#plt.savefig("cells.png", format="PNG")


        """
                
        svgHelper = SvgHelper()
        svg_str, plot_code = svgHelper.get_svg_data(custom_code, 
                                                    strip_lines = False)


        problemTemplate.add_solution(plot_code)
        problemTemplate.add_solution(svg_str, 'text/svg')
        problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate
        pass
    
