#!/usr/bin/python

import sys, getopt, os, os.path, fnmatch, string, StringIO

#---------- globals ----------

FALSE     = 0
TRUE      = not FALSE

ops       = ['tr', 'qtNoTr', 'shpix', 'notify', 'varhier', 'appQuit', "kjsfix", "fixQVariant", "fixSignal"]
operation = ''
opPath    = ''
pattern   = ''


# --------- support functions ----------

def getOptions ():
    global pattern
    arglist = sys.argv [1:]
    shortOptions = "p:o:"
    longOptions  = "path= op="

    try:
        optlist, args = getopt.getopt (arglist, shortOptions, longOptions)
    except getopt.GetoptError:
        optlist = []
        args    = []

    if (optlist == []) or (len (args) != 1):
        print '\nUsage: postproc -p<path> -o<operation> <filespec>\n'
        return FALSE

    pattern = args [0]
    return checkOptions (optlist)

def checkOptions (optlist):
    havePath = FALSE
    haveOp   = FALSE

    for pair in optlist:
        if (pair [0] == '--path') or (pair [0] == '-p'):
            if not checkPath (pair [1]):
                print '\nPath ' + pair [1] + ' does not exist\n'
            else:
                havePath = TRUE

        elif (pair [0] == '--op') or (pair [0] == '-o'):
            if not checkOp (pair [1]):
                print '\nOperation ' + pair [1] + ' does not exist\n'
            else:
                haveOp = TRUE

    return havePath and haveOp

def checkPath (path):
    global opPath
    if not os.path.exists (path):
        return FALSE

    opPath = path
    if not (opPath [-1] == '/'):
        opPath = opPath + '/'

    return TRUE


def checkOp (op):
    global operation
    if not op in ops:
        return FALSE

    operation = op
    return TRUE

def getFilelist ():
    filelist = []
    tmpfilelist = os.listdir (opPath)
    for fn in tmpfilelist:
        if fnmatch.fnmatchcase (fn, pattern):
            filelist.append (fn)

    return filelist

# --------- operations ----------

# removes sipDo_<classname>_tr and table reference ('sipName_qt_tr')
# because KDE2 is compiled with QT_NO_TRANSLATION defined (which also
# makes QObject::tr methods invisible to any KDE2 QObject descendants)

def trFix (filelist):
    for fn in filelist:
        m       = open (opPath + fn, 'r')
        tmpname = os.path.splitext (fn) [0] + '.tmp'
        tmp     = StringIO.StringIO ()

        buff    = m.readlines ()
        m.close ()

        i       = 0
        nLines  = len (buff)

        # skip leading comments
        while (i < nLines) and (buff [i][0:1] == '//'):
            tmp.write (buff [i])
            i = i + 1

        # find classname
        while (i < nLines) and (not string.find (buff [i], 'PyObject *sipClass_') == 0):
            tmp.write (buff [i])
            i = i + 1

        if i >= nLines:     # no classname - don't bother
            tmp.close ()
            continue

        classname = buff [i][19:-2]

        trStr = 'static PyObject *sipDo_' + classname + '_tr(PyObject *sipThisObj,PyObject *sipArgs)\n'

        while (i < nLines) and (buff [i] != trStr):
            tmp.write (buff [i])
            i = i + 1

        if i >= nLines:     # no sipDo_*_tr - done
            tmp.close ()
            continue

        # skip over this method without writing it out
        while (i < nLines) and (buff [i][0] != '}'):
            i = i + 1

        i = i + 1   # skip the '}' too


        while (i < nLines):
            # skip sipName_qt_tr table entry/write out everything else
            if string.find (buff [i], '{sipName_qt_tr') < 0:
                tmp.write (buff [i])
            i = i + 1

        tmpfile = open (opPath + tmpname, 'w')
        tmpfile.write (tmp.getvalue ())
        tmpfile.close ()
        tmp.close ()
        os.unlink (opPath + fn)
        os.rename (opPath + tmpname, opPath + fn)

    return TRUE

def qtNoTr (filelist):
    for fn in filelist:
        m       = open (opPath + fn, 'r')
        tmpname = os.path.splitext (fn) [0] + '.tmp'
        tmp     = StringIO.StringIO ()

        buff    = m.readlines ()
        m.close ()

        i       = 0
        nLines  = len (buff)

        while (i < nLines) and (string.find (buff [i], 'Q_OBJECT') < 0):
            tmp.write (buff [i])
            i = i + 1

        tmp.write ("#define QT_NO_TRANSLATION\n")

        while (i < nLines):
            tmp.write (buff [i])
            i = i + 1

        tmpfile = open (opPath + tmpname, 'w')
        tmpfile.write (tmp.getvalue ())
        tmpfile.close ()
        tmp.close ()
        os.unlink (opPath + fn)
        os.rename (opPath + tmpname, opPath + fn)

    return TRUE

