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

# -----------------------------------------------------------------
# This file is a part of PAMPI project.
# Name:         PAMPI
# Copyright:    (C) 2017-2021 Pascal PETER
# Licence:      GNU General Public Licence version 3
# Website:      http://pascal.peter.free.fr/
# Email:        pascal.peter at free.fr
# -----------------------------------------------------------------
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
# -----------------------------------------------------------------

"""
DESCRIPTION :
    Fonctions de manipulation de fichiers ou dossiers :
    copier, ...
"""

# importation des modules utiles :
from __future__ import division, print_function
import sys
import os
import json

# importation des modules perso :
import utils, utils_functions

# PyQt5 ou PyQt4 :
if utils.PYQT == 'PYQT5':
    from PyQt5 import QtCore, QtGui
else:
    from PyQt4 import QtCore, QtGui



"""
****************************************************
    CONFIGURATION
****************************************************
"""

def createTempAppDir(PROGLINK, mustReCreate=True):
    """
    (re)création du dossier temporaire
    on cree un sous-dossier /tmp/PROGLINK
    à améliorer avec tests sous windob
    """
    tempDir = QtCore.QDir.temp()
    if mustReCreate:
        emptyDir(QtCore.QDir.tempPath() + '/' + PROGLINK)
        tempDir.rmdir(PROGLINK)
    tempAppDir = QtCore.QDir(QtCore.QDir.tempPath() + '/' + PROGLINK + '/')
    if tempAppDir.exists():
        tempAppPath = tempAppDir.path()
    elif tempDir.mkdir(PROGLINK):
        tempAppPath = QtCore.QDir(QtCore.QDir.tempPath() + '/' + PROGLINK + '/').path()
    else:
        utils_functions.myPrint('tempAppDir sera temp')
        tempAppPath = QtCore.QDir.tempPath()
    return tempAppPath

def createConfigAppDir(PROGLINK):
    """
    Crée un sous dossier ".PROGLINK" dans le home (dossier utilisateur)
    (ou un dossier PROGLINK dans home/.config)
    Ce sera le dossier de configuration du logiciel
    """
    first = False
    progLink = '.' + PROGLINK
    # récupération du dossier home:
    if sys.platform == 'win32':
        # home on win32 is broken
        if 'APPDATA' in os.environ:
            winAppDataDir = os.environ['APPDATA']
        else:
            winAppDataDir = QtCore.QDir.homePath()
        if utils.MODEBAVARD:
            utils_functions.myPrint('winAppDataDir: ', winAppDataDir)
        homeDir = QtCore.QDir(winAppDataDir)
        homeDirPath = QtCore.QDir(winAppDataDir).path()
    else:
        homeDir = QtCore.QDir.home()
        homeDirPath = QtCore.QDir.home().path()
        # test de la présence d'un dossier .config :
        pConfigPath = homeDirPath + '/.config/'
        if QtCore.QDir(pConfigPath).exists():
            # s'il y a un home/.PROGLINK, on le déplace dans .config (en supprimant le .) :
            pProgLinkPath = homeDirPath + '/.' + PROGLINK + '/'
            if QtCore.QDir(pProgLinkPath).exists():
                if not(QtCore.QDir(pConfigPath + PROGLINK).exists()):
                    QtCore.QDir(pConfigPath).mkdir(PROGLINK)
                copyDir(pProgLinkPath, pConfigPath + PROGLINK)
                emptyDir(pProgLinkPath)
            progLink = PROGLINK
            homeDirPath = homeDirPath + '/.config'

    # création du dossier config dans le home:
    configAppDir = QtCore.QDir(homeDirPath + '/' + progLink + '/')
    if not(configAppDir.exists()):
        first = True
        QtCore.QDir(homeDirPath).mkdir(progLink)
        configAppDir = QtCore.QDir(homeDirPath + '/' + progLink + '/')
    return configAppDir, first

def deleteLockFile():
    LOCKFILENAME = QtCore.QDir.tempPath() + '/verac_lock'
    if QtCore.QFile(LOCKFILENAME).exists():
        removeOK = QtCore.QFile(LOCKFILENAME).remove()
        if not(removeOK):
            utils_functions.myPrint('REMOVE ERROR : ', LOCKFILENAME)

