"""
A generic tab that displays a serie of items in a scrollable, searchable,
sortable list.  It should be inherited, to actually provide methods that
insert items in the list, and that lets the user interact with them.
"""

import logging
log = logging.getLogger(__name__)

import curses
import collections

import windows
from common import safeJID
from decorators import refresh_wrapper

from . import Tab


class ListTab(Tab):
    plugin_commands = {}
    plugin_keys = {}

    def __init__(self, name, help_message, header_text, cols):
        """Parameters:
        name: The name of the tab
        help_message: The default help message displayed instead of the
        input
        header_text: The text displayed on the header line, at the top of
        the tab
        cols: a tuple of 2-tuples. e.g. (('column1_name', number),
                                         ('column2_name', number))
        """
        Tab.__init__(self)
        self.state = 'normal'
        self.name = name
        columns = collections.OrderedDict()
        for col, num in cols:
            columns[col] = num
        self.list_header = windows.ColumnHeaderWin(list(columns))
        self.listview = windows.ListWin(columns)
        self.info_header = windows.MucListInfoWin(header_text)
        self.default_help_message = windows.HelpText(help_message)
        self.input = self.default_help_message
        self.key_func["KEY_DOWN"] = self.move_cursor_down
        self.key_func["KEY_UP"] = self.move_cursor_up
        self.key_func['^I'] = self.completion
        self.key_func["/"] = self.on_slash
        self.key_func['KEY_LEFT'] = self.list_header.sel_column_left
        self.key_func['KEY_RIGHT'] = self.list_header.sel_column_right
        self.key_func[' '] = self.sort_by
        self.register_command('close', self.close,
                shortdesc='Close this tab.')
        self.resize()
        self.update_keys()
        self.update_commands()

    def get_columns_sizes(self):
        """
        Must be implemented in subclasses. Must return a dict like this:
        {'column1_name': size1,
         'column2_name': size2}
        Where the size are calculated based on the size of the tab etc
        """
        raise NotImplementedError


    def refresh(self):
        if self.need_resize:
            self.resize()
        log.debug('  TAB   Refresh: %s', self.__class__.__name__)
        if self.size.tab_degrade_y:
            display_info_win = False
        else:
            display_info_win = True

        self.info_header.refresh(window=self.listview)
        if display_info_win:
            self.info_win.refresh()
        self.refresh_tab_win()
        self.list_header.refresh()
        self.listview.refresh()
        self.input.refresh()

    def resize(self):
        if self.size.tab_degrade_y:
            info_win_height = 0
            tab_win_height = 0
        else:
            info_win_height = self.core.information_win_size
            tab_win_height = Tab.tab_win_height()

        self.info_header.resize(1, self.width,
                                self.height - 2 - info_win_height
                                    - tab_win_height,
                                0)
        column_size = self.get_columns_sizes()
        self.list_header.resize_columns(column_size)
        self.list_header.resize(1, self.width, 0, 0)
        self.listview.resize_columns(column_size)
        self.listview.resize(self.height - 3 - info_win_height - tab_win_height,
                             self.width, 1, 0)
        self.input.resize(1, self.width, self.height-1, 0)

    def on_slash(self):
        """
        '/' is pressed, activate the input
        """
        curses.curs_set(1)
        self.input = windows.CommandInput("", self.reset_help_message, self.execute_slash_command)
        self.input.resize(1, self.width, self.height-1, 0)
        self.input.do_command("/") # we add the slash

    def close(self, arg=None):
        self.input.on_delete()
        self.core.close_tab(self)

    def set_error(self, msg, code, body):
        """
        If there's an error (retrieving the values etc)
        """
        self._error_message = 'Error: %(code)s - %(msg)s: %(body)s' % {'msg':msg, 'body':body, 'code':code}
        self.info_header.message = self._error_message
        self.info_header.refresh()
        curses.doupdate()

    def sort_by(self):
        if self.list_header.get_order():
            self.listview.sort_by_column(
                    col_name=self.list_header.get_sel_column(),
                    asc=False)
            self.list_header.set_order(False)
            self.list_header.refresh()
        else:
            self.listview.sort_by_column(
                    col_name=self.list_header.get_sel_column(),
                    asc=True)
            self.list_header.set_order(True)
            self.list_header.refresh()
        self.core.doupdate()

    @refresh_wrapper.always
    def reset_help_message(self, _=None):
        curses.curs_set(0)
        self.input = self.default_help_message
        self.input.resize(1, self.width, self.height-1, 0)
        return True

    def execute_slash_command(self, txt):
        if txt.startswith('/'):
            self.input.key_enter()
            self.execute_command(txt)
        return self.reset_help_message()

    def completion(self):
        if isinstance(self.input, windows.Input):
            self.complete_commands(self.input)

    def on_input(self, key, raw):
        res = self.input.do_command(key, raw=raw)
        if res and not isinstance(self.input, windows.Input):
            return True
        elif res:
            return False
        if not raw and key in self.key_func:
            return self.key_func[key]()

    def on_info_win_size_changed(self):
        if self.core.information_win_size >= self.height-3:
            return
        self.info_header.resize(1, self.width, self.height-2-self.core.information_win_size - Tab.tab_win_height(), 0)
        self.listview.resize(self.height-3-self.core.information_win_size - Tab.tab_win_height(), self.width, 1, 0)

    def on_lose_focus(self):
        self.state = 'normal'

    def on_gain_focus(self):
        self.state = 'current'
        curses.curs_set(0)

    def on_scroll_up(self):
        return self.listview.scroll_up()

    def on_scroll_down(self):
        return self.listview.scroll_down()

    def move_cursor_up(self):
        self.listview.move_cursor_up()
        self.listview.refresh()
        self.core.doupdate()

    def move_cursor_down(self):
        self.listview.move_cursor_down()
        self.listview.refresh()
        self.core.doupdate()

    def matching_names(self):
        return [(2, self.name)]


