
from ui_diskinstall import Ui_MainWindow
from ui_about import Ui_Dialog as Ui_AboutDialog
from PyQt5.QtWidgets import QMainWindow, QAbstractScrollArea, QDialog
from PyQt5.QtCore import pyqtSignal
from markdown import markdownFromFile
from tools import MyItem
from wizards import DiskinstallWizard
import usbDisk2
from monitor import Monitor

import os, io

class HardDiskMain(Ui_MainWindow, QMainWindow):

    newmonitor        = pyqtSignal(Monitor)
    monitorfinished   = pyqtSignal(Monitor)
    monitorclosed     = pyqtSignal(Monitor)
    monitorout        = pyqtSignal(Monitor, str)
    monitorerr        = pyqtSignal(Monitor, str)

    def __init__(self, owndisk, parent=None):
        """
        Constructeur de la fenêtre principale
        :param owndisk: une chaîne vide ou quelque chose comme "sdc"
        :type  owndisk: str
        :param parent: fenêtre parente, None par défaut
        """
        QMainWindow.__init__(self, parent)
        Ui_MainWindow.__init__(self)
        self.ui = self # for consistency with the main window in __init__.py
        self.owndisk = owndisk
        self.wd=os.path.abspath(os.path.dirname(__file__))
        self.monitors={}
        self.setupUi(self)
        self.initTable()
        self.initTab()
        self.initHelpTab()
        self.about=QDialog()
        self.about.ui=Ui_AboutDialog()
        self.about.ui.setupUi(self.about)
        self.initAbout()

        self.helpButton.clicked.connect(self.showHelp)
        self.quitButton.clicked.connect(self.close)
        self.cloneButton.clicked.connect(self.cloneAction)
        self.cloneButton1.clicked.connect(self.cloneAction)
        self.newmonitor.connect(self.new_monitor)
        self.monitorfinished.connect(self.monitor_finished)
        self.monitorclosed.connect(self.monitor_closed)
        self.monitorout.connect(self.monitor_out)
        self.monitorerr.connect(self.monitor_err)

        self.updateSda() # take /dev/sda in account
        return
    
    def initTable(self):
        """
        Prepare the table to show the hard disk
        """
        t=self.tableWidget
        t.setColumnCount(3)
        t.setHorizontalHeaderLabels([
            self.tr("Device"), self.tr("Partitions"),self.tr("Status")
        ])
        t.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents)
        return
    
    def initTab(self):
        """
        Initialise le QTabWidget dans l'interface utilisateur
        retire le widget numéro 1, qui provient du Designer.
        Attention, le widget numéro 0 est spécial : il contient l'aide.
        """
        w=self.tabWidget.widget(1)
        self.tabWidget.removeTab(1)
        w.close()
        return
    
    def mdToEdit(self, path, edit):
        """
        Remplit une instance de QTextEdit avec un fichier Markdown
        :param path: le chemin du fichier .md, relatif à ce fichier source.
        :type  path: str
        :param edit: le widget d'affichage
        :type  edit: QTextEdit
        """
        path=os.path.join(self.wd, path)
        html=io.BytesIO()
        markdownFromFile(input=path, output=html)
        html.seek(0)
        edit.setHtml(html.read().decode("utf-8"))
        return        

    def initHelpTab(self):
        """
        Met en place le fichier d'aide dans le bon onglet
        """
        self.mdToEdit(self.tr("HelpDiskTab.md"), self.textEdit)
        return
    
    def initAbout(self):
        """
        Remplit le dialogue "À propos" avec un texte localisé
        """
        self.mdToEdit(self.tr("HelpAbout.md"), self.about.ui.textEdit)
        return
    
    def showHelp(self):
        """
        Montre l'aide intégrée
        """
        self.about.show()
        self.tabWidget.setCurrentIndex(0) # ensure the help tab is visible
        return

    def cloneAction(self, event):
        """
        Fonction de rappel pour self.ui.toolsButtoncloneButton ; sert à cloner
        les disques
        """
        wiz=DiskinstallWizard(self)
        wiz.exec_()
        return
        
    def monitor_finished(self, monitor):
        """
        Fonction de rappel pour quand un monitor a fini son job.
        """
        t=self.tableWidget
        t.setItem(monitor.rindex,3,
                  MyItem(self.tr("Clone ready ... Tab #{0}").format(monitor.index)))
        t.resizeColumnsToContents()
        return

    def new_monitor(self, monitor):
        """
        Fonction de rappel pour quand un nouveau moniteur devient prêt
        :param monitor: le nouveau moniteur
        :type  monitor: Monitor
        """
        self.update_monitored_row(monitor)
        return
        
    def monitor_closed(self, monitor):
        """
        Fonction de rappel quand un moniteur est refermé
        :param monitor: le nouveau moniteur
        :type  monitor: Monitor
        """
        device = self.monitors.pop(monitor)
        w=self.tabWidget.widget(monitor.index)
        self.tabWidget.removeTab(monitor.index)
        if w: w.close()
        t=self.tableWidget
        t.setItem(monitor.rindex,3,
                  MyItem(self.tr("Tab closed.")))
        t.resizeColumnsToContents()
        return

    def monitor_out(self, monitor, text):
        """
        Callback function when a monitor sends a text which appeared in stdout
        """
        print("out", monitor, text)
        return
    
    def monitor_err(self, monitor, text):
        """
        Callback function when a monitor sends a text which appeared in stderr
        """
        if monitor.category == "clone_monitor":
            msg = monitor.progresstext(text)
            if msg:
                self.update_monitored_row(monitor, msg)
        return
    

    def updateSda(self):
        """
        Fonction de rappel pour inscrire les
        donnés du disque dur
        """
        t=self.tableWidget
        rindex = 0
        rindex=self.makeRow(rindex, "/dev/sda")
        t.resizeColumnsToContents()
        return

    def makeRow(self, rindex, disk):
        """
        Crée une ligne dans la vue table pour un disque
        :param index: numéro de la ligne
        :param disk: l'instance de disque
        :return: une nouvelle valeur pour l'index, augmentée si une ligne a été
        créée.
        """

        def description(partition_ud):
            dev=os.path.basename(partition_ud.path)
            label=partition_ud.label
            label1=label.split(" ")[0]
            if len(label) > 11:
                label=label1[:8]+"..."
            if partition_ud.label:
                return "{}({})".format(dev, label)
            else:
                return dev
            
        t=self.tableWidget
        available = usbDisk2.Available(access="all")
        freeDestktopPaths = available.disks()
        sdaPath = [p for p in freeDestktopPaths if "sda" in p][0]
        partlist = available.parts(sdaPath)
        nextIndex=rindex
        shortDisk=os.path.join("/dev",os.path.basename(disk))
        shortParts=available.parts_summary(sdaPath)
        t.insertRow(rindex)
        t.setItem(rindex,0,MyItem(shortDisk))
        nextIndex=rindex+1
        t.setItem(rindex,1,MyItem(", ".join(shortParts)))
        ## check whether there is still a Monitor with a process for this device
        for m, devicepath in self.monitors.items():
            if shortDisk == os.path.basename(devicepath):
                self.update_monitored_row(m, button)
        return nextIndex

    def update_monitored_row(self, m, msg = ""):
        """
        Quelques trucs à lancer pour la mise à jour d'une ligne de tableau
        si elle est déjà en relation à un quelconque moniteur
        :param m: le nouveau moniteur
        :type  m: Monitor
        :param msg: an extra message (defaults to "")
        """
        t=self.tableWidget
        r=m.rindex
        i=m.index
        t.setItem(
            r, 2,
            MyItem(self.tr("{} ... Tab #{} {}").format(m.actionMessage, i, msg))
        )
        t.resizeColumnsToContents()
        return

