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

"""Fonctions utilitaires diverses
"""

__all__ = (
    'isnum',
    'istrue', 'isfalse',
    'isseq', 'seqof', 'listof', 'ulistof',
    'flattenstr', 'flattenseq',
    'qshell',
    'withpath', 'cwithpath', 'find_in_path', 'relpath',
)

from os import path

def isnum(v):
    return isinstance(v, int) or isinstance(v, long)

def istrue(b):
    s = str(b).lower()
    if s in ('true', 'vrai', 'yes', 'oui', '1'):
        return True
    elif s in ('false', 'faux', 'no', 'non', '0'):
        return False
    else:
        return bool(b) # laisser python décider de la valeur

def isfalse(b):
    s = str(b).lower()
    if s in ('true', 'vrai', 'yes', 'oui', '1'):
        return False
    elif s in ('false', 'faux', 'no', 'non', '0'):
        return True
    else:
        return not bool(b) # laisser python décider de la valeur

def isseq(t):
    """Tester si t est une séquence
    """
    return isinstance(t, list) or isinstance(t, tuple) or isinstance(t, set)

_SEQOF_UNDEF = object()
def seqof(o, noneValue=_SEQOF_UNDEF):
    """Retourner un tuple à parti de o
    * si o est une séquence, retourner tuple(o)
    * si noneValue est défini, et que o is noneValue, retourner noneValue
    * sinon, retourner le tuple (o,)
    """
    if isseq(o): return tuple(o)
    elif o is noneValue and noneValue is not _SEQOF_UNDEF: return noneValue
    else: return (o,)

_LISTOF_UNDEF = object()
def listof(o, noneValue=_LISTOF_UNDEF):
    """Retourner une nouvelle liste à parti de o
    * si o est une séquence, retourner list(o)
    * si noneValue est défini, et que o is noneValue, retourner noneValue
    * sinon, retourner la liste [o]
    """
    if isseq(o): return list(o)
    elif o is noneValue and noneValue is not _LISTOF_UNDEF: return noneValue
    else: return [o]

def ulistof(o, noneValue=_LISTOF_UNDEF):
    """Retourner une nouvelle liste à parti de o
    * si o est une séquence, retourner list(o)
    * si noneValue est défini, et que o is noneValue, retourner noneValue
    * sinon, retourner la liste [o]

    La différence avec listof(), c'est que les doublons sont supprimés de la
    liste, tout en préservant l'ordre original, ce qui n'est pas le cas avec
    set()
    """
    if isseq(o): tmplist = list(o)
    elif o is noneValue and noneValue is not _LISTOF_UNDEF: return noneValue
    else: return [o]
    ulist = []
    for item in tmplist:
        if item not in ulist: ulist.append(item)
    return ulist

def flattenstr(src, unique=True, clean=True, sep=','):
    """découper chaque élément du tableau src selon sep et les aplatir dans une
    seule liste.

    Si unique==True, supprimer les doublons.
    Si clean==True, supprimer les valeurs vides et les espaces périphériques

    e.g flattenstr(['a , b', 'c,']) --> ['a', 'b', 'c']
    """
    if src is None: return None
    dest = []
    for items in seqof(src):
        items = items.split(sep)
        if clean: items = filter(None, map(lambda item: item.strip(), items))
        if unique:
            for item in items:
                if item not in dest: dest.append(item)
        else:
            dest.extend(items)
    return dest

def flattenseq(seq):
    """aplatir les éléments de seq en une seule liste

    e.g flattenlist([(1, 2), (3, 4), 5]) --> [1, 2, 3, 4, 5]
    """
    if seq is None: return None
    if not isseq(seq): return [seq]
    items = []
    for item in seq:
        if isseq(item): items.extend(item)
        else: items.append(item)
    return items

def qshell(values):
    if isseq(values): return map(qshell, values)
    elif not values: return ''
    else: return "'%s'" % values.replace("'", "'\\''")

def withpath(p): return p is not None and '/' in p
def cwithpath(p): return p is not None and ('/' in p or p in ('.', '..'))

def find_in_path(filename, dirs, allow_path=False):
    """chercher le fichier nommé filename dans les répertoires dirs

    si filename est un chemin (contient le caractère '/' ou path.sep) alors la
    valeur est retournée telle quelle, sauf si allow_path=True

    retourner le chemin complet dir/filename si le fichier est trouvé, ou None
    si le fichier ne figure dans aucun des répertoires

    """
    is_path = '/' in filename or path.sep in filename
    if is_path and not allow_path: return filename

    for dir in dirs:
        pf = path.join(dir, filename)
        if path.isfile(pf): return pf
    return None

def relpath(filep, refp, abspath=True):
    """exprimer filep par rapport au répertoire de refp

    si abspath==True, rendre le chemin absolu
    """
    pf = path.join(dirname(refp), filep)
    if abspath: pf = path.abspath(pf)
    return pf
