# /usr/bin/env python
# -*- coding: utf-8 -*-
# -*- encoding: utf-8 -*-

"""
    Clase que controla los eventos del downloader
    además de las descargas de los videos y audios
"""

# __author__=jjr4p

from io import BytesIO
from PIL import ImageTk
from PIL.Image import open as opp
from tkinter import Toplevel, NORMAL, DISABLED, END, INSERT, TclError, IntVar
from tkinter import messagebox as msg
from tkinter import ttk
from tkinter import filedialog
import pafy
import requests
import os
import threading
import platform

class Controlador:

    def setVista(self, vista):
        """ Define la vista que será controlada """
        self.vista = vista
        self.recurso = None

    def cargarurl(self):
        """
            Método encargado de llamar al método cargarInfo en un
             hilo distinto
         """
        self.vista.button.config(state=DISABLED)
        self.vista.bvideo.config(state=DISABLED)
        self.vista.baudio.config(state=DISABLED)
        self.vista.bborrar.config(state=DISABLED)

        if platform.system() == 'Windows':
            self.vista.config(cursor="wait")

        if "facebook" in self.vista.url.get():
            self.t = threading.Thread(target=self.cargarFB)
            self.t.start()
        else:
            try:
                self.recursoPL = pafy.get_playlist(self.vista.url.get())
                self.t = threading.Thread(target=self.cargarPlayList)
                self.t.start()
            except ValueError as e:
                try:
                    self.recurso = pafy.new(self.vista.url.get())
                    self.t = threading.Thread(target=self.cargarInfo)
                    self.t.start()
                except ValueError as e:
                    mensaje = "La url es inválida o no se encuentra conectado "
                    mensaje += "a internet, intentelo nuevamente."
                    msg.showerror("Error", mensaje)
                    self.vista.button.config(state=NORMAL)
                    self.vista.bvideo.config(state=NORMAL)
                    self.vista.baudio.config(state=NORMAL)
                    self.vista.bborrar.config(state=NORMAL)
                    self.vista.config(cursor="")


    def cargarInfo(self):
        self.vista.notebook.select(self.vista.tab1)
        """ Método encargado de obtener información dela url ingresada """
        info = ""
        info += "■Título: " + self.recurso.title+"\n"
        info += "■Duración: " + self.recurso.duration+"\n"
        info += "■Autor: " + self.recurso.author+"\n"

        try:
            info += "■Categoría: " + self.recurso.category+"\n"
        except:
            info += "■Categoría: No disponible\n"
            pass

        info += "■Likes: " + str(self.recurso.likes)+"\n"
        info += "■Dislikes: " + str(self.recurso.dislikes)+"\n"
        mejor = self.recurso.getbest()
        info += "■Mejor resolución: " + mejor.resolution+"\n"
        info += "■Mejor formato: " + mejor.extension
        if self.recurso.bigthumb != '':
            response = requests.get(self.recurso.bigthumb)
            img_data = response.content
            img = ImageTk.PhotoImage(opp(BytesIO(img_data)))
            self.vista.imagen.config(text="", image=img)
            self.vista.imagen.image = img

        self.vista.text.config(state=NORMAL)
        self.vista.text.delete(1.0, END)
        self.vista.text.insert(INSERT, info)
        self.vista.text.config(state=DISABLED)
        self.cargarLista()
        self.vista.button.config(state=NORMAL)
        self.vista.bvideo.config(state=NORMAL)
        self.vista.baudio.config(state=NORMAL)
        self.vista.bborrar.config(state=NORMAL)
        self.vista.config(cursor="")

    def cargarLista(self):
        """
            Método encargado de obtener los formatos disponibles del
            video que se busca
        """

        self.streams = self.recurso.streams
        self.vista.listbox.delete(0, END)
        i = 0
        texto_a_insertar = "{}) Resolución: {}, Extensión: {}, Tamaño: {}"
        for s in self.streams:
            i += 1
            tamanio = str("%.2f MB." % (s.get_filesize()/(1024**2)))
            self.vista.listbox.insert(END, texto_a_insertar.format(
                i, s.resolution, s.extension, tamanio))

    def descargaVideo(self):
        """
            Método encargado de llamar al método __descargaVideo, 
            según lo seleccionado por el usuario además que
            se ejecuta en un hilo distinto    
        """
        index = self.vista.listbox.curselection()
        if len(index) > 0:
            self.seleccion = self.streams[index[0]]
            self.size = self.seleccion.get_filesize()
            self.mostrarDialogo()
            t = threading.Thread(target=self.__descargarVideo)
            t.start()

            self.vista.button.config(state=DISABLED)
            self.vista.bvideo.config(state=DISABLED)
            self.vista.baudio.config(state=DISABLED)
            self.vista.bborrar.config(state=DISABLED)
        else:
            msg.showerror("Error", "Se debe seleccionar un video de la lista.")

    def __descargarVideo(self):
        """ Método que descarga el video seleccionado y muestra la carga """
        self.d = True
        try:
            file = self.seleccion.download(
                quiet=True, filepath=self.vista.path.get(),
                callback=self.callback)

        except Exception as e:
            raise e
            msg.showerror("Error", "El archivo ya existe.")

        self.top.destroy()
        self.d = False
        msg.showinfo("Mensaje", "Archivo descargado correctamente")
        self.vista.text.config(state=NORMAL)
        self.vista.text.delete(1.0, END)
        self.vista.text.config(state=DISABLED)
        self.vista.listbox.delete(0, END)
        self.vista.url.set("")
        self.vista.imagen.config(text="No disponible", image='')
        self.vista.imagen.image = ''
        self.vista.button.config(state=NORMAL)
        self.vista.bvideo.config(state=NORMAL)
        self.vista.baudio.config(state=NORMAL)
        self.vista.config(cursor='')
        self.vista.bborrar.config(state=NORMAL)
        self.vista.config(cursor="")

    def descargaAudio(self):
        """
            Método encargado de llamar al método __descargaAudio, 
            que descarga la mejor resolución de audio, además que
            se ejecuta en un hilo distinto    
        """
        if self.recurso != None:
            t = threading.Thread(target=self.__descargaAudio)
            t.start()
            self.vista.button.config(state=DISABLED)
            self.vista.bvideo.config(state=DISABLED)
            self.vista.baudio.config(state=DISABLED)
            self.vista.bborrar.config(state=DISABLED)
            self.mostrarDialogo()

    def __descargaAudio(self):
        """ Método que descarga el video seleccionado y muestra la carga """
        self.bestaudio = self.recurso.getbestaudio(preftype='m4a')
        if self.bestaudio != None:
            self.d = True
            self.fileaudio = self.bestaudio.title+".m4a"
            self.size = self.bestaudio.get_filesize()
            try:
                self.bestaudio.download(
                    quiet=True, callback=self.callback,
                    filepath=self.vista.path.get())

                msg.showinfo("Mensaje", "Archivo descargado correctamente.")

            except Exception as e:
                msg.showerror("Error", "El archivo ya existe.")

        self.top.destroy()
        self.d = False
        self.vista.text.config(state=NORMAL)
        self.vista.text.delete(1.0, END)
        self.vista.text.config(state=DISABLED)
        self.vista.listbox.delete(0, END)
        self.vista.url.set("")
        self.vista.imagen.config(text="No disponible", image='')
        self.vista.imagen.image = ''
        self.vista.button.config(state=NORMAL)
        self.vista.bvideo.config(state=NORMAL)
        self.vista.baudio.config(state=NORMAL)
        self.vista.config(cursor='')
        self.vista.bborrar.config(state=NORMAL)
        self.vista.config(cursor="")

    def mostrarDialogo(self):
        """ Método que muestra la GUI de descarga del archivo """
        self.top = Toplevel(self.vista)
        self.top.resizable(0, 0)
        self.top.iconbitmap('descarga.ico')
        geometry = "400x150+"
        geometry = "400x250+"
        geometry += str(int(self.vista.ancho/2)-150)+"+"
        geometry += str(int(self.vista.alto/2)-50)
        self.top.geometry(geometry)
        self.top.title("Descarga en progreso...")
        self.label = Label(self.top, text="Descargando: ", font=("Arial", 13))
        self.label.place(x=5, y=15)
        self.label2 = Label(self.top, text="Tiempo: ", font=("Arial", 13))
        self.label2.place(x=130, y=15)
        self.label3 = Label(self.top, text="Vel.: ", font=("Arial", 13))
        self.label3.place(x=250, y=15)
        self.progress = IntVar()
        self.progress.set(0)
        self.progressbar = ttk.Progressbar(self.top, variable=self.progress)
        self.progressbar.place(x=30, y=60, width=320)
        self.bcancelar = ttk.Button(self.top, text="Cancelar")
        self.bcancelar.place(x=150, y= 100)
        self.top.iconbitmap('descarga.ico')
        self.progress = IntVar()
        self.progress.set(0)
        self.progressbar = ttk.Progressbar(self.top, variable=self.progress)
        self.label = ttk.Label(self.top, text="Descargando: ", font=("Arial", 14))
        self.label.place(x=5, y=15)
        self.label2 = ttk.Label(self.top, text="Tiempo restante: ", font=("Arial", 14))
        self.label2.place(x=5, y=65)
        self.label3 = ttk.Label(self.top, text="Velocidad: ", font=("Arial", 14))
        self.label3.place(x=5, y=115)
        
        self.progressbar.place(x=30, y=160, width=320)
        if platform.system() == 'Windows':
            self.vista.config(cursor="wait")

        self.bcancelar = ttk.Button(self.top, text="cancelar", command=self.cancelar)
        self.bcancelar.place(x=150,y=200)
        self.top.transient(self.vista)
        self.top.config(bg="#4C4C4D")

    def iniciar(self):
        """ Método que muestra la GUI """
        self.vista.mainloop()

    def cancelar(self):
        pass

    def borrarurl(self):
        """ Método borra la url ingresada """
        self.vista.url.set("")

    def callback(self, total, recvd, ratio, rate, eta):
        """ Método que controla la descarga del archivo """
        carga = int(ratio*100)
        self.progressbar.step(carga - self.progress.get())
        self.progress.set(carga)
        self.label.config(text="Descarga: "+str(carga)+" %")
        self.label2.config(text="Tiempo restante: "+str("%.0f" % (eta))+" segundos")
        self.label3.config(text="Velocidad: "+str("%.2f" % (rate/1024))+" Mb/s")
        

    def cambiaPath(self):
        """ Método para cambiar la carpeta destino """
        path = filedialog.askdirectory()
        if path != None and path != '':
            self.vista.path.set(path)

    def copia(self, event):
        """ Método que pega la url del portapapeles """
        self.vista.url.set(self.vista.clipboard_get())

    def cargarPlayList(self):
        self.vista.notebook.select(self.vista.tabPL)
        self.disponibles = self.recursoPL['items']
        self.vista.listPL.delete(0, END)
        i = 0
        texto_a_insertar = "{}) Título: {}, Duración: {}"
        for s in self.disponibles:
            i += 1
            insertar = texto_a_insertar.format(i, s['pafy'].title[:40]+"...", s['pafy'].duration)
            try:
                self.vista.listPL.insert(END,insertar)
            except TclError as e:
                pass

        self.vista.button.config(state=NORMAL)
        self.vista.bvideo.config(state=NORMAL)
        self.vista.baudio.config(state=NORMAL)
        self.vista.bborrar.config(state=NORMAL)
        self.vista.config(cursor="")

    def cargarInfoDesdePL(self):

        index = self.vista.listPL.curselection()

        if len(index) > 0:

            if platform.system() == 'Windows':
                self.vista.config(cursor="wait")

            self.recurso = self.recursoPL['items'][index[0]]['pafy']
            self.vista.button.config(state=DISABLED)
            self.vista.bvideo.config(state=DISABLED)
            self.vista.baudio.config(state=DISABLED)
            self.vista.bborrar.config(state=DISABLED)
            self.t = threading.Thread(target=self.cargarInfo)
            self.t.start()

        else:
            msg.showerror("Error", "Se debe seleccionar un video de la lista.")

    def cargarFB(self):

        try:
            rpta = msg.askyesno("Pregunta", "No se puede obtener información "+
                "de un video de facebook, desea continuar con la descarga?")

            if rpta:
                path = filedialog.asksaveasfilename()
                os.popen("facebook-dl.py {} hd {}".format(self.vista.url.get(),path))
                msg.showinfo("Mensaje", "Archivo descargado correctamente.")
                
        except:
            msg.showerror("Error", "El video no es público, o la url es inválida.")

        self.vista.button.config(state=NORMAL)
        self.vista.bvideo.config(state=NORMAL)
        self.vista.baudio.config(state=NORMAL)
        self.vista.bborrar.config(state=NORMAL)
        self.vista.config(cursor="")