"""Small GUI for displaying resource discovery progress to the user."""

import collections
import threading
import Tkinter as tk
import tkMessageBox
import ttk


class LifetimeError(Exception):
    """Progress was interrupted (i.e., window closed or cancel button was pressed)."""
    pass

class GuiProgressBar(ttk.Frame):
    def __init__(self, title, work_count, work_func, *func_args):
        ttk.Frame.__init__(self, relief='ridge', borderwidth=2)
        self.work_count = work_count
        self.worker_task = threading.Thread(target=work_func, args=func_args)
        self.pending_stop = False
        self.master.title(title)
        self.master.protocol('WM_DELETE_WINDOW', self._confirm_quit)
        self.pack(fill='both', expand=1)
        self.widget_space = self._create_widgets()

    def _create_widgets(self):
        # storage for widgets so we don't pollute GUI app instance namespace
        widget_space = collections.namedtuple('WidgetSpace', [
            'button_text',
            'button',
            'label_frame',
            'label_text',
            'label',
            'progress_bar',
            'status_label_text',
            'status_label'
        ])

        button_text = tk.StringVar(value='Start')
        button = ttk.Button(self, textvariable=button_text, command=self._start)
        button.pack()

        label_frame = ttk.LabelFrame(self, text='Service:Region')
        label_frame.pack(fill='x')

        label_text = tk.StringVar()
        label = ttk.Label(label_frame, anchor='w', textvariable=label_text)
        label.pack(fill='x')


        #XXX: add small fraction to max so progress bar doesn't wrap when work finishes
        progress_bar = ttk.Progressbar(
            self,
            orient='horizontal',
            length=self.master.winfo_screenwidth()/5,
            mode='determinate',
            maximum=self.work_count+1e-10
        )
        progress_bar.pack(fill='both')

        status_label_text = tk.StringVar(value='0 / {}'.format(self.work_count))
        status_label = ttk.Label(self, anchor='w', textvariable=status_label_text)
        status_label.pack(fill='x')

        return widget_space(button_text,
                            button,
                            label_frame,
                            label_text,
                            label,
                            progress_bar,
                            status_label_text,
                            status_label)

    def _confirm_quit(self):
        if tkMessageBox.askyesno(message='Quit?'):
            self.pending_stop = True
            self.master.destroy()

    def _confirm_cancel(self):
        if tkMessageBox.askyesno(message='Cancel?'):
            self.pending_stop = True
            self.widget_space.button_text.set('Canceled')
            self.widget_space.button.state(['disabled'])

    def _start(self):
        self.widget_space.button_text.set('Cancel')
        self.widget_space.button['command'] = self._confirm_cancel
        self.worker_task.start()

    def update_progress(self, delta):
        """Update progress bar.

        :param float delta: increment progress by some amount"""
        if self.pending_stop:
            raise LifetimeError('User initiated stop.')
        self.widget_space.progress_bar.step(delta)
        self.widget_space.status_label_text.set('{} / {}'.format(
            int(self.widget_space.progress_bar['value']),
            self.work_count
        ))

    def update_svc_text(self, svc_name, region):
        """Update text in status area of GUI.

        :param str svc_name: service name
        :param str region: region name
        """
        self.widget_space.label_text.set('{}:{}'.format(svc_name, region))

    def finish_work(self):
        """Update GUI when work is complete."""
        self.widget_space.button.state(['disabled'])
        self.widget_space.button_text.set('Finished')