"""
Copyright 2007, 2008, 2009, 2015 Free Software Foundation, Inc.
This file is part of GNU Radio

GNU Radio Companion is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

GNU Radio Companion is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
"""

import pygtk
pygtk.require('2.0')
import gtk

from . import Actions


# The list of actions for the toolbar.
TOOLBAR_LIST = (
    (Actions.FLOW_GRAPH_NEW, 'flow_graph_new'),
    (Actions.FLOW_GRAPH_OPEN, 'flow_graph_recent'),
    Actions.FLOW_GRAPH_SAVE,
    Actions.FLOW_GRAPH_CLOSE,
    None,
    Actions.FLOW_GRAPH_SCREEN_CAPTURE,
    None,
    Actions.BLOCK_CUT,
    Actions.BLOCK_COPY,
    Actions.BLOCK_PASTE,
    Actions.ELEMENT_DELETE,
    None,
    Actions.FLOW_GRAPH_UNDO,
    Actions.FLOW_GRAPH_REDO,
    None,
    Actions.ERRORS_WINDOW_DISPLAY,
    Actions.FLOW_GRAPH_GEN,
    Actions.FLOW_GRAPH_EXEC,
    Actions.FLOW_GRAPH_KILL,
    None,
    Actions.BLOCK_ROTATE_CCW,
    Actions.BLOCK_ROTATE_CW,
    None,
    Actions.BLOCK_ENABLE,
    Actions.BLOCK_DISABLE,
    Actions.BLOCK_BYPASS,
    Actions.TOGGLE_HIDE_DISABLED_BLOCKS,
    None,
    Actions.FIND_BLOCKS,
    Actions.RELOAD_BLOCKS,
    Actions.OPEN_HIER,
)

# The list of actions and categories for the menu bar.
MENU_BAR_LIST = (
    (gtk.Action('File', '_File', None, None), [
        'flow_graph_new',
        Actions.FLOW_GRAPH_OPEN,
        'flow_graph_recent',
        None,
        Actions.FLOW_GRAPH_SAVE,
        Actions.FLOW_GRAPH_SAVE_AS,
        None,
        Actions.FLOW_GRAPH_SCREEN_CAPTURE,
        None,
        Actions.FLOW_GRAPH_CLOSE,
        Actions.APPLICATION_QUIT,
    ]),
    (gtk.Action('Edit', '_Edit', None, None), [
        Actions.FLOW_GRAPH_UNDO,
        Actions.FLOW_GRAPH_REDO,
        None,
        Actions.BLOCK_CUT,
        Actions.BLOCK_COPY,
        Actions.BLOCK_PASTE,
        Actions.ELEMENT_DELETE,
        Actions.SELECT_ALL,
        None,
        Actions.BLOCK_ROTATE_CCW,
        Actions.BLOCK_ROTATE_CW,
        (gtk.Action('Align', '_Align', None, None), Actions.BLOCK_ALIGNMENTS),
        None,
        Actions.BLOCK_ENABLE,
        Actions.BLOCK_DISABLE,
        Actions.BLOCK_BYPASS,
        None,
        Actions.BLOCK_PARAM_MODIFY,
    ]),
    (gtk.Action('View', '_View', None, None), [
        Actions.TOGGLE_BLOCKS_WINDOW,
        None,
        Actions.TOGGLE_REPORTS_WINDOW,
        Actions.TOGGLE_SCROLL_LOCK,
        Actions.SAVE_REPORTS,
        Actions.CLEAR_REPORTS,
        None,
        Actions.TOGGLE_HIDE_VARIABLES,
        Actions.TOGGLE_HIDE_DISABLED_BLOCKS,
        Actions.TOGGLE_AUTO_HIDE_PORT_LABELS,
        Actions.TOGGLE_SNAP_TO_GRID,
        Actions.TOGGLE_SHOW_BLOCK_COMMENTS,
        None,
        Actions.TOGGLE_SHOW_CODE_PREVIEW_TAB,
        None,
        Actions.ERRORS_WINDOW_DISPLAY,
        Actions.FIND_BLOCKS,
    ]),
    (gtk.Action('Run', '_Run', None, None), [
        Actions.FLOW_GRAPH_GEN,
        Actions.FLOW_GRAPH_EXEC,
        Actions.FLOW_GRAPH_KILL,
    ]),
    (gtk.Action('Tools', '_Tools', None, None), [
        Actions.TOOLS_RUN_FDESIGN,
        Actions.FLOW_GRAPH_OPEN_QSS_THEME,
        None,
        Actions.TOGGLE_SHOW_FLOWGRAPH_COMPLEXITY,
        None,
        Actions.TOOLS_MORE_TO_COME,
    ]),
    (gtk.Action('Help', '_Help', None, None), [
        Actions.HELP_WINDOW_DISPLAY,
        Actions.TYPES_WINDOW_DISPLAY,
        Actions.XML_PARSER_ERRORS_DISPLAY,
        None,
        Actions.ABOUT_WINDOW_DISPLAY,
    ]),
)

# The list of actions for the context menu.
CONTEXT_MENU_LIST = [
    Actions.BLOCK_CUT,
    Actions.BLOCK_COPY,
    Actions.BLOCK_PASTE,
    Actions.ELEMENT_DELETE,
    None,
    Actions.BLOCK_ROTATE_CCW,
    Actions.BLOCK_ROTATE_CW,
    Actions.BLOCK_ENABLE,
    Actions.BLOCK_DISABLE,
    Actions.BLOCK_BYPASS,
    None,
    (gtk.Action('More', '_More', None, None), [
        Actions.BLOCK_CREATE_HIER,
        Actions.OPEN_HIER,
        None,
        Actions.BUSSIFY_SOURCES,
        Actions.BUSSIFY_SINKS,
    ]),
    Actions.BLOCK_PARAM_MODIFY
]


