# -*- coding: utf-8 -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
import i_need_py23

"""Des fonctions pour gérer les fichiers temporaires. Les fichiers temporaires
créés par les fonctions de ce module sont automatiquement supprimés à l'arrêt du
programme.
"""

__all__ = ('TempFiles', 'mktemp', 'mktempfile', 'litemp', 'cltemp', 'actemp')

import os, atexit
from os import path

import tempfile
try:
    from tempfile import mkstemp
except ImportError:
    def mkstemp(suffix="", prefix=tempfile.template, dir=None, text=False):
        absfile = tempfile.mktemp(suffix, prefix, dir)
        flags = os.O_RDWR | os.O_CREAT | os.O_EXCL
        flags |= getattr(os, 'O_NOINHERIT', 0)
        flags |= getattr(os, 'O_NOFOLLOW', 0)
        if not text: flags |= getattr(os, 'O_BINARY', 0)
        return os.open(absfile, flags, 0600), absfile
try:
    from threading import local as ThreadingLocal
except ImportError:
    class ThreadingLocal(object): pass


def _mktemp(suffix="", prefix=tempfile.template, dir=None, text=False):
    """Créer un fichier temporaire et retourner (tmpf, tmpfile) où tmpf est un
    file object ouvert en lecture/écriture, et tmpfile le chemin vers le fichier
    temporaire.
    """
    fd, absfile = mkstemp(suffix, prefix, dir, text)
    return os.fdopen(fd, 'w+b'), absfile

class SharedData:
    """Une liste global de fichiers temporaires à supprimer
    """

    tmpfiles = None
    def _init_tmpfiles(self):
        self.tmpfiles = []

    registered = False
    def _register_atexit(self):
        if not self.registered:
            self.registered = True
            atexit.register(self.remove_tmpfiles)

    def __init__(self):
        self._init_tmpfiles()

    def add_tmpfile(self, tmpfile):
        self.tmpfiles.append(tmpfile)
        self._register_atexit()

    def get_last_index(self):
        return len(self.tmpfiles)

    def remove_tmpfiles(self, li=None):
        li = li or 0
        for tmpfile in self.tmpfiles[li:]:
            try:
                if path.exists(tmpfile):
                    os.remove(tmpfile)
            except OSError: pass
        del self.tmpfiles[li:]

class ThreadLocalData(ThreadingLocal, SharedData):
    """Une liste par thread de fichiers temporaires à supprimer
    """
    def __init__(self):
        self._init_tmpfiles()

class TempFiles:
    def __init__(self, local=None):
        if local is None: local = SharedData()
        self.local = local

    def mktemp(self, suffix="", prefix=tempfile.template, dir=None, text=False):
        """Créer un fichier temporaire et retourner (tmpf, tmpfile) où tmpf est un
        file object ouvert en lecture/écriture, et tmpfile le chemin vers le fichier
        temporaire.

        tmpfile est enregistré pour suppression avec cltemp().
        """
        tmpf, tmpfile = _mktemp(suffix, prefix, dir, text)
        self.local.add_tmpfile(tmpfile)
        return tmpf, tmpfile

    def mktempfile(self, suffix="", prefix=tempfile.template, dir=None, text=False):
        """Créer un fichier temporaire et retourner tmpfile, le chemin vers le
        fichier temporaire.

        tmpfile est enregistré pour suppression avec cltemp().
        """
        tmpf, tmpfile = self.mktemp(suffix, prefix, dir, text)
        tmpf.close()
        return tmpfile

    def litemp(self):
        """Retourner le nombre de fichiers temporaires enregistrés pour
        suppression.

        Cette information peut être utilisée par cltemp() pour indiquer à
        partir de quel index il faut supprimer les fichiers temporaires.
        """
        return self.local.get_last_index()

    def cltemp(self, li=0):
        """Supprimer les fichiers temporaires enregistrés à partir de l'index li.
        """
        self.local.remove_tmpfiles(li)

    def actemp(self, tmpfile):
        """Enregistrer un fichier pour suppression avec cltemp().

        @return: la valeur de litemp() avant l'enregistrement du fichier
        tmpfile.
        """
        li = self.litemp()
        self.local.add_tmpfile(path.abspath(tmpfile))
        return li

TEMP_FILES = TempFiles(ThreadLocalData())

def mktemp(suffix="", prefix=tempfile.template, dir=None, text=False):
    """Créer un fichier temporaire et l'enregistrer dans la liste des fichiers
    temporaires à supprimer pour le thread courant.
    """
    return TEMP_FILES.mktemp(suffix, prefix, dir, text)

def mktempfile(suffix="", prefix=tempfile.template, dir=None, text=False):
    """Créer un fichier temporaire et l'enregistrer dans la liste des fichiers
    temporaires à supprimer pour le thread courant.
    """
    return TEMP_FILES.mktempfile(suffix, prefix, dir, text)

def litemp():
    """Retourner le nombre de fichiers temporaires à supprimer pour le thread courant.
    """
    return TEMP_FILES.litemp()

def cltemp(li=0):
    """Supprimer les fichiers temporaires enregistrés pour le thread courant à
    partir de l'index li.
    """
    return TEMP_FILES.cltemp(li)

def actemp(tmpfile):
    """Ajouter un nom de fichier à la liste des fichiers à supprimer
    automatiquement pour le thread courant.
    """
    return TEMP_FILES.actemp(tmpfile)
