#!/usr/bin/python
# -*- coding: utf-8 -*-

# List of namespaces.The 2nd part in the array states whether the attributes
# should be in the namespace
namespaces = {
    "xhtml": ['"http://www.w3.org/1999/xhtml"', False, 0 ],
    "empty": [ "DOMString()", False, 1 ],
    "svg":   ['"http://www.w3.org/2000/svg"', False, 2 ],
    "xlink": ['"http://www.w3.org/1999/xlink"', True, 3 ],
    "xmlns":   ['"http://www.w3.org/2000/xmlns/"', True, 4 ],
    "xml":   ['"http://www.w3.org/XML/1998/namespace"', True, 5 ],
}

cache = {}
namesList = []

additionalCaseSensitiveAttrs = []
lastCaseInsensitiveAttr      = 0


def constName(prefix, ns, i):
    if namespaces[ns][1]:
        return (prefix + "_%s_%s") % (ns.upper(), i.upper().replace("-", "_"));
    else:
        return (prefix + "_%s") % i.upper().replace("-", "_");

def parseFile(fname, ns, isAttrs, isHtmlAttrs):
    global cache
    global namesList

    global additionalCaseSensitiveAttrs
    global lastCaseInsensitiveAttr

    prefix = "ID"
    if isAttrs:
        prefix = "ATTR"

    f = open(fname, "r")
    for i in f.xreadlines():
        i = i.strip()
        if i.startswith("#") or i == "": continue
        if isHtmlAttrs and i.startswith("END_CI"):
            lastCaseInsensitiveAttr = len(cache)
            continue

        # don't add it twice to names list
        cons = constName(prefix, ns, i)
        alreadyDefined = [k for k in namesList if k[2] == cons]
        if len(alreadyDefined) > 0:
            continue

        if i.upper() == "TEXT" and isAttrs: # hack to get ID_TEXT and ATTR_TEXT be different
            key = len(cache) + 1
            cache["TEXT#"] = -1
        else:
            key = cache.get(i, len(cache) + 1)

        if isHtmlAttrs and lastCaseInsensitiveAttr > 0 and key <= len(cache):
            additionalCaseSensitiveAttrs.append(cons)

        cache[i] = key
        namesList.append([key, i, cons, ns])
    f.close();

def parseTags(fname, ns):
    parseFile(fname, ns, False, False)

def parseAttrs(fname, ns, isHtml):
    parseFile(fname, ns, True, isHtml)

# parse htmltags.in
parseTags("htmltags.in", "xhtml");
lastTagId = len(cache)

# parse htmlattrs.in file
parseAttrs("htmlattrs.in", "xhtml", True)
lastAttrId = len(cache)

# parse SVG tags, attrs
parseTags("../svg/svgtags.in", "svg")
parseAttrs("../svg/svgattrs.in", "svg", False)

# parse XLink attrs
parseAttrs("../svg/xlinkattrs.in", "xlink", False)

# and XML attrs
parseAttrs("xmlattrs.in", "xml", False)

# sort the list
def func(a, b):
    return cmp(a[0], b[0]) or -cmp(a[2], b[2])
namesList.sort(func)

########################################
# END OF PARSING, START WRITING FILES
########################################

out = open("htmlnames.h", "w")
out.write("/* This file is automatically generated from htmltags.in and htmlattrs.in by gennames.py, do not edit */\n")
out.write("/* Copyright 2008 Vyacheslav Tokarev */\n")
out.write("\n")
out.write("#ifndef HTMLNames_h\n")
out.write("#define HTMLNames_h\n")
out.write("\n")
out.write("#include \"misc/idstring.h\"\n")
out.write("\n")

# Print out namespace string constants
for n in namespaces.keys():
    uri = namespaces[n][0];
    if uri.startswith('"'):
        out.write("#define %s_NAMESPACE %s\n" % (n.upper(), uri))

