class TkUserListSelect(object):
    """
    A simple box to pop up for user based item selection.
    This is not for file or file path selection, there is another class
    for that

    Example
    -------
    >>> user_list_box = TkUserListSelect(title='Title',
    >>>                                  message='Info For User',
    >>>                                  user_enum=dict(
    >>>      zip([1, 'hi', 'user sees these', 4],
    >>>          [1, 'user doesnt see these',
    >>>          'but they correspond with the keys that the user does see',
    >>>          ' 1:1 by location and are what are returned if desired'])))

    >>> user_list_box.open_frame()
    ...Interaction (user selects 'hi')
    >>> user_list_box.return_index()
    1
    >>> user_list_box.return_index_value()
    'hi'
    >>> user_list_box.return_enum()
    {'hi': 'user doesnt see these'}
    >>> user_list_box.return_value()
    'user doesnt see these'
    """
    def __init__(self, title, message, user_enum):
        self.master = Tk()
        self.value = None
        self._user_presented_list = list(user_enum.keys())
        self._short_bubble_sort()
        self._user_enum = user_enum
        self._current_font_type = 'Times'
        self._current_font_size = 10
        self.font_obj = font.Font(font=(self._current_font_type,
                                        self._current_font_size))

        # self.modalPane = Toplevel(self.master)
        self.modalPane = self.master

        # self.modalPane.transient(self.master)
        self.modalPane.grab_set()

        self.modalPane.bind("<Return>", self._choose)
        self.modalPane.bind("<Escape>", self._cancel)

        if title:
            self.modalPane.title(title)

        if message:
            self.message_label = \
                Label(self.modalPane, text=message)
            self.message_label.pack(padx=5, pady=5)

        listFrame = Frame(self.modalPane)
        listFrame.pack(side=TOP, padx=5, pady=5)

        scrollBar = Scrollbar(listFrame)
        scrollBar.pack(side=RIGHT, fill=Y)
        self.listBox = Listbox(listFrame, selectmode=SINGLE)
        self.listBox.pack(side=LEFT, fill=Y)
        scrollBar.config(command=self.listBox.yview)
        self.listBox.config(yscrollcommand=scrollBar.set)
        # self.list.sort()
        for item in self._user_presented_list:
            self.listBox.insert(END, item)

        buttonFrame = Frame(self.modalPane)
        buttonFrame.pack(side=BOTTOM)

        chooseButton = Button(buttonFrame, text="Choose", command=self._choose)
        chooseButton.pack()

        cancelButton = Button(buttonFrame, text="Cancel", command=self._cancel)
        cancelButton.pack(side=RIGHT)

        self.set_font_size('Times', 10)
        self.autowidth(500)

    def set_font_size(self, FONT_TYPE, FONT_SIZE):
        self._current_font_type = FONT_TYPE
        self._current_font_size = FONT_SIZE
        self.font_obj = font.Font(font=(self._current_font_type,
                                        self._current_font_size))
        self.message_label.config(font=(self._current_font_type,
                                        self._current_font_size))
        self.listBox.config(font=(self._current_font_type,
                                  self._current_font_size))

    def autowidth(self, maxwidth):
        pixels = 0
        for item in self.listBox.get(0, "end"):
            pixels = max(pixels, self.font_obj.measure(item))
        # bump listbox size until all entries fit
        pixels = pixels + 10
        width = int(self.listBox.cget("width"))
        for w in range(0, maxwidth + 1, 5):
            if self.listBox.winfo_reqwidth() >= pixels:
                break
            self.listBox.config(width=width + w)

    def _short_bubble_sort(self):
        exchanges = True
        passnum = len(self._user_presented_list) - 1
        while (passnum > 0) and exchanges:
            exchanges = False
            for i in range(passnum):
                try:
                    if len(self._user_presented_list[i]) > \
                          len(self._user_presented_list[i + 1]):
                        exchanges = True
                        self._user_presented_list[i], self._user_presented_list[i + 1] = \
                        self._user_presented_list[i + 1], self._user_presented_list[i]
                except TypeError as e:
                    pass
            passnum = passnum - 1

    def open_frame(self):
        self.master.mainloop()

    def _choose(self, event=None):
        try:
            firstIndex = self.listBox.curselection()[0]
            self.index = firstIndex
            self.index_value = self._user_presented_list[int(firstIndex)]
        except IndexError:
            self.index_value = None
        self.modalPane.destroy()

    def _cancel(self, event=None):
        self.modalPane.destroy()

    def return_index_value(self):
        return self.index_value

    def return_index(self):
        return self.index

    def return_enum(self):
        return {self.index_value: self._user_enum[self.index_value]}

    def return_value(self):
        return self._user_enum[self.index_value]