def readConfigFile(configDir):
    """
    on lit le fichier de config
    """
    configDict = {}
    configFileName = utils_functions.u(
        '{0}/config.json').format(configDir.canonicalPath())
    try:
        if QtCore.QFile(configFileName).exists():
            if utils.PYTHONVERSION >= 30:
                configFile = open(
                    configFileName, newline='', encoding='utf-8')
            else:
                configFile = open(
                    configFileName, 'rb')
            configDict = json.load(configFile)
            configFile.close()
    except:
        configDict = {}
    # récupération ou initialisation des valeurs :
    for key in utils.DEFAULTCONFIG:
        if not(key in configDict):
            configDict[key] = utils.DEFAULTCONFIG[key]
    for key in utils.DEFAULTCONFIG['OTHER']:
        if not(key in configDict['OTHER']):
            configDict['OTHER'][key] = utils.DEFAULTCONFIG['OTHER'][key]
    return configDict

def writeConfigFile(configDir, configDict, presentationsDir):
    """
    on écrit le fichier de config
    """
    configFileName = utils_functions.u(
        '{0}/config.json').format(configDir.canonicalPath())
    if utils.PYTHONVERSION >= 30:
        configFile = open(
            configFileName, 'w', encoding='utf-8')
    else:
        configFile = open(
            configFileName, 'wb')
    # on ne garde que 10 fichiers :
    configDict['LASTFILES'] = configDict['LASTFILES'][:10]
    configDict['OTHER']['presentationsDir'] = presentationsDir
    json.dump(configDict, configFile, indent=4)
    configFile.close()




"""
****************************************************
    FICHIERS ET DOSSIERS (COPIE, ETC)
****************************************************
"""

def openFile(fileName):
    localefileFile = QtCore.QFileInfo(fileName)
    localefileFile.makeAbsolute()
    thefile = localefileFile.filePath()
    url = QtCore.QUrl.fromLocalFile(utils_functions.u(thefile))
    QtGui.QDesktopServices.openUrl(url)

def openDir(dirName):
    """
    Sous Windobs, ça ne marche qu'avec des ~1 partout
    Comme quoi Dos existe encore...
    Pas sùr que ça marche à tous les coups.
    """
    try:
        dirName = utils_functions.u(dirName)
        url = QtCore.QUrl().fromLocalFile(dirName)
        QtGui.QDesktopServices.openUrl(url)
    except:
        if utils.OS_NAME[0] == 'win':
            dirName = os.sep.join(dirName.split('/'))
            dirName = utils_functions.u(dirName)
            commandLine = utils_functions.u('explorer "{0}"').format(dirName)
            os.system(commandLine)

def copyDir(src, dst, ignore=()):
    """
    copie récursive d'un dossier dans un autre
    """
    src = utils_functions.addSlash(src)
    dst = utils_functions.addSlash(dst)
    if utils.MODEBAVARD:
        utils_functions.myPrint('copyDir :', src, dst)
    has_err = False
    srcDir = QtCore.QDir(src)
    dstDir = QtCore.QDir(dst)
    if srcDir.exists():
        entries = srcDir.entryInfoList(
            QtCore.QDir.NoDotAndDotDot | QtCore.QDir.Dirs | QtCore.QDir.Files | QtCore.QDir.Hidden)
        for entryInfo in entries:
            name = entryInfo.fileName()
            path = entryInfo.absoluteFilePath()
            if entryInfo.isDir():
                if not(name in ignore):
                    dstDir.mkdir(name)
                    # on fait suivre :
                    has_err = copyDir(
                        utils_functions.u('{0}{1}').format(src, name), 
                        utils_functions.u('{0}{1}').format(dst, name), 
                        ignore=ignore)
            elif entryInfo.isFile():
                if not(name in ignore):
                    if utils.MODEBAVARD:
                        utils_functions.myPrint('copy: ', name)
                    srcFileName = utils_functions.u('{0}{1}').format(src, name)
                    dstFileName = utils_functions.u('{0}{1}').format(dst, name)
                    if QtCore.QFile(dstFileName).exists():
                        QtCore.QFile(dstFileName).remove()
                    QtCore.QFile(srcFileName).copy(dstFileName)
    return has_err