class SubMenuCreator(object):

    def __init__(self, generate_modes, action_handler_callback):
        self.generate_modes = generate_modes
        self.action_handler_callback = action_handler_callback
        self.submenus = []

    def create_submenu(self, action_tuple, item):
        func = getattr(self, '_fill_' + action_tuple[1] + "_submenu")
        self.submenus.append((action_tuple[0], func, item))
        self.refresh_submenus()

    def refresh_submenus(self):
        for action, func, item in self.submenus:
            try:
                item.set_property("menu", func(action))
            except TypeError:
                item.set_property("submenu", func(action))
            item.set_property('sensitive', True)

    def callback_adaptor(self, item, action_key):
        action, key = action_key
        self.action_handler_callback(action, key)

    def _fill_flow_graph_new_submenu(self, action):
        """Sub menu to create flow-graph with pre-set generate mode"""
        menu = gtk.Menu()
        for key, name, default in self.generate_modes:
            if default:
                item = Actions.FLOW_GRAPH_NEW.create_menu_item()
                item.set_label(name)
            else:
                item = gtk.MenuItem(name, use_underline=False)
                item.connect('activate', self.callback_adaptor, (action, key))
            menu.append(item)
        menu.show_all()
        return menu

    def _fill_flow_graph_recent_submenu(self, action):
        """menu showing recent flow-graphs"""
        import Preferences
        menu = gtk.Menu()
        recent_files = Preferences.get_recent_files()
        if len(recent_files) > 0:
            for i, file_name in enumerate(recent_files):
                item = gtk.MenuItem("%d. %s" % (i+1, file_name), use_underline=False)
                item.connect('activate', self.callback_adaptor,
                             (action, file_name))
                menu.append(item)
            menu.show_all()
            return menu
        return None


class Toolbar(gtk.Toolbar, SubMenuCreator):
    """The gtk toolbar with actions added from the toolbar list."""

    def __init__(self, generate_modes, action_handler_callback):
        """
        Parse the list of action names in the toolbar list.
        Look up the action for each name in the action list and add it to the
        toolbar.
        """
        gtk.Toolbar.__init__(self)
        self.set_style(gtk.TOOLBAR_ICONS)
        SubMenuCreator.__init__(self, generate_modes, action_handler_callback)

        for action in TOOLBAR_LIST:
            if isinstance(action, tuple) and isinstance(action[1], str):
                # create a button with a sub-menu
                action[0].set_tool_item_type(gtk.MenuToolButton)
                item = action[0].create_tool_item()
                self.create_submenu(action, item)
                self.refresh_submenus()

            elif action is None:
                item = gtk.SeparatorToolItem()

            else:
                action.set_tool_item_type(gtk.ToolButton)
                item = action.create_tool_item()
                # this reset of the tooltip property is required
                # (after creating the tool item) for the tooltip to show
                action.set_property('tooltip', action.get_property('tooltip'))
            self.add(item)


class MenuHelperMixin(object):
    """Mixin class to help build menus from the above action lists"""

    def _fill_menu(self, actions, menu=None):
        """Create a menu from list of actions"""
        menu = menu or gtk.Menu()
        for item in actions:
            if isinstance(item, tuple):
                menu_item = self._make_sub_menu(*item)
            elif isinstance(item, str):
                menu_item = getattr(self, 'create_' + item)()
            elif item is None:
                menu_item = gtk.SeparatorMenuItem()
            else:
                menu_item = item.create_menu_item()
            menu.append(menu_item)
        menu.show_all()
        return menu

    def _make_sub_menu(self, main, actions):
        """Create a submenu from a main action and a list of actions"""
        main = main.create_menu_item()
        main.set_submenu(self._fill_menu(actions))
        return main


class MenuBar(gtk.MenuBar, MenuHelperMixin, SubMenuCreator):
    """The gtk menu bar with actions added from the menu bar list."""

    def __init__(self, generate_modes, action_handler_callback):
        """
        Parse the list of submenus from the menubar list.
        For each submenu, get a list of action names.
        Look up the action for each name in the action list and add it to the
        submenu. Add the submenu to the menu bar.
        """
        gtk.MenuBar.__init__(self)
        SubMenuCreator.__init__(self, generate_modes, action_handler_callback)
        for main_action, actions in MENU_BAR_LIST:
            self.append(self._make_sub_menu(main_action, actions))

    def create_flow_graph_new(self):
        main = gtk.ImageMenuItem(gtk.STOCK_NEW)
        main.set_label(Actions.FLOW_GRAPH_NEW.get_label())
        func = self._fill_flow_graph_new_submenu
        self.submenus.append((Actions.FLOW_GRAPH_NEW, func, main))
        self.refresh_submenus()
        return main

    def create_flow_graph_recent(self):
        main = gtk.ImageMenuItem(gtk.STOCK_OPEN)
        main.set_label(Actions.FLOW_GRAPH_OPEN_RECENT.get_label())
        func = self._fill_flow_graph_recent_submenu
        self.submenus.append((Actions.FLOW_GRAPH_OPEN, func, main))
        self.refresh_submenus()
        if main.get_submenu() is None:
            main.set_property('sensitive', False)
        return main


class ContextMenu(gtk.Menu, MenuHelperMixin):
    """The gtk menu with actions added from the context menu list."""

    def __init__(self):
        gtk.Menu.__init__(self)
        self._fill_menu(CONTEXT_MENU_LIST, self)