from . import renderers, datasources
from .elements import PlotList,Plot
from .renderers import BaseRenderer
from .datasources import BaseDataSource
import dill, inspect, logging
import os
class BelugaPlot:
    """
    Manages the plotting framework
    """
    def __init__(self, filename = None, datasource='dill', renderer = 'matplotlib', default_step = -1, default_sol = -1):
        """
        Initializes plotting framework with given data file
        """
        self._plots = []
        self._figures = []
        self._plotconfig = {}
        self.global_settings = {}
        self.filename = filename
        self.default_step_idx = default_step
        self.default_sol_idx = default_sol

        # Load datasource by filename unless one is specified directly
        if filename is not None:
            fname, file_ext = os.path.splitext(filename)
        else:
            file_ext = None

        # TODO: Get default datasource information from global configuration
        if isinstance(datasource, BaseDataSource):
            # Use custom renderer object
            self.datasource = datasource
        else:
            # Load renderer from the list of existing classes
            self.datasource = None
            for name, obj in inspect.getmembers(datasources):
                if inspect.isclass(obj) and issubclass(obj, BaseDataSource):
                    if (isinstance(datasource, str) and name.lower() == datasource.lower()) \
                        or file_ext in obj.valid_exts:
                        # Renderer initialized with its default settings
                        self.datasource = obj(filename)
            if self.datasource is None:
                raise ValueError('Datasource "'+datasource+'" not found')

        # TODO: Get default renderer information from global configuration
        if isinstance(renderer, BaseRenderer):
            # Use custom renderer object
            self.renderer = renderer
        else:
            # Load renderer from the list of existing classes
            self.renderer = None
            for name, obj in inspect.getmembers(renderers):
                if inspect.isclass(obj) and issubclass(obj, BaseRenderer):
                    if name.lower() == renderer.lower():
                        # Renderer initialized with its default settings
                        self.renderer = obj()
            if self.renderer is None:
                raise ValueError('Renderer "'+renderer+'" not found')

    def add_plot(self, step = None, sol = None, datasource = None, colormap=None, mesh_size=None):
        """
        Adds a new plot
            (alias for add_plot() in PlotList)
        """
        if step is None:
            step = self.default_step_idx
        if sol is None:
            sol = self.default_sol_idx
        if datasource is None:
            datasource = self.datasource

        plot = Plot(step, sol, mesh_size, datasource, colormap)
        self._plots.append(plot)
        return plot

    def render(self,show=True):
        for plot in self._plots:
            plot.preprocess()
            fig = self.renderer.create_figure()
            self.renderer.render_plot(fig, plot)
            self._figures.append(fig)
            for fn in plot.postprocess_list:
                fn(self.renderer, fig, plot)
        if show:
            self.show()

    def show(self):
        self.renderer.show_all()

    def plotconfig(varname,value=None):
        """
        Adds/updates settings affecting all plots
        """
        if isinstance(varname, dict):
            self._plotconfig.update(varname)
        else:
            self._plotconfig[varname] = value
        return self
