import coral
import jhelp
import os

L = coral.meta.UML14

from coral.lgen.codeartifact import CodeArtifact

### METHOD ###########################################################

def create_method(method, c):
    c.ca.add("")
    t_static = ""
    if method.specification.ownerScope == "instance":
        pass
    elif method.specification.ownerScope == "classifier":
        t_static = "static "
    else:
        assert 0

    res = method.specification.name
    res += "("
    # Loop through method formal parameters
    params = []
    retparams = []
    for param in method.specification.parameter:
        if param.kind == "return":
            retparams.append(param)
            continue
        params.append(param)

    def f(params):
        l = []
        for p in params:
            c.import_these.add(p.type)
            s = jhelp.dot_name(p.type) + " " + str(p.name)
            # DUH. Java does not have default values
            #if p.defaultValue and p.defaultValue.body:
            #    s += " = " + p.defaultValue.body
            l.append(s)
        return ", ".join( l )
    
    # BUG loop through keywords args
    # BUG remember to set default values.
    rp = f(retparams)
    if not rp:
        rp += jhelp.dot_name(jhelp.java.lang.void)
    rp += " "
    res = rp + res + f(params)

    res += ")"
    res = jhelp.visibility_u2j(method.specification.visibility) + t_static + res
    # COMMENTS
    l = []
    l.extend(method.specification.comment.body)
    l.extend(method.comment.body)
    for param in method.specification.parameter:
        if param.comment:
            s = []
            s.extend(param.comment.body)
            s[0] = "@" + unicode(param.name) + " - " + unicode(s[0])
            l.extend( s )
        
    jhelp.add_comment(c.ca, l)
    
    c.ca.add(res + " {")
    # Method body
    c.ca.indent(1)
    b = ""
    if method.body:
        b = unicode(method.body.body).strip()

    if b == "" and method.specification.specification:
        b = unicode(method.specification.specification)

    if b == "":
        c.ca.add("/* No method body defined */")
        c.ca.add("System.out.println(\"" + res + "\");")
    else:
        b = b.split("\n")
        for i in b:
            c.ca.add(i)
    c.ca.indent(-1)
    c.ca.add("}")

### ATTRIBUTES ###########################################################

def create_attribute(c, name, type, multiplicity, ordering, visibility, comment):
    l = 0
    u = 1
    if multiplicity:
        for r in multiplicity.range:
            l = min(l, r.lower)
            u = max(u, r.upper)

    if u > 1:
        if ordering == "ordered":
            type = jhelp.java.util.Vector
        else:
            type = jhelp.java.util.TreeSet

    c.import_these.add(type)
    jhelp.add_comment(c.ca, comment)
    c.ca.add(jhelp.visibility_u2j(visibility) + jhelp.dot_name(type) + " " + name + ";")


### CLASS/INTERFACE ######################################################

def create_class(F_elems, e):
    c = jhelp.Creator()
    c.import_these = coral.Set()
    
    pkglist = coral.Element__getParentsAndMyself__(e, False)

    pkgnames = [ str(i.name) for i in pkglist ]

    c.ca_header = CodeArtifact()
    c.ca_imports = CodeArtifact()
    c.ca = CodeArtifact()
    c.ca_footer = CodeArtifact()
    c.ca_list = [ c.ca_header, c.ca_imports, c.ca, c.ca_footer ]
    fname = os.sep.join(pkgnames)
    if fname:
        fname += os.sep
    F_elems[e] = ( fname + e.name + ".java", c.ca_list)

    pkgname = ".".join( pkgnames )

    l = 16 - len(jhelp.uml2java_version)
    c.ca_header.add("/***********************************************************************")
    c.ca_header.add(" *                                                                     *")
    c.ca_header.add(" * This file was generated with Coral uml2java version " + jhelp.uml2java_version + " " * l + "*")
    c.ca_header.add(" * DO NOT EDIT!                                                        *")
    c.ca_header.add(" *                                                                     *")
    c.ca_header.add(" ***********************************************************************/")
    if pkgname:
        c.ca_header.add("package " + pkgname + ";")
        c.ca_header.add("")

    # CLASS DESCRIPTION
    
    a = c.ca.add
    i = lambda: c.ca.indent(1)
    d = lambda: c.ca.indent(-1)

    all_sc = e.generalization.parent
    s_c = ""
    s_i = ""
    sc = all_sc.select(lambda x: x.oclIsKindOf(L.Class))
    assert len(sc) <= 1
    if sc:
        s_c = " extends " + jhelp.dot_name(sc[0])
        c.import_these.add(sc[0])
        
    si = all_sc.select(lambda x: x.oclIsKindOf(L.Interface))
    if si:
        s_i = " implements " + ", ".join( [ jhelp.dot_name(iface) for iface in si ] )
        for iface in si:
            c.import_these.add(iface)

    typestr = "class"
    if e.oclIsKindOf(L.Interface):
        typestr = "interface"

    jhelp.add_comment(c.ca, e.comment.body)
    
    a(jhelp.visibility_u2j(e.visibility) + typestr + " " + e.name + s_c + s_i + " {")
    i()

    # ATTRIBUTES
    attr = e.feature.select(lambda x: x.oclIsKindOf(L.Attribute))
    for at in attr:
        create_attribute(c,
                         at.name,
                         at.type,
                         at.multiplicity,
                         at.ordering,
                         at.visibility,
                         at.comment.body)
    for ae in e.association:
        ae2 = ae.association.connection[0]
        if ae == ae2: ae2 = ae.association.connection[1]
        if not ae2.isNavigable:
            continue
        create_attribute(c,
                         ae2.name,
                         ae2.participant,
                         ae2.multiplicity,
                         ae2.ordering,
                         ae2.visibility,
                         ae2.comment.body)

    # METHODS
    for m in e.feature.select(lambda x: x.oclIsKindOf(L.Method)):
        create_method(m, c)

    # DEPENDENCIES
    # Also import these classes
    for dep in e.clientDependency:
        for target in dep.supplier:
            c.import_these.add(target)

    d()
    a("")
    a("};")

    # IMPORT DECLARATIONS
    s = coral.Set()
    for n in c.import_these:
        s.add(n.__parent__())
    names = [ jhelp.dot_name(n) for n in s ]
    names.sort()
    for n in names:
        # We can't import two "A" classes from different packages
        # using the "import foo.bar.A; import qwe.rty.A;" statements
        # ???
        c.ca_imports.add("import " + n + ".*;")
    if names:
        c.ca_imports.add("")