# Now the main macros and constants
out.write("namespace DOM {\n\
\n\
#define NodeImpl_IdNSMask    0xffff0000\n\
#define NodeImpl_IdLocalMask 0x0000ffff\n\
\n");

for n in namespaces.keys():
    out.write("const quint32 %sNamespace = %d;\n" % (n, namespaces[n][2]));

out.write("const quint16 anyNamespace = 0xffff;\n\
const quint16 anyLocalName = 0xffff;\n\
const quint16 emptyPrefix = 0;\n\
const quint16 xmlPrefix = 1;\n\
const quint16 xmlnsPrefix = 2;\n\
\n\
inline quint16 localNamePart(quint32 id) { return id & NodeImpl_IdLocalMask; }\n\
inline quint16 namespacePart(quint32 id) { return (((unsigned int)id) & NodeImpl_IdNSMask) >> 16; }\n\
inline quint32 makeId(quint16 n, quint16 l) { return (n << 16) | l; }\n\
\n\
const quint32 anyQName = makeId(anyNamespace, anyLocalName);\n\
\n\
}\n")
out.write("\n")


# Now the ATTR_ and ID_ constants
out.write("\n")
for i in namesList:
    if i[2].startswith("ATTR"):
        attrNS = i[3]
        useNS  = "empty"
        if namespaces[attrNS][1]:
            useNS = attrNS
        out.write("#define %s ((DOM::%s << 16) | %d)\n" % (i[2], useNS + "Namespace", i[0]))
    else:
        out.write("#define %s %d\n" % (i[2], i[0]))
out.write("#define ID_LAST_TAG %d\n" % (lastTagId))
out.write("#define ID_CLOSE_TAG 16384\n")
out.write("#define ATTR_LAST_ATTR %d\n" % (lastAttrId))
out.write("#define ATTR_LAST_CI_ATTR %d\n" % (lastCaseInsensitiveAttr))
out.write("\n")
s = "((localNamePart(id)) > ATTR_LAST_CI_ATTR"
for i in additionalCaseSensitiveAttrs:
    s = s + " || (id) == %s" % i
s = s + ")"
out.write("#define caseSensitiveAttr(id) (%s)\n" % s)
out.write("\n")
out.write("namespace khtml {\n\
\n\
class NamespaceFactory {\n\
public:\n\
    static IDTable<NamespaceFactory>* idTable() {\n\
        return s_idTable;\n\
    }\n\
    static IDTable<NamespaceFactory>* initIdTable();\n\
protected:\n\
    static IDTable<NamespaceFactory>* s_idTable;\n\
};\n\
\n\
class LocalNameFactory {\n\
public:\n\
    static IDTable<LocalNameFactory>* idTable() {\n\
        return s_idTable;\n\
    }\n\
    static IDTable<LocalNameFactory>* initIdTable();\n\
protected:\n\
    static IDTable<LocalNameFactory>* s_idTable;\n\
};\n\
\n\
class PrefixFactory {\n\
public:\n\
    static IDTable<PrefixFactory>* idTable() {\n\
        return s_idTable;\n\
    }\n\
    static IDTable<PrefixFactory>* initIdTable();\n\
protected:\n\
    static IDTable<PrefixFactory>* s_idTable;\n\
};\n")
out.write("\n")
out.write("}\n")
out.write("\n")
out.write("namespace DOM {\n\
\n\
    typedef khtml::IDString<khtml::NamespaceFactory> NamespaceName;\n\
    typedef khtml::IDString<khtml::LocalNameFactory> LocalName;\n\
    typedef khtml::IDString<khtml::PrefixFactory> PrefixName;\n\
    extern PrefixName emptyPrefixName;\n\
    extern LocalName emptyLocalName;\n\
    extern NamespaceName emptyNamespaceName;\n\
\n\
    QString getPrintableName(int id);\n\n")
out.write("}\n\n")
out.write("#endif\n")
out.close()