def removeAndCopy(sourceFile, destFile, testSize=-1):
    if testSize > 0:
        sourceSize = QtCore.QFileInfo(sourceFile).size()
        if sourceSize < testSize:
            utils_functions.myPrint(
                'TEST SIZE : ', sourceFile, sourceSize)
            return False
    if QtCore.QFile(destFile).exists():
        removeOK = QtCore.QFile(destFile).remove()
        if not(removeOK):
            utils_functions.myPrint('REMOVE ERROR : ', destFile)
    copyOK = QtCore.QFile(sourceFile).copy(destFile)
    if not(copyOK):
        utils_functions.myPrint('COPY ERROR : ', sourceFile, destFile)
    return copyOK

def copyFile(actualPath, newPath, actualFile, srcbackup):
    src = srcbackup + actualPath + '/' + actualFile
    dst = newPath + '/' + actualFile
    if QtCore.QFileInfo(src).isDir():
        if not(QtCore.QDir(dst).exists()):
            QtCore.QDir(newPath).mkdir(actualFile)
    elif QtCore.QFileInfo(src).isFile():
        if not(QtCore.QFile(dst).exists()):
            QtCore.QFile(src).copy(dst)

def emptyDir(dirName, deleteThisDir=True, filesToKeep=[]):
    """
    Vidage récursif d'un dossier.
    Si deleteThisDir est mis à False, le dossier lui-même n'est pas supprimé.
    filesToKeep est une liste de noms de fichiers à ne pas effacer
        (filesToKeep=['.htaccess'] par exemple).
    """
    if utils.MODEBAVARD:
        utils_functions.myPrint('emptyDir ', dirName)
    has_err = False
    aDir = QtCore.QDir(dirName)
    if aDir.exists():
        entries = aDir.entryInfoList(
            QtCore.QDir.NoDotAndDotDot | QtCore.QDir.Dirs | QtCore.QDir.Files | QtCore.QDir.Hidden)
        for entryInfo in entries:
            path = entryInfo.absoluteFilePath()
            if entryInfo.isDir():
                # on fait suivre filesToKeep, mais deleteThisDir sera True :
                has_err = emptyDir(path, filesToKeep=filesToKeep)
            elif entryInfo.isFile():
                if not(entryInfo.fileName() in filesToKeep):
                    f = QtCore.QFile(path)
                    if f.exists():
                        if not(f.remove()):
                            utils_functions.myPrint("PB: ", path)
                            has_err = True
        if deleteThisDir:
            if not(aDir.rmdir(aDir.absolutePath())):
                utils_functions.myPrint("Erreur de suppression de : " + aDir.absolutePath())
                has_err = True
    return has_err

def createDirs(inPath, newPaths):
    """
    création de sous-dossiers (newPaths) dans un dossier (inPath)
    newPaths peut contenir plusieurs dossiers à créer
    Par exemple, createDirs(inPath, utils_functions.u('abé/ééc'))
    """
    if newPaths.split('/')[0] != '':
        a, b = newPaths.split('/')[0], '/'.join(newPaths.split('/')[1:])
    else:
        a, b = newPaths.split('/')[1], '/'.join(newPaths.split('/')[2:])
    if a != '':
        inDir = QtCore.QDir(inPath)
        a = utils_functions.u(a)
        newDir = QtCore.QDir(inPath + '/' + a)
        if not(newDir.exists()):
            if utils.MODEBAVARD:
                utils_functions.myPrint('create ', inPath + '/' + a)
            inDir.mkdir(a)
        if b != '':
            createDirs(inPath + '/' + a, b)




"""
****************************************************
    DIVERS
****************************************************
"""

def readTextFile(fileName):
    """
    retourne le contenu d'un fichier texte.
    fileContent = utils_filesdirs.readTextFile(fileName)
    """
    result = ''
    inFile = QtCore.QFile(fileName)
    if inFile.open(QtCore.QFile.ReadOnly | QtCore.QFile.Text):
        stream = QtCore.QTextStream(inFile)
        stream.setCodec('UTF-8')
        result = stream.readAll()
        inFile.close()
    return result

