"""
Classes and functions for displaying error/warning/info dialogs to the user.
"""
__author__ = 'laharah'

# noinspection PyUnresolvedReferences
import gtk
import pprint
from filebottool.common import LOG

log = LOG


class InfoDialog(gtk.Dialog):
    """
    Loads and shows a dialog to the user informing them of some event.
    used to display errors.
    """

    def __init__(self, title, message, parent=None, modal=False):
        if modal:
            modal = gtk.DIALOG_MODAL
        else:
            modal = 0
        gtk.Dialog.__init__(self, title, parent, modal, (gtk.STOCK_OK, gtk.RESPONSE_OK))
        self.message = message
        label = gtk.Label(message)
        self.get_content_area().add(label)
        self.set_position(gtk.WIN_POS_CENTER)
        self.set_gravity(gtk.gdk.GRAVITY_CENTER)
        self.show_all()

    def run_async(self):
        """a version of run that does not block"""

        def dialog_response_cb(dialog, response_id):
            dialog.destroy()

        if not self.modal:
            self.set_modal(True)
        self.connect('response', dialog_response_cb)
        self.show()


class ResponseDialog(gtk.Dialog):
    """
    Loads and shows a dialog that presents a user with options, one of which they must
    choose to continue. Defaults to OK and Cancle Buttons.
    """

    def __init__(self, title, message, parent=None, modal=True, buttons=None):
        if not buttons:
            buttons = (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT, gtk.STOCK_CANCEL,
                       gtk.RESPONSE_CANCEL)
        modal = gtk.DIALOG_MODAL if modal else 0
        super(self.__class__, self).__init__(title, parent, modal, buttons)
        self.message = message
        label = gtk.Label(message)
        self.get_content_area().add(label)
        self.set_gravity(gtk.gdk.GRAVITY_CENTER)
        self.set_position(gtk.WIN_POS_CENTER)
        self.show_all()


class UserMessenger(object):
    """
    handles the formatting and creation of dialogs to display info to the user.
    """

    def __init__(self):
        pass

    def show_new_files(self, files):
        """
        Given a list of new files, display message showing them to the user
        Args:
            files: list of files or file => linked file pairs
        """
        message = """FileBot has created the following new files:\n"""
        title = "New Files Created"
        dialog = InfoDialog(title, message)
        files = [' => '.join(f) if isinstance(f, tuple) else f for f in files]
        files = pprint.pformat(files)
        text_view = gtk.TextView()
        text_view.get_buffer().set_text(files)
        text_view.set_editable(False)
        text_view.set_cursor_visible(False)
        text_view.show()
        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        sw.show()
        sw.add(text_view)
        detail_view = gtk.Frame()
        detail_view.set_shadow_type(gtk.SHADOW_IN)
        detail_view.add(sw)
        detail_view.set_border_width(6)
        dialog.vbox.add(detail_view)
        text_view.set_size_request(485, 300)
        detail_view.show()
        dialog.run_async()
        return

    def display_errors(self,
                       errors,
                       title=None,
                       message=None,
                       parent=None,
                       modal=False,
                       show_details=False,
                       response_needed=False):
        """
        Given a dictionary of errors, display them as a dialog for the user.
        :param errors:dictionary in format {torrent_id; (error, error_message)
            OR tuple in format (error, error_message)
        :param parent: Optional parent of the new dialog displayed.
        :param modal: Make dialog modal
        :return:
        """
        if isinstance(errors, tuple):
            errors = {0: errors}

        if message is None:
            message = ("One or more errors occurred in FileBotTool. Click \"Show"
                       " Details\" for more info.")
        if title is None:
            title = "FilebotTool Error"
        dialog = InfoDialog(title, message, parent, modal)
        error_details = format_errors(errors)
        text_view = gtk.TextView()
        text_view.get_buffer().set_text(error_details)
        text_view.set_editable(False)
        text_view.set_cursor_visible(False)
        text_view.show()
        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        sw.show()
        sw.add(text_view)
        detail_view = gtk.Frame()
        detail_view.set_shadow_type(gtk.SHADOW_IN)
        detail_view.add(sw)
        detail_view.set_border_width(6)
        dialog.vbox.add(detail_view)
        text_view.set_size_request(485, 300)

        info_button = gtk.Button("Show Details")

        def _show_details(_):
            detail_view.show()

        if show_details:
            _show_details(None)

        info_button.connect("clicked", _show_details)
        dialog.action_area.pack_start(info_button)
        dialog.action_area.reorder_child(info_button, 0)
        info_button.show()

        if response_needed:
            response = None
            while response not in [gtk.RESPONSE_OK, gtk.RESPONSE_DELETE_EVENT]:
                response = dialog.run()
            dialog.destroy()
            return response
        else:
            dialog.run_async()
            return

    def display_text(self, title, text, parent=None, modal=False):
        dialog = InfoDialog(title, None, parent, modal)
        text_view = gtk.TextView()
        text_view.get_buffer().set_text(text)
        text_view.set_editable(False)
        text_view.set_cursor_visible(False)
        text_view.show()
        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        sw.show()
        sw.add(text_view)
        detail_view = gtk.Frame()
        detail_view.set_shadow_type(gtk.SHADOW_IN)
        detail_view.add(sw)
        detail_view.set_border_width(6)
        dialog.vbox.add(detail_view)
        detail_view.show()
        text_view.set_size_request(485, 300)
        dialog.run_async()
        return


def format_errors(errors):
    """
    formats errors into a human readable text blob.

    :param errors: dictionary in format {torrent_id: (error, error_msg),...}
    """
    error_list = []

    for torrent_id in errors:
        if torrent_id != 0:
            text = "{0} error on torrent {1}:\n".format(errors[torrent_id][0], torrent_id)
        else:
            text = "{0} error:\n".format(errors[torrent_id][0])

        text += ''.join("    {0}\n".format(l) for l in errors[torrent_id][1].splitlines())
        error_list.append(text)

    return '\n'.join(error_list)