import Tkinter as tk
import sys
import tkFont
import ttk
import locale
import os


class StreamFrame(object):
    def __init__(self, app, uri):
        self.app = app
        self.uri = uri
        self.stream_hash = None
        self.cancel_func = None

        self.stream_frame = ttk.Frame(self.app.streams_frame, style="B.TFrame")

        self.stream_frame.pack(fill=tk.X, side=tk.BOTTOM, pady=(30, 0))

        self.stream_frame_header = ttk.Frame(self.stream_frame, style="C.TFrame")
        self.stream_frame_header.grid(sticky=tk.E + tk.W)

        self.uri_font = tkFont.Font(size=8)
        self.uri_label = ttk.Label(
            self.stream_frame_header, text=self.uri, font=self.uri_font, foreground="#666666"
        )
        self.uri_label.grid(row=0, column=0, sticky=tk.W)

        if os.name == "nt":
            self.button_cursor = ""
        else:
            self.button_cursor = "hand1"

        close_file_name = "close2.gif"
        if os.name == "nt":
            close_file = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), close_file_name)
        else:
            close_file = os.path.join(os.path.dirname(__file__), close_file_name)

        self.close_picture = tk.PhotoImage(
            file=close_file
        )
        self.close_button = ttk.Button(
            self.stream_frame_header, command=self.cancel, style="Stop.TButton", cursor=self.button_cursor
        )
        self.close_button.config(image=self.close_picture)
        self.close_button.grid(row=0, column=1, sticky=tk.E + tk.N)

        self.stream_frame_header.grid_columnconfigure(0, weight=1)

        self.stream_frame.grid_columnconfigure(0, weight=1)

        self.stream_frame_body = ttk.Frame(self.stream_frame, style="C.TFrame")
        self.stream_frame_body.grid(row=1, column=0, sticky=tk.E + tk.W)

        self.name_frame = ttk.Frame(self.stream_frame_body, style="D.TFrame")
        self.name_frame.grid(sticky=tk.W + tk.E)
        self.name_frame.grid_columnconfigure(0, weight=16)
        self.name_frame.grid_columnconfigure(1, weight=1)

        self.stream_frame_body.grid_columnconfigure(0, weight=1)

        self.metadata_frame = ttk.Frame(self.stream_frame_body, style="D.TFrame")
        self.metadata_frame.grid(sticky=tk.W + tk.E, row=1)
        self.metadata_frame.grid_columnconfigure(0, weight=1)

        self.options_frame = ttk.Frame(self.stream_frame_body, style="D.TFrame")

        self.outer_button_frame = ttk.Frame(self.stream_frame_body, style="D.TFrame")
        self.outer_button_frame.grid(sticky=tk.W + tk.E, row=4)

        #show_options_picture_file_name = "show_options.gif"
        #if os.name == "nt":
        #    show_options_picture_file = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])),
        #                                             "lbrynet", "lbrynet_downloader_gui",
        #                                             show_options_picture_file_name)
        #else:
        #    show_options_picture_file = os.path.join(os.path.dirname(__file__),
        #                                             show_options_picture_file_name)

        #self.show_options_picture = tk.PhotoImage(
        #    file=show_options_picture_file
        #)

        #hide_options_picture_file_name = "hide_options.gif"
        #if os.name == "nt":
        #    hide_options_picture_file = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])),
        #                                             "lbrynet", "lbrynet_downloader_gui",
        #                                             hide_options_picture_file_name)
        #else:
        #    hide_options_picture_file = os.path.join(os.path.dirname(__file__),
        #                                             hide_options_picture_file_name)

        #self.hide_options_picture = tk.PhotoImage(
        #    file=hide_options_picture_file
        #)

        #self.show_options_button = None

        self.status_label = None
        #self.name_label = None
        self.name_text = None
        self.estimated_cost_frame = None
        self.bytes_downloaded_label = None
        self.button_frame = None
        self.download_buttons = []
        self.option_frames = []
        self.name_font = None
        self.description_text = None
        #self.description_label = None
        self.file_name_frame = None
        self.cost_frame = None
        self.cost_description = None
        self.remaining_cost_description = None
        self.cost_label = None
        self.remaining_cost_label = None
        self.progress_frame = None

    def cancel(self):
        if self.cancel_func is not None:
            self.cancel_func() # pylint: disable=not-callable
        self.stream_frame.destroy()
        self.app.stream_removed()

    def _resize_text(self, text_widget):
        actual_height = text_widget.tk.call(text_widget._w, "count", "-displaylines", "0.0", "end")
        text_widget.config(height=int(actual_height))

    def show_name(self, name):
        self.name_font = tkFont.Font(size=16)
        #self.name_label = ttk.Label(
        #    self.name_frame, text=name, font=self.name_font
        #)
        #self.name_label.grid(row=0, column=0, sticky=tk.W)
        self.name_text = tk.Text(
            self.name_frame, font=self.name_font, wrap=tk.WORD, relief=tk.FLAT, borderwidth=0,
            highlightthickness=0, width=1, height=1
        )
        self.name_text.insert(tk.INSERT, name)
        self.name_text.config(state=tk.DISABLED)
        self.name_text.grid(row=0, column=0, sticky=tk.W+tk.E+tk.N+tk.S)
        self.name_text.update()
        self._resize_text(self.name_text)

    def show_description(self, description):
        #if os.name == "nt":
        #    wraplength = 580
        #else:
        #    wraplength = 600
        #self.description_label = ttk.Label(
        #    self.name_frame, text=description, wraplength=wraplength
        #)
        #self.description_label.grid(row=1, column=0, sticky=tk.W)
        self.description_text = tk.Text(
            self.name_frame, wrap=tk.WORD, relief=tk.FLAT, borderwidth=0,
            highlightthickness=0, width=1, height=1
        )
        self.description_text.insert(tk.INSERT, description)
        self.description_text.config(state=tk.DISABLED)
        self.description_text.grid(row=1, column=0, sticky=tk.W+tk.E+tk.N+tk.S)
        self.description_text.update()
        self._resize_text(self.description_text)

    def show_thumbnail(self, url=None):
        thumbnail = None
        if url is not None:
            import urllib2
            import base64
            response = urllib2.urlopen(url)
            thumbnail_data = base64.b64encode(response.read())
            thumbnail = tk.PhotoImage(data=thumbnail_data)
            current_width = thumbnail.width()
            current_height = thumbnail.height()
            max_width = 130
            max_height = 90
            scale_ratio = max(1.0 * current_width / max_width, 1.0 * current_height / max_height)
            if scale_ratio < 1:
                scale_ratio = 1
            else:
                scale_ratio = int(scale_ratio + 1)
            thumbnail = thumbnail.subsample(scale_ratio)
        if thumbnail is not None:
            label = ttk.Label(self.name_frame, image=thumbnail)
            label.safekeeping = thumbnail
            label.grid(row=0, column=1, rowspan=2, sticky=tk.E+tk.N+tk.W+tk.S)
            label.update()
            self.description_text.update()
            self.name_text.update()
            self._resize_text(self.description_text)
            self._resize_text(self.name_text)

    def show_metadata_status(self, value):
        if self.status_label is None:
            self.status_label = ttk.Label(
                self.metadata_frame, text=value
            )
            self.status_label.grid()
            self.metadata_frame.grid_columnconfigure(0, weight=1)
        else:
            self.status_label.config(text=value)

    @staticmethod
    def get_formatted_stream_size(stream_size):
        if isinstance(stream_size, (int, long)):
            if stream_size >= 2**40:
                units = "TB"
                factor = 2**40
            elif stream_size >= 2**30:
                units = "GB"
                factor = 2**30
            elif stream_size >= 2**20:
                units = "MB"
                factor = 2**20
            elif stream_size >= 2**10:
                units = "KB"
                factor = 2**10
            else:
                return str(stream_size) + " B"
            return "%.1f %s" % (round((stream_size * 1.0 / factor), 1), units)
        return stream_size

    def show_stream_metadata(self, stream_name, stream_size, stream_cost):
        if self.status_label is not None:
            self.status_label.destroy()

        self.file_name_frame = ttk.Frame(self.metadata_frame, style="F.TFrame")
        self.file_name_frame.grid(row=0, column=0, sticky=tk.W)
        self.metadata_frame.grid_columnconfigure(0, weight=1, uniform="metadata")

        file_size_label = ttk.Label(
            self.file_name_frame,
            text=self.get_formatted_stream_size(stream_size)
        )
        file_size_label.grid(row=0, column=2)

        file_name_label = ttk.Label(
            self.file_name_frame,
            text=" - " + stream_name,
        )
        file_name_label.grid(row=0, column=3)

        self.estimated_cost_frame = ttk.Frame(self.metadata_frame, style="F.TFrame")
        self.estimated_cost_frame.grid(row=1, column=0, sticky=tk.W)

        estimated_cost_label = ttk.Label(
            self.estimated_cost_frame,
            text=locale.format_string("%.2f LBC",
                                      (round(stream_cost, 2)), grouping=True),
            foreground="red"
        )
        estimated_cost_label.grid(row=1, column=2)

        self.button_frame = ttk.Frame(self.outer_button_frame, style="E.TFrame")
        self.button_frame.grid(row=0, column=1)

        self.outer_button_frame.grid_columnconfigure(0, weight=1, uniform="buttons")
        self.outer_button_frame.grid_columnconfigure(1, weight=2, uniform="buttons1")
        self.outer_button_frame.grid_columnconfigure(2, weight=1, uniform="buttons")

    def add_download_factory(self, factory, download_func):
        download_button = ttk.Button(
            self.button_frame, text=factory.get_description(), command=download_func,
            style='LBRY.TButton', cursor=self.button_cursor
        )
        self.download_buttons.append(download_button)
        download_button.grid(row=0, column=len(self.download_buttons) - 1, padx=5, pady=(1, 2))

    def disable_download_buttons(self):
        for download_button in self.download_buttons:
            download_button.config(state=tk.DISABLED)

    def remove_download_buttons(self):
        for download_button in self.download_buttons:
            download_button.destroy()
        self.download_buttons = []

    def get_option_widget(self, option_type, option_frame):
        if option_type.value == float:
            entry_frame = ttk.Frame(
                option_frame,
                style="H.TFrame"
            )
            entry_frame.grid()
            col = 0
            if option_type.short_description is not None:
                entry_label = ttk.Label(
                    entry_frame,
                    #text=option_type.short_description
                    text=""
                )
                entry_label.grid(row=0, column=0, sticky=tk.W)
                col = 1
            entry = ttk.Entry(
                entry_frame,
                width=10,
                style="Float.TEntry"
            )
            entry_frame.entry = entry
            entry.grid(row=0, column=col, sticky=tk.W)
            return entry_frame
        if option_type.value == bool:
            bool_frame = ttk.Frame(
                option_frame,
                style="H.TFrame"
            )
            bool_frame.chosen_value = tk.BooleanVar()
            true_text = "True"
            false_text = "False"
            if option_type.bool_options_description is not None:
                true_text, false_text = option_type.bool_options_description
            true_radio_button = ttk.Radiobutton(
                bool_frame, text=true_text, variable=bool_frame.chosen_value, value=True
            )
            true_radio_button.grid(row=0, sticky=tk.W)
            false_radio_button = ttk.Radiobutton(
                bool_frame, text=false_text, variable=bool_frame.chosen_value, value=False
            )
            false_radio_button.grid(row=1, sticky=tk.W)
            return bool_frame
        label = ttk.Label(
            option_frame,
            text=""
        )
        return label

    def show_download_options(self, options):
        left_padding = 20
        for option in options:
            f = ttk.Frame(
                self.options_frame,
                style="E.TFrame"
            )
            f.grid(sticky=tk.W + tk.E, padx=left_padding)
            self.option_frames.append((option, f))
            description_label = ttk.Label(
                f,
                text=option.long_description
            )
            description_label.grid(row=0, sticky=tk.W)
            if len(option.option_types) > 1:
                f.chosen_type = tk.IntVar()
                choices_frame = ttk.Frame(
                    f,
                    style="F.TFrame"
                )
                f.choices_frame = choices_frame
                choices_frame.grid(row=1, sticky=tk.W, padx=left_padding)
                choices_frame.choices = []
                for i, option_type in enumerate(option.option_types):
                    choice_frame = ttk.Frame(
                        choices_frame,
                        style="G.TFrame"
                    )
                    choice_frame.grid(sticky=tk.W)
                    option_text = ""
                    if option_type.short_description is not None:
                        option_text = option_type.short_description
                    option_radio_button = ttk.Radiobutton(
                        choice_frame, text=option_text, variable=f.chosen_type, value=i
                    )
                    option_radio_button.grid(row=0, column=0, sticky=tk.W)
                    option_widget = self.get_option_widget(option_type, choice_frame)
                    option_widget.grid(row=0, column=1, sticky=tk.W)
                    choices_frame.choices.append(option_widget)
                    if i == 0:
                        option_radio_button.invoke()
            else:
                choice_frame = ttk.Frame(
                    f,
                    style="F.TFrame"
                )
                choice_frame.grid(sticky=tk.W, padx=left_padding)
                option_widget = self.get_option_widget(option.option_types[0], choice_frame)
                option_widget.grid(row=0, column=0, sticky=tk.W)
                f.option_widget = option_widget
        #self.show_options_button = ttk.Button(
        #    self.stream_frame_body, command=self._toggle_show_options, style="Stop.TButton",
        #    cursor=self.button_cursor
        #)
        #self.show_options_button.config(image=self.show_options_picture)
        #self.show_options_button.grid(sticky=tk.W, row=2, column=0)

    def _get_chosen_option(self, option_type, option_widget):
        if option_type.value == float:
            return float(option_widget.entry.get())
        if option_type.value == bool:
            return option_widget.chosen_value.get()
        return option_type.value

    def get_chosen_options(self):
        chosen_options = []
        for o, f in self.option_frames:
            if len(o.option_types) > 1:
                chosen_index = f.chosen_type.get()
                option_type = o.option_types[chosen_index]
                option_widget = f.choices_frame.choices[chosen_index]
                chosen_options.append(self._get_chosen_option(option_type, option_widget))
            else:
                option_type = o.option_types[0]
                option_widget = f.option_widget
                chosen_options.append(self._get_chosen_option(option_type, option_widget))
        return chosen_options

    #def _toggle_show_options(self):
    #    if self.options_frame.winfo_ismapped():
    #        self.show_options_button.config(image=self.show_options_picture)
    #        self.options_frame.grid_forget()
    #    else:
    #        self.show_options_button.config(image=self.hide_options_picture)
    #        self.options_frame.grid(sticky=tk.W + tk.E, row=3)

    def show_progress(self, total_bytes, bytes_left_to_download, points_paid,
                      points_remaining):
        if self.bytes_downloaded_label is None:
            self.remove_download_buttons()
            self.button_frame.destroy()
            self.estimated_cost_frame.destroy()
            for option, frame in self.option_frames:
                frame.destroy()
            self.options_frame.destroy()
            #self.show_options_button.destroy()

            self.progress_frame = ttk.Frame(self.outer_button_frame, style="F.TFrame")
            self.progress_frame.grid(row=0, column=0, sticky=tk.W, pady=(0, 8))

            self.bytes_downloaded_label = ttk.Label(
                self.progress_frame,
                text=""
            )
            self.bytes_downloaded_label.grid(row=0, column=0)

            self.cost_frame = ttk.Frame(self.outer_button_frame, style="F.TFrame")
            self.cost_frame.grid(row=1, column=0, sticky=tk.W, pady=(0, 4))

            self.cost_label = ttk.Label(
                self.cost_frame,
                text="",
                foreground="red"
            )
            self.cost_label.grid(row=0, column=1, padx=(1, 0))
            self.outer_button_frame.grid_columnconfigure(2, weight=0, uniform="")

        if self.bytes_downloaded_label.winfo_exists():
            percent_done = 0
            if total_bytes > 0:
                percent_done = 100.0 * (total_bytes - bytes_left_to_download) / total_bytes
            percent_done_string = locale.format_string("  (%.2f%%)", percent_done)
            self.bytes_downloaded_label.config(
                text=self.get_formatted_stream_size(total_bytes - bytes_left_to_download) + percent_done_string
            )
        if self.cost_label.winfo_exists():
            total_points = points_remaining + points_paid
            self.cost_label.config(text=locale.format_string("%.2f/%.2f LBC",
                                                             (round(points_paid, 2), round(total_points, 2)),
                                                             grouping=True))

    def show_download_done(self, total_points_paid):
        if self.bytes_downloaded_label is not None and self.bytes_downloaded_label.winfo_exists():
            self.bytes_downloaded_label.destroy()
        if self.cost_label is not None and self.cost_label.winfo_exists():
            self.cost_label.config(text=locale.format_string("%.2f LBC",
                                                             (round(total_points_paid, 2),),
                                                             grouping=True))
