# -*- coding: utf-8 -*-

# Copyright (c) 2014 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing the shelve extension interface.
"""


import os

from PyQt5.QtCore import QProcess
from PyQt5.QtWidgets import QDialog

from E5Gui import E5MessageBox

from ..HgExtension import HgExtension
from ..HgDialog import HgDialog


class Shelve(HgExtension):
    """
    Class implementing the shelve extension interface.
    """
    def __init__(self, vcs):
        """
        Constructor
        
        @param vcs reference to the Mercurial vcs object
        """
        super(Shelve, self).__init__(vcs)
        
        self.__unshelveKeep = False
        
        self.__shelveBrowserDialog = None
    
    def shutdown(self):
        """
        Public method used to shutdown the shelve interface.
        """
        if self.__shelveBrowserDialog is not None:
            self.__shelveBrowserDialog.close()
    
    def __hgGetShelveNamesList(self, repodir):
        """
        Private method to get the list of shelved changes.
        
        @param repodir directory name of the repository (string)
        @return list of shelved changes (list of string)
        """
        args = self.vcs.initCommand("shelve")
        args.append('--list')
        args.append('--quiet')
        
        client = self.vcs.getClient()
        output = ""
        if client:
            output = client.runcommand(args)[0]
        else:
            process = QProcess()
            process.setWorkingDirectory(repodir)
            process.start('hg', args)
            procStarted = process.waitForStarted(5000)
            if procStarted:
                finished = process.waitForFinished(30000)
                if finished and process.exitCode() == 0:
                    output = str(process.readAllStandardOutput(),
                                 self.vcs.getEncoding(), 'replace')
        
        shelveNamesList = []
        for line in output.splitlines():
            shelveNamesList.append(line.strip())
        
        return shelveNamesList[:]
    
    def hgShelve(self, name):
        """
        Public method to shelve current changes of files or directories.
        
        @param name directory or file name (string) or list of directory
            or file names (list of string)
        @return flag indicating that the project should be reread (boolean)
        """
        if isinstance(name, list):
            dname = self.vcs.splitPathList(name)[0]
        else:
            dname = self.vcs.splitPath(name)[0]
        
        # find the root of the repo
        repodir = dname
        while not os.path.isdir(os.path.join(repodir, self.vcs.adminDir)):
            repodir = os.path.dirname(repodir)
            if os.path.splitdrive(repodir)[1] == os.sep:
                return False
        
        res = False
        from .HgShelveDataDialog import HgShelveDataDialog
        dlg = HgShelveDataDialog(self.vcs.version)
        if dlg.exec_() == QDialog.Accepted:
            shelveName, dateTime, message, addRemove, keep = dlg.getData()
            
            args = self.vcs.initCommand("shelve")
            if shelveName:
                args.append("--name")
                args.append(shelveName)
            if message:
                args.append("--message")
                args.append(message)
            if addRemove:
                args.append("--addRemove")
            if dateTime.isValid():
                args.append("--date")
                args.append(dateTime.toString("yyyy-MM-dd hh:mm:ss"))
            if self.vcs.version >= (5, 0, 0) and keep:
                args.append("--keep")
            args.append("-v")
            
            if isinstance(name, list):
                self.vcs.addArguments(args, name)
            else:
                args.append(name)
            
            dia = HgDialog(self.tr('Shelve current changes'), self.vcs)
            res = dia.startProcess(args, repodir)
            if res:
                dia.exec_()
                res = dia.hasAddOrDelete()
                self.vcs.checkVCSStatus()
        return res
    
    def hgShelveBrowser(self, projectDir):
        """
        Public method to show the shelve browser dialog.
        
        @param projectDir name of the project directory (string)
        """
        if self.__shelveBrowserDialog is None:
            from .HgShelveBrowserDialog import HgShelveBrowserDialog
            self.__shelveBrowserDialog = HgShelveBrowserDialog(
                self.vcs)
        self.__shelveBrowserDialog.show()
        self.__shelveBrowserDialog.start(projectDir)
    
    def hgUnshelve(self, name, shelveName=""):
        """
        Public method to restore shelved changes to the project directory.
        
        @param name name of the project directory (string)
        @keyparam shelveName name of the shelve to restore (string)
        @return flag indicating that the project should be reread (boolean)
        """
        # find the root of the repo
        repodir = name
        while not os.path.isdir(os.path.join(repodir, self.vcs.adminDir)):
            repodir = os.path.dirname(repodir)
            if os.path.splitdrive(repodir)[1] == os.sep:
                return False
        
        res = False
        from .HgUnshelveDataDialog import HgUnshelveDataDialog
        dlg = HgUnshelveDataDialog(self.__hgGetShelveNamesList(repodir),
                                   shelveName=shelveName)
        if dlg.exec_() == QDialog.Accepted:
            shelveName, keep = dlg.getData()
            self.__unshelveKeep = keep  # store for potential continue
            
            args = self.vcs.initCommand("unshelve")
            if keep:
                args.append("--keep")
            if shelveName:
                args.append(shelveName)
            
            dia = HgDialog(self.tr('Restore shelved changes'), self.vcs)
            res = dia.startProcess(args, repodir)
            if res:
                dia.exec_()
                res = dia.hasAddOrDelete()
                self.vcs.checkVCSStatus()
        return res
    
    def hgUnshelveAbort(self, name):
        """
        Public method to abort the ongoing restore operation.
        
        @param name name of the project directory (string)
        @return flag indicating that the project should be reread (boolean)
        """
        # find the root of the repo
        repodir = name
        while not os.path.isdir(os.path.join(repodir, self.vcs.adminDir)):
            repodir = os.path.dirname(repodir)
            if os.path.splitdrive(repodir)[1] == os.sep:
                return False
        
        args = self.vcs.initCommand("unshelve")
        args.append("--abort")
        
        dia = HgDialog(self.tr('Abort restore operation'), self.vcs)
        res = dia.startProcess(args, repodir)
        if res:
            dia.exec_()
            res = dia.hasAddOrDelete()
            self.vcs.checkVCSStatus()
        return res
    
    def hgUnshelveContinue(self, name):
        """
        Public method to continue the ongoing restore operation.
        
        @param name name of the project directory (string)
        @return flag indicating that the project should be reread (boolean)
        """
        # find the root of the repo
        repodir = name
        while not os.path.isdir(os.path.join(repodir, self.vcs.adminDir)):
            repodir = os.path.dirname(repodir)
            if os.path.splitdrive(repodir)[1] == os.sep:
                return False
        
        args = self.vcs.initCommand("unshelve")
        if self.__unshelveKeep:
            args.append("--keep")
        args.append("--continue")
        
        dia = HgDialog(self.tr('Continue restore operation'), self.vcs)
        res = dia.startProcess(args, repodir)
        if res:
            dia.exec_()
            res = dia.hasAddOrDelete()
            self.vcs.checkVCSStatus()
        return res
    
    def hgDeleteShelves(self, name, shelveNames=None):
        """
        Public method to delete named shelves.
        
        @param name name of the project directory (string)
        @param shelveNames name of shelves to delete (list of string)
        """
        # find the root of the repo
        repodir = name
        while not os.path.isdir(os.path.join(repodir, self.vcs.adminDir)):
            repodir = os.path.dirname(repodir)
            if os.path.splitdrive(repodir)[1] == os.sep:
                return
        
        if not shelveNames:
            from .HgShelvesSelectionDialog import HgShelvesSelectionDialog
            dlg = HgShelvesSelectionDialog(
                self.tr("Select the shelves to be deleted:"),
                self.__hgGetShelveNamesList(repodir))
            if dlg.exec_() == QDialog.Accepted:
                shelveNames = dlg.getSelectedShelves()
            else:
                return
        
        from UI.DeleteFilesConfirmationDialog import (
            DeleteFilesConfirmationDialog
        )
        dlg = DeleteFilesConfirmationDialog(
            None,
            self.tr("Delete shelves"),
            self.tr("Do you really want to delete these shelves?"),
            shelveNames)
        if dlg.exec_() == QDialog.Accepted:
            args = self.vcs.initCommand("shelve")
            args.append("--delete")
            args.extend(shelveNames)
            
            dia = HgDialog(self.tr('Delete shelves'), self.vcs)
            res = dia.startProcess(args, repodir)
            if res:
                dia.exec_()
    
    def hgCleanupShelves(self, name):
        """
        Public method to delete all shelves.
        
        @param name name of the project directory (string)
        """
        # find the root of the repo
        repodir = name
        while not os.path.isdir(os.path.join(repodir, self.vcs.adminDir)):
            repodir = os.path.dirname(repodir)
            if os.path.splitdrive(repodir)[1] == os.sep:
                return
        
        res = E5MessageBox.yesNo(
            None,
            self.tr("Delete all shelves"),
            self.tr("""Do you really want to delete all shelved changes?"""))
        if res:
            args = self.vcs.initCommand("shelve")
            args.append("--cleanup")
            
            dia = HgDialog(self.tr('Delete all shelves'), self.vcs)
            res = dia.startProcess(args, repodir)
            if res:
                dia.exec_()
