from __future__ import absolute_import, unicode_literals

import warnings

from django.template.loader import render_to_string

from debug_toolbar import settings as dt_settings
from debug_toolbar.utils import get_name_from_obj


class Panel(object):
    """
    Base class for panels.
    """
    def __init__(self, toolbar):
        self.toolbar = toolbar

    # Private panel properties

    @property
    def panel_id(self):
        return self.__class__.__name__

    @property
    def enabled(self):
        # Check to see if settings has a default value for it
        if get_name_from_obj(self) in dt_settings.CONFIG['DISABLE_PANELS']:
            default = 'off'
        else:
            default = 'on'
        # The user's cookies should override the default value
        return self.toolbar.request.COOKIES.get('djdt' + self.panel_id, default) == 'on'

    # Titles and content

    @property
    def nav_title(self):
        """
        Title shown in the side bar. Defaults to :attr:`title`.
        """
        return self.title

    @property
    def nav_subtitle(self):
        """
        Subtitle shown in the side bar. Defaults to the empty string.
        """
        return ''

    @property
    def has_content(self):
        """
        ``True`` if the panel can be displayed in full screen, ``False`` if
        it's only shown in the side bar. Defaults to ``True``.
        """
        return True

    @property
    def title(self):
        """
        Title shown in the panel when it's displayed in full screen.

        Mandatory, unless the panel sets :attr:`has_content` to ``False``.
        """
        raise NotImplementedError

    @property
    def template(self):
        """
        Template used to render :attr:`content`.

        Mandatory, unless the panel sets :attr:`has_content` to ``False`` or
        overrides `attr`:content`.
        """
        raise NotImplementedError

    @property
    def content(self):
        """
        Content of the panel when it's displayed in full screen.

        By default this renders the template defined by :attr:`template`.
        Statistics stored with :meth:`record_stats` are available in the
        template's context.
        """
        if self.has_content:
            return render_to_string(self.template, self.get_stats())

    # URLs for panel-specific views

    @classmethod
    def get_urls(cls):
        """
        Return URLpatterns, if the panel has its own views.
        """
        return []

    # Enable and disable (expensive) instrumentation, must be idempotent

    def enable_instrumentation(self):
        """
        Enable instrumentation to gather data for this panel.

        This usually means monkey-patching (!) or registering signal
        receivers. Any instrumentation with a non-negligible effect on
        performance should be installed by this method rather than at import
        time.

        Unless the toolbar or this panel is disabled, this method will be
        called early in :class:`DebugToolbarMiddleware.process_request`. It
        should be idempotent.
        """

    def disable_instrumentation(self):
        """
        Disable instrumentation to gather data for this panel.

        This is the opposite of :meth:`enable_instrumentation`.

        Unless the toolbar or this panel is disabled, this method will be
        called late in :class:`DebugToolbarMiddleware.process_response`. It
        should be idempotent.
        """

    # Store and retrieve stats (shared between panels for no good reason)

    def record_stats(self, stats):
        """
        Store data gathered by the panel. ``stats`` is a :class:`dict`.

        Each call to ``record_stats`` updates the statistics dictionary.
        """
        self.toolbar.stats.setdefault(self.panel_id, {}).update(stats)

    def get_stats(self):
        """
        Access data stored by the panel. Returns a :class:`dict`.
        """
        return self.toolbar.stats.get(self.panel_id, {})

    # Standard middleware methods

    def process_request(self, request):
        """
        Like process_request in Django's middleware.

        Write panel logic related to the request there. Save data with
        :meth:`record_stats`.
        """

    def process_view(self, request, view_func, view_args, view_kwargs):
        """
        Like process_view in Django's middleware.

        Write panel logic related to the view there. Save data with
        :meth:`record_stats`.
        """

    def process_response(self, request, response):
        """
        Like process_response in Django's middleware.

        Write panel logic related to the response there. Post-process data
        gathered while the view executed. Save data with :meth:`record_stats`.
        """


# Backward-compatibility for 1.0, remove in 2.0.
class DebugPanel(Panel):

    def __init__(self, *args, **kwargs):
        warnings.warn("DebugPanel was renamed to Panel.", DeprecationWarning)
        super(DebugPanel, self).__init__(*args, **kwargs)