# changes QPaintDevice to KPixmap for two method calls
# gcc reports QPaintDevice as "ambiguous"

def shpix ():
    # if concatenated, the sip*.cpp file doesn't exist
    fn      = ['sipkdeuiKSharedPixmap.cpp']
    if not os.path.exists (os.path.join (opPath, fn [0])):
        files = os.listdir (opPath)
        fn = []
        for file in files:
             if string.find (file, "kdeuipart") >= 0 and file [-4:] == ".cpp":
                fn.append (file)

    if not fn:
        return FALSE

    for file in fn:
        m       = open (os.path.join (opPath, file), 'r')
        tmpname = os.path.splitext (file) [0] + '.tmp'

        buff = m.readlines ()
        m.close ()

        changed = 0
        state = None
        for ln in range (0, len (buff)):
            line = buff [ln]
            if string.find (line, "sipKSharedPixmap::resolution") >= 0:
                state = "res"
            elif string.find (line, "sipKSharedPixmap::setResolution") >= 0:
                state = "setRes"
            else:
                state = None

            if state and changed < 2:
                changed = changed + 1
                while "}" not in line:
                    ln = ln + 1
                    line = buff [ln]
                    if state == "res":
                        buff [ln] = string.replace (line, "QPaintDevice::resolution", "KPixmap::resolution")
                    elif state == "setRes":
                        buff [ln] = string.replace (line, "QPaintDevice::setResolution", "KPixmap::setResolution")

        tmpfile = open (os.path.join (opPath, tmpname), 'w')
        for line in buff:
            tmpfile.write (line)
        tmpfile.close ()
        os.unlink (os.path.join (opPath, file))
        os.rename (os.path.join (opPath, tmpname), os.path.join (opPath, file))

    return TRUE

def notify ():
    fn = os.path.join (opPath, pattern)
    m  = open (fn, "r")
    tmpname = fn + '.tmp'

    buff = m.readlines ()
    m.close ()
    tmpfile = open (tmpname, 'w')

    tmpBuff = []
    flag = 0
    for line in buff:
        if string.find (line, "class KNotify:") >= 0:
            flag = 1

        elif flag == 1 and string.find (line, "class KNotifyWidgetBase(QWidget):") >= 0:
            flag = 2

        elif flag == 2 and string.find (line, "class KNotifyWidget(KNotifyWidgetBase):") >= 0:
            for ln in tmpBuff:
                tmpfile.write (ln)
            flag = 0

        if flag != 1:
            tmpfile.write (line)
        else:
            tmpBuff.append (line)

    tmpfile.close ()
    os.unlink (fn)
    os.rename (tmpname, fn)

    return TRUE

def varhier (filelist):
    for fn in filelist:
        m       = open (opPath + fn, 'r')
        tmpname = os.path.splitext (fn) [0] + '.tmp'
        tmp     = StringIO.StringIO ()

        buff    = m.readlines ()
        m.close ()

        i       = 0
        nLines  = len (buff)

        while (i < nLines) and (string.find (buff [i], 'PyMethodDef *sipClassVarHierTab_') < 0):
            tmp.write (buff [i])
            i = i + 1

        while (i < nLines) and (string.find (buff [i], "};") < 0):
            tmp.write (buff [i])
            i = i + 1

        if i < nLines:
            flag = TRUE
            tmp.write (buff [i] + "\n")
            while i < nLines:
                if not flag:
                    tmp.write (buff [i])

                if flag and not ((string.find (buff [i], "};") >= 0) or (string.find (buff [i], "NULL") >= 0)):
                    flag = FALSE

                i = i + 1

        tmpfile = open (opPath + tmpname, 'w')
        tmpfile.write (tmp.getvalue ())
        tmpfile.close ()
        tmp.close ()
        os.unlink (opPath + fn)
        os.rename (opPath + tmpname, opPath + fn)

    return TRUE


