# coding=utf-8
import traceback
import importlib
from qtpy import QtGui, QtWidgets, QtCore
import inspect


############################
# a typical tool-packages __init__.py file might look like that:
#from ToolMod1 import ToolCls1
#from ToolMod2 import ToolCls2
#
# position='top',
# show=True, # OR {"simple":True,"advanced":False}
# secondRow=False,#show tools normally in first toolbar row
# tools=set(ToolCls1, Toolcls2 ...) #to define tool position in toolbar
# color=None OR 'red' ...
############################

# TO_QT_POSITION = {'top':QtCore.Qt.TopToolBarArea,
#                   'left':QtCore.Qt.LeftToolBarArea,
#                   'right':QtCore.Qt.RightToolBarArea,
#                   'bottom':QtCore.Qt.BottomToolBarArea}


def build(widget):
    '''
    create and return a list of toolbars for the given [displayWidget]
    '''
    # get name of the corresponding tools package:
    pkg_name = widget.__class__.__module__.split('.')[:-1]
    pkg_name.append('tools')
    pkg_name = '.'.join(pkg_name)

    pkg = importlib.import_module(pkg_name)
    bars = inspect.getmembers(pkg, inspect.ismodule)

    l, l2 = [], []
    for (bar_name, bar_mod) in bars:
        tools = getattr(bar_mod, 'tools', None)
        if tools is None:
            tools = [
                t[1] for t in inspect.getmembers(
                    bar_mod, inspect.isclass)]

        if len(tools):
            # EVERY FOLDER CONTAINING TOOLS BECOMES A TOOLBAR:
            toolbar = _ToolBar(bar_name, widget, bar_mod, tools)

            if getattr(bar_mod, 'secondRow', False):
                # put all toolbars ment to be shown in a second row in other
                # list:
                l2.append(toolbar)
            else:
                l.append(toolbar)

    # create the second row:
    if l2:
        l2[0].hasBreak = True
        l.extend(l2)

    return l


class _ToolBar(QtWidgets.QToolBar):
    '''
    A ToolBar remembering it's position
    and whether it's selected.
    This allows to use one the same set of toolBars
    for different display widgets of the same kind
    '''

    def __init__(self, name, widget, pkg, toolClasses):
        QtWidgets.QToolBar.__init__(self, name)

        self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self._openContextMenu)

        PX_FACTOR = QtWidgets.QApplication.instance().PX_FACTOR
        # make ToolBar smaller:
        self.setIconSize(QtCore.QSize(PX_FACTOR * 16, PX_FACTOR * 16))
        self.layout().setContentsMargins(0, 0, 0, 0)
        self.setAllowedAreas(QtCore.Qt.TopToolBarArea)

        # measure toolbar width in order to find best place when added

        # whether position of toolbar should be
        # found depending on available space:
#         self.needPositioning = False

        name[0].islower()
        f = name[0]
        if f.islower():
            name = f.upper() + name[1:]
        self.name = name
        # show name:
#         self._nameLab = QtWidgets.QLabel(self.name + " ")
#         self.addWidget(self._nameLab)  # .setEnabled(False)
        # TODO": measure handle width!
        self.width = self._nameLab().sizeHint().width() + 6 * \
            PX_FACTOR  # 6=handle width

        self.widget = widget
        self.toolClasses = toolClasses
        self._toolsCreated = False
        self._firstTime = True

        # there is a central setup for the visibility of all
        # toolbars that have the same display widget:
        show = getattr(pkg, 'show', True)
        if isinstance(show, dict):
            # whether to show/hide a toolbar depends on the chosen profile:
            session = QtWidgets.QApplication.instance().session
            profile = session.opts.get('profile', None)
            show = show.get(profile, False)
        if self.widget.__class__.selectedToolbars.get(name, None) is None:
            self.widget.__class__.selectedToolbars[name] = [show,
                                                            #                             QtCore.Qt.TopToolBarArea,
                                                            #                             TO_QT_POSITION[getattr(pkg, 'position','top')],
                                                            False]  # ->hasBreak

#         #add logo to toolbar:
#         icon  = getattr(pkg, 'icon', None)
#         if icon:
#             #icon can ge given as direct path
#             if not os.path.exists(icon):
#                 #otherwise it is assumed that
#                 #the icon is to be found in the icon directory:
#                 icon = ICONFOLDER.join(icon)
#             s = ToolBarIcon(self, icon)

            tip = getattr(pkg, '__doc__', None)
#             ttname = name
            if tip:
                #                 ttname += '\n\t%s' % tip
                #                 self.setToolTip(ttname)
                self.setToolTip(tip)

        # BACKGROUND COLOR:
        c = getattr(pkg, 'color', None)
        if c is not None:
            # create a semi-transparent colour from
            # normal background color (grey)
            # and given color:
            a = 0.9
            b = 1 - a
            p = self.palette()
            bg = p.color(self.backgroundRole())
            c = QtGui.QColor(c)
            bg.setRed(a * bg.red() + b * c.red())
            bg.setGreen(a * bg.green() + b * c.green())
            bg.setBlue(a * bg.blue() + b * c.blue())
            self.setBackgroundRole(QtGui.QPalette.Window)
            p.setColor(self.backgroundRole(), bg)
            self.setPalette(p)
            self.setAutoFillBackground(True)

        self.actionSelect = a = QtWidgets.QAction(name, self)
        s = 'contains...'
        for cls in self.toolClasses:
            s += '\n     %s' % cls.__name__
        a.setToolTip(s)
        a.setCheckable(True)
        a.setChecked(show)
        a.triggered.connect(self.setSelected)