def writeTextFile(fileName, lines):
    """
    retourne le contenu d'un fichier texte.
    utils_filesdirs.writeTextFile(fileName, lines)
    """
    result = False
    QtCore.QFile(fileName).remove()
    outFile = QtCore.QFile(fileName)
    if outFile.open(QtCore.QFile.WriteOnly | QtCore.QFile.Text):
        stream = QtCore.QTextStream(outFile)
        stream.setCodec('UTF-8')
        stream << lines
        outFile.close()
        result = True
    return result

def createLinuxDesktopFile(main, beginDir, directory, progName, iconName, progFile=''):
    """
    création du fichier progName.desktop
    """
    # on ouvre le fichier livré avec l'archive :
    desktopFileName = utils_functions.u('{0}/files/{1}.desktop').format(
        beginDir, progName)
    desktopFile = QtCore.QFile(desktopFileName)
    if not(desktopFile.open(QtCore.QFile.ReadOnly | QtCore.QFile.Text)):
        return False
    stream = QtCore.QTextStream(desktopFile)
    stream.setCodec('UTF-8')
    lines = stream.readAll()
    # on remplace les variables :
    lines = lines.replace('PYTHON', utils_functions.u(sys.executable))
    lines = lines.replace('CHEMIN', utils_functions.u(beginDir))
    lines = lines.replace('PROGNAME', progName)
    lines = lines.replace('PROGFILE', progFile)
    lines = lines.replace('ICON', iconName)
    desktopFile.close()
    # on crée le fichier final :
    desktopFileName = utils_functions.u('{0}/{1}.desktop').format(
        directory, progName)
    QtCore.QFile(desktopFileName).remove()
    desktopFile = QtCore.QFile(desktopFileName)
    if desktopFile.open(QtCore.QFile.WriteOnly | QtCore.QFile.Text):
        stream = QtCore.QTextStream(desktopFile)
        stream.setCodec('UTF-8')
        stream << lines
        desktopFile.close()
    # avec les bons attributs :
    QtCore.QFile(desktopFileName).setPermissions(\
        QtCore.QFile(desktopFileName).permissions() | \
        QtCore.QFile.ExeOwner | \
        QtCore.QFile.ExeUser | \
        QtCore.QFile.ExeGroup | \
        QtCore.QFile.ExeOther)
    # on le copie aussi dans ~/.local/share/applications :
    applicationsPath = QtCore.QDir.homePath() + '/.local/share/applications'
    if QtCore.QDir(applicationsPath).exists():
        desktopFileName2 = utils_functions.u('{0}/{1}.desktop').format(
            applicationsPath, progName)
        QtCore.QFile(desktopFileName2).remove()
        QtCore.QFile(desktopFileName).copy(desktopFileName2)
    return True

def md2html(main, mdFile, template='default', replace=False):
    """
    retourne un fichier html d'après un fichier md (markdown).
    Les dossiers main.beginDir et main.tempPath
    doivent être définis.
    """
    # fichier final :
    outFileName = utils_functions.u(
        '{0}/md/{1}.html').format(
            main.tempPath, 
            QtCore.QFileInfo(mdFile).baseName())
    # s'il existe déjà, rien à faire de plus :
    if QtCore.QFileInfo(outFileName).exists():
        if not(replace):
            return outFileName
    # fichier du modèle html à utiliser :
    templateFile = utils_functions.u(
        '{0}/md/{1}.html').format(main.tempPath, template)
    # si on ne l'a pas trouvé, c'est qu'on lance pour la première fois.
    # on recopie alors le dossier md dans temp :
    if not(QtCore.QFileInfo(templateFile).exists()):
        createDirs(main.tempPath, 'md')
        scrDir = main.beginDir + '/files/md'
        destDir = main.tempPath + '/md'
        copyDir(scrDir, destDir)
    # récupération du contenu du modèle html :
    htmlLines = readTextFile(templateFile)
    # récupération du fichier Markdown :
    mdLines = readTextFile(mdFile)
    # on met en forme et on remplace le repère du modèle :
    mdLines = mdLines.replace('\n', '\\n').replace("'", "\\'")
    htmlLines = htmlLines.replace('# USER TEXT', mdLines)
    # on enregistre le nouveau fichier html :
    writeTextFile(outFileName, htmlLines)
    return outFileName


