import psLibSwig as psLib
import sys

def logcntl(what = "NM"):
    """Control logging; disable if what == \"\""""
    
    if what == "":
        psLib.psLogSetDestination("none")   # turn off logging
    else:
        psLib.psLogSetDestination("dest:stderr")
        psLib.psLogSetFormat(what)

logcntl("NM")

class PsError(StandardError):
    """An error signalled via a call to psError"""

def raisePsError(clear = True):
    """Raise the most recently signalled psError (the psError stack is cleared if clear is True)"""
    
    err = psLib.psErrorLast()
    if err.code != 0:
        if clear:                       # clear the error?
            psLib.psErrorClear()
        raise PsError, "psError was called without an error return: (%s) %s" % (err.name, err.msg)

def errStack():
    """Print the current error stack"""
    
    i = 0;
    while 1:
        err = psLib.psErrorGetForSwig(i)
        if err == None :
            return
        
        errString = psLib.psErrorCodeString(err.code)
        if not errString:
            errString = "(unknown code: %d)" % err.code
        print "%s\t%-40s %s" %(err.name, errString + ':', err.msg)
        i += 1

def printMD(meta, match=None, file=sys.stdout, hdr=""):
    """Print a set of psMetadata"""

    for i in range(0,meta.list.size):
        md = psLib.psMetadataGet(meta, i)

        if md.type == psLib.PS_META_STR:
            fmt = "%s"
        elif md.type == psLib.PS_META_S32:
            fmt = "%d"
        elif md.type == psLib.PS_META_F32 or md.type == psLib.PS_META_F64:
            fmt = "%g"
        psLib.psMetadataItemPrint(file, md.name + " " + fmt + "\n", md)

def memCheckLeaks(fd = None, id0 = 0, getList = 0, unique = 0, addresses = 0, persistent = False):
    """Check for memory leaks.

    If file (an fd or a filename) is provided, write the list of
    leaked pointers to it.  If id0 is specified, only check for leaked
    memory allocated after that memory id. 

    If getList is true, return a list of tuples for each leaked block:
        (isMagic0, id, file, lineNo, refCounter, isMagic)

    If unique is true, print/return a list of places where memory is leaking, along with
    the number of pointers leaked at each point.  If addresses is true, include the addresses
    of the pointers
    """

    if (unique and addresses):
        raise "Please choose unique _or_ addresses"

    if isinstance(fd, str):
        fd = file(fd, "w")

    if addresses or getList or unique:
        arr = []
    else:
        arr = None

    if addresses or unique:
        nleak = psLib.psMemCheckLeaks(id0, arr, None, persistent)
    else:
        nleak = psLib.psMemCheckLeaks(id0, arr, fd, persistent)

    if fd == None and not (addresses or unique):
        if nleak == 0:
            print "No leaks"
        else:
            print "%d leaked pointers" % (nleak)

    if addresses or unique:
        un = {}
        for el in arr:
            if addresses:
                key = "%s:%d:%d" % (el[2], el[3], el[6])
                un[key] = el[1]
            else:
                key = "%s:%d:" % (el[2], el[3])

                if un.get(key):
                    un[key] += 1
                else:
                    un[key] = 1

        keys = un.keys()

        if unique:
            def cmpKeys(a,b):               # sort keys by file then linenumber
                a=a.split(':')
                b=b.split(':')
                c= cmp(a[0],b[0])
                if c:
                    return c
                else:
                    return int(a[1]) - int(b[1])
        else:
            def cmpKeys(a,b):               # sort keys by ID
                return un[a] - un[b]

        keys.sort(cmpKeys)

        arr = []
        for el in keys:
            arr.append((el, un[el]))

        if fd == None and not getList:
            fd = sys.stdout

        if fd != None:
            if len(arr) == 0:
                fd.write("No leaks\n")
            else:
                if unique:
                    fd.write("%-20s Nptr\n" % "file:line")
                    for el in arr:
                        fd.write("%-20s %d\n" % el)
                else:
                    fd.write("%-15s %4s   %-10s   ID\n" % ("file", "line", "ADDR"))
                    for el in arr:
                        el = el[0].split(":") + [el[1]]
                        fd.write("%-15s %4s   0x%08x   %d\n" % (el[0], el[1], int(el[2]), el[3]))

    try:
        if fd != sys.stderr and fd != sys.stdout:
            fd.close();
    except: pass

    if getList:
        return arr