#         if self.isSelected:
#             self.addTools()


#     @property
#     def position(self):
#         p = self.widget.__class__.selectedToolbars[self.name][1]
#         if p == QtCore.Qt.NoToolBarArea:
#             return QtCore.Qt.LeftToolBarArea
#         return p
#     @position.setter
#     def position(self, val):
#         if val == QtCore.Qt.NoToolBarArea:
#             val = QtCore.Qt.TopToolBarArea
#         self.widget.__class__.selectedToolbars[self.name][1] = val

    @property
    def hasBreak(self):
        return self.widget.__class__.selectedToolbars[self.name][1]

    @hasBreak.setter
    def hasBreak(self, val):
        self.widget.__class__.selectedToolbars[self.name][1] = val

    def _openContextMenu(self, pos):
        # show toolbar name and action[remove] on right click
        m = QtWidgets.QMenu()

        ######
        # title:
#         a = QtWidgets.QAction('Toolbar:   %s' % self.name, self)
#         # removed in Qt5:
# #         a.setSoftKeyRole(QtWidgets.QAction.NoSoftKey)
#         f = a.font()
#         f.setBold(True)
#         a.setFont(f)
#         m.addAction(a)
#         m.addSeparator()
        ######

        m.addAction("Remove").triggered.connect(self.actionSelect.trigger)
        m.exec_(self.mapToGlobal(pos))

    def addTools(self):
        PX_FACTOR = QtWidgets.QApplication.instance().PX_FACTOR
        if not self._toolsCreated:
            # TO ALL TOOLS IN PACKAGE:
            for cls in self.toolClasses:
                try:
                    # CREATE TOOL
                    tool = cls(self.widget.display)
                    self.widget.tools[cls.__name__] = tool
                    # ADD TOOL
                    self.addWidget(tool)
                    if self._firstTime:
                        self.width += tool.sizeHint().width()
#                         if tool.popupMode() == QtWidgets.QToolButton.MenuButtonPopup:
#                             # [px] - tool is wider if drop down button is shown
#                             self.width += 39 * PX_FACTOR
#                         else:
#                             self.width += 27 * PX_FACTOR  # px
                except Exception:
                    print("ERROR loading toolbutton: ", traceback.print_exc())
            self._toolsCreated = True
            self._firstTime = False


#     def width(self):
#         h = 4 #width of a toolbar handle
#         t = 35 #tool width - assume every 2nd has drop down menu
#         w = 0
#         for
#         h+len(bar.toolClasses)*t

    def removeTools(self):
        # REMOVE TOOL TO FREE SOME MEMORY
        # TODO: REMOVING A TOOL DOESN'T FREE MEMORY AT THE MOMENT
        #      WHY? gc.collect(), tool.close(), tool.deletLater()...
        #      nothing works!

        # TODO: also remove this toolbar in other displays
        for cls in self.toolClasses:
            try:
                tool = self.widget.tools.pop(cls.__name__)
                del tool
            except KeyError:
                pass  # tool no created yet
        for toolAction in self.findChildren(QtWidgets.QAction):
            self.removeAction(toolAction)
            del toolAction

        self._toolsCreated = False
# self.width = self._initWidth #9 *
# QtWidgets.QApplication.instance().PX_FACTOR

    def _nameLab(self):
        lab = QtWidgets.QLabel(self.name + " ")
        # gray txt:
        p = lab.palette()
        p.setColor(lab.foregroundRole(), QtCore.Qt.darkGray)
        lab.setPalette(p)
        return lab

    def show(self):
        if not self._toolsCreated:
            self.addWidget(self._nameLab())

        # ensure that all tools are loaded:
        self.addTools()
        QtWidgets.QToolBar.show(self)
        # self._nameLab.show()
#         print(self._nameLab.isVisible())

#     def hide(self):
#         if not self.isSelected():
#             self.removeTools()
#         QtWidgets.QToolBar.hide(self)

    def toggleViewAction(self):
        '''
        return an action to show/hide the toolbar
        '''
        self.actionSelect.setChecked(self.isVisible())
        return self.actionSelect

    def setSelected(self, select):
        '''
        store whether is selected to restore when toolbar is changed
        '''
#         if self.widget.__class__.selectedToolbars[self.name][0] == select:
#             return
        if self.isSelected() == select:
            return
        self.widget.__class__.selectedToolbars[self.name][0] = select
        if select:
            # self.addTools()
            #             if not self._toolsCreated:
            #             self.needPositioning = True
            self.show()
            self.widget.display.workspace.addNewToolbar(self)
#             self.show()

        else:
            #             self.hide()

            self.widget.display.workspace.gui.removeToolBar(self)
            self.removeTools()

    def isSelected(self):
        return self.widget.__class__.selectedToolbars[self.name][0]