temp = ""
prev = 0
for i in namesList:
    if prev and prev[0] == i[0]: continue
    if i[2] == "ID_TEXT" or i[2] == "ID_COMMENT":
        temp = temp + ("    s_idTable->addHiddenMapping(%s, \"%s\");\n" % (i[2], i[1]))
    else:
        temp = temp + ("    s_idTable->addStaticMapping(localNamePart(%s), \"%s\");\n" % (i[2], i[1]))
    prev = i

out = open("htmlnames.cpp", "w")
out.write("#include \"misc/htmlnames.h\"\n")
out.write("#include \"dom/dom_string.h\"\n")
out.write("\nusing namespace DOM;\n")
out.write("\n")
out.write("namespace khtml {\n\n")
out.write("IDTable<NamespaceFactory>* NamespaceFactory::s_idTable;\n\
IDTable<NamespaceFactory>* NamespaceFactory::initIdTable()\n\
{\n\
    if (s_idTable) return s_idTable; // Can happen if KHTMLGlobal was recreated..\n\
    s_idTable = new IDTable<NamespaceFactory>();\n");
for n in namespaces.keys():
    uri = namespaces[n][0];
    if uri.startswith('"'):
        out.write("    s_idTable->addStaticMapping(DOM::%sNamespace, %s_NAMESPACE);\n" % (n, n.upper()))
    else:
        out.write("    s_idTable->addStaticMapping(DOM::%sNamespace, %s);\n" % (n, uri))

out.write("    return s_idTable;\n\
}\n\
\n\
IDTable<LocalNameFactory>* LocalNameFactory::s_idTable;\n\
IDTable<LocalNameFactory>* LocalNameFactory::initIdTable()\n\
{\n\
    if (s_idTable) return s_idTable; // Can happen if KHTMLGlobal was recreated..\n\
    s_idTable = new IDTable<LocalNameFactory>();\n\
    s_idTable->addStaticMapping(0, DOMString());\n\
%s\
    return s_idTable;\n\
}\n\
\n\
IDTable<PrefixFactory>* PrefixFactory::s_idTable;\n\
IDTable<PrefixFactory>* PrefixFactory::initIdTable()\n\
{\n\
    if (s_idTable) return s_idTable; // Can happen if KHTMLGlobal was recreated..\n\
    s_idTable = new IDTable<PrefixFactory>();\n\
    s_idTable->addStaticMapping(DOM::emptyPrefix, DOMString());\n\
    s_idTable->addStaticMapping(DOM::xmlPrefix, \"xml\");\n\
    s_idTable->addStaticMapping(DOM::xmlnsPrefix, \"xmlns\");\n\
    return s_idTable;\n\
}\n" % temp)
out.write("\n}\n")
out.write("\n")
out.write("namespace DOM {\n\n")
out.write("LocalName emptyLocalName;// = LocalName::fromId(0);\n")
out.write("PrefixName emptyPrefixName;// = PrefixName::fromId(0);\n")
out.write("NamespaceName emptyNamespaceName;// = NamespaceName::fromId(0);\n")
out.write("\n")
out.write("""QString getPrintableName(int id) {
    QString local = QString("null");
    QString namespacename = QString("null");

    if (localNamePart(id) != anyLocalName) {
        DOMString localName = LocalName::fromId(localNamePart(id)).toString();
        if (localName.implementation())
            local = localName.string();
    } else {
        local = "*";
    }

    if (namespacePart(id) != anyNamespace) {
        DOMString namespaceName = NamespaceName::fromId(namespacePart(id)).toString();
        if (namespaceName.implementation())
            namespacename = namespaceName.string();
    } else {
        namespacename = "*";
    }
    return "{ns:" + QString::number(namespacePart(id)) + ",[" + namespacename + "] local:" + QString::number(localNamePart(id)) + ",[" + local + "]}";
}\n""")
out.write("\n}\n")
out.close()

# kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;