def appQuit (filelist):
    for fn in filelist:
        m       = open (opPath + fn, 'r')
        tmpname = os.path.splitext (fn) [0] + '.tmp'
        tmp     = StringIO.StringIO ()

        buff    = m.readlines ()
        m.close ()

        i       = 0
        nLines  = len (buff)

        while (i < nLines) and (string.find (buff [i], 'import libsip') < 0):
            tmp.write (buff [i])
            i = i + 1

        tmp.write (buff [i] + "\nfrom qt import QCloseEvent")
        i = i + 1

        while (i < nLines) and (string.find (buff [i], "class KApplication") < 0):
            tmp.write (buff [i])
            i = i + 1

        count = 0
        while count < 2:
            while (i < nLines) and (string.find (buff [i], "return") < 0):
                tmp.write (buff [i])
                i = i + 1

            tmp.write (buff [i])
            i = i + 1
            count = count + 1

        tmp.write (\
"""\tdef quit (self):
\t\tk = KApplication.kApplication ()
\t\te = QCloseEvent ()

\t\tfor w in k.topLevelWidgets ():
\t\t\tif w.inherits ("KMainWindow"):
\t\t\t\tk.sendEvent (w, e)
\t\t\t\tif not e.isAccepted ():
\t\t\t\t\treturn

\t\tQApplication.quit (self)
""")

        while (i < nLines):
            tmp.write (buff [i])
            i = i + 1

        tmpfile = open (opPath + tmpname, 'w')
        tmpfile.write (tmp.getvalue ())
        tmpfile.close ()
        tmp.close ()
        os.unlink (opPath + fn)
        os.rename (opPath + tmpname, opPath + fn)

    return True

def fixQVariant ():
    infile = os.path.join (opPath, "sipkdecorecmodule.cpp")
    if not os.path.exists (infile):
        infile = os.path.join (opPath, "sipkdecorepart0.cpp")
        if not os.path.exists (infile):
            return TRUE

    m = open (infile, "r")
    n = open (infile + ".new", "w")
    looking = True
    for line in m:
        if looking and line.find ("sipAPIkdecore.h") > 0:
            n.write (line)
            n.write ('\n#include "sipqtQVariant.h"\n\n')
            looking = False
            continue

        n.write (line)

    m.close ()
    n.close ()
    os.unlink (infile)
    os.rename (infile + ".new", infile)

    return TRUE

def fixSignal (filelist):
    for file in filelist:
        if file [-1] == "h":
            times = 1
        else:
            times = 2

        infile = os.path.join (opPath, file)
        m = open (infile, "r")
        n = open (infile + ".new", "w")

        count = 0
        for line in m:
            if count < times:
                if string.find (line, "proxySlot(unsigned long)") > 0\
                    or string.find (line, "proxySlot(unsigned long a0)") > 0:
                    line = string.replace (line, "unsigned long", "WId")
                    count = count + 1

            n.write (line)

        m.close ()
        n.close ()
        os.unlink (infile)
        os.rename (infile + ".new", infile)

    return TRUE


def kjsfix (filelist):
    for fn in filelist:
        if not os.path.exists (opPath + fn):
            continue
        m       = open (opPath + fn, 'r')
        tmpname = os.path.splitext (fn) [0] + '.tmp'

        buff    = m.readlines ()
        m.close ()

        i       = 0
        nLines  = len (buff)

        purevirt = ["toPrimitive", "toBoolean", "toNumber", "toString", "toObject"]

        while (i < nLines):
            if string.find (buff [i], "KJS::ExecState") >= 0:
                for pv in purevirt:
                    if string.find (buff [i], pv) >= 0:
                        i = i + 2
                        buff [i] = "\t\treturn KJS::ObjectImp::%s(a0);" % pv
                        i = i + 1
                        while string.find (buff [i], "}") < 0:
                            buff [i] = ""
                            i = i + 1
                        break
            i = i + 1

        tmpfile = open (opPath + tmpname, 'w')
        i = 0
        while (i < nLines):
            tmpfile.write (buff [i])
            i = i + 1
        tmpfile.close ()
        os.unlink (opPath + fn)
        os.rename (opPath + tmpname, opPath + fn)

    return TRUE

# --------- main ----------

if not getOptions ():
    sys.exit (-1)

if operation != "shpix":
    filelist = getFilelist ()
    if filelist == []:
        sys.exit (0)

if operation == "tr":
    if not trFix (filelist):
        print 'operation error -- tr'
        sys.exit (-1)

elif operation == 'qtNoTr':
    if not qtNoTr (filelist):
        print 'operation error -- qtNoTr'
        sys.exit (-1)

elif operation == 'shpix':
    if not shpix ():
        print 'operation error -- shpix'
        sys.exit (-1)

elif operation == "notify":
    if not notify ():
        print "operation error -- notify"
        sys.exit (-1)

elif operation == "varhier":
    if not varhier (filelist):
        print "operation error -- varhier"
        sys.exit (-1)

elif operation == "appQuit":
    if not appQuit (filelist):
        print "operation error -- appQuit"
        sys.exit (-1)

elif operation == "kjsfix":
    if not kjsfix (filelist):
        print "operation error -- kjsfix"
        sys.exit (-1)

elif operation == "fixQVariant":
    """if not fixQVariant ():
        print "operation error -- fixQVariant"
        sys.exit (-1)"""

elif operation == "fixSignal":
    if not fixSignal (filelist):
        print "operation error -- fixSignal"
        sys.exit (-1)

sys.exit (0)