# Copyright 2012 Nebula, Inc.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

from collections import OrderedDict
import logging
import operator
import sys

import six

from django.conf import settings
from django.template.loader import render_to_string
from django.template import TemplateSyntaxError
from django.utils import module_loading

from horizon import exceptions
from horizon.utils import html

LOG = logging.getLogger(__name__)

SEPARATOR = "__"
CSS_TAB_GROUP_CLASSES = ["nav", "nav-tabs", "ajax-tabs"]
CSS_ACTIVE_TAB_CLASSES = ["active"]
CSS_DISABLED_TAB_CLASSES = ["disabled"]


class TabGroup(html.HTMLElement):
    """A container class which knows how to manage and render Tab objects.

    .. attribute:: slug

        The URL slug and pseudo-unique identifier for this tab group.

    .. attribute:: tabs

       A list of :class:`.Tab` classes. Tabs specified here are displayed
       in the order of the list.

    .. attribute:: template_name

        The name of the template which will be used to render this tab group.
        Default: ``"horizon/common/_tab_group.html"``

    .. attribute:: sticky

        Boolean to control whether the active tab state should be stored
        across requests for a given user. (State storage is all done
        client-side.)

    .. attribute:: show_single_tab

        Boolean to control whether the tab bar is shown when the tab group
        has only one tab. Default: ``False``

    .. attribute:: param_name

        The name of the GET request parameter which will be used when
        requesting specific tab data. Default: ``tab``.

    .. attribute:: classes

        A list of CSS classes which should be displayed on this tab group.

    .. attribute:: attrs

        A dictionary of HTML attributes which should be rendered into the
        markup for this tab group.

    .. attribute:: selected

        Read-only property which is set to the instance of the
        currently-selected tab if there is one, otherwise ``None``.

    .. attribute:: active

        Read-only property which is set to the value of the current active tab.
        This may not be the same as the value of ``selected`` if no
        specific tab was requested via the ``GET`` parameter.
    """
    slug = None
    template_name = "horizon/common/_tab_group.html"
    param_name = 'tab'
    sticky = False
    show_single_tab = False
    _selected = None
    _active = None

    @property
    def selected(self):
        return self._selected

    @property
    def active(self):
        return self._active

    def __init__(self, request, **kwargs):
        super(TabGroup, self).__init__()
        if not hasattr(self, "tabs"):
            raise NotImplementedError('%s must declare a "tabs" attribute.'
                                      % self.__class__)
        if not self.slug:
            raise NotImplementedError('%s must declare a "slug" attribute.'
                                      % self.__class__)
        self.request = request
        self.kwargs = kwargs
        self._data = None
        self._tabs = self._load_tabs(request)
        if self.sticky:
            self.attrs['data-sticky-tabs'] = 'sticky'
        if not self._set_active_tab():
            self.tabs_not_available()

    def _load_tabs(self, request):
        tabs = tuple(self.tabs)
        tabs += self._load_tabs_from_config()
        return OrderedDict([(tab.slug, tab(self, request))
                            for tab in tabs])

    def _load_tabs_from_config(self):
        my_name = '.'.join([self.__class__.__module__,
                            self.__class__.__name__])
        horizon_config = settings.HORIZON_CONFIG.get('extra_tabs', {})
        tabs_config = [self._load_tab_config(tab_config, my_name)
                       for tab_config in horizon_config.get(my_name, [])]
        tabs_config = [t for t in tabs_config if t]
        tabs_config.sort(key=operator.itemgetter(0))
        LOG.debug('Loaded extra tabs for %s: %s',