# This file is part of the Coral project.
# Please read the copyright notice in the LICENSE file.

import string
import sys
import inspect
import coral
from coral.lgen import lang2smd
from coral.configuration import getCoralConfiguration
from coral.lgen import smd2lang

from coral import log
logger=log.getLogger("natural2smd")

core=coral.Language.__getLanguage__("CORE",0,1)
smd=coral.Language.__getLanguage__("SMD",0,1)
uml=coral.Language.__getLanguage__("UML",1,4)

def strToMulty(s):
    if s=="0..1":
        # BUG should be (0, 1)
        return (1, 1)
    if s=="1" or s=="1..1":
        return (1, 1)
    else:
        return (0, -1)

def checkRedefinition(d,name,ln):
    if d.has_key(name):
        logger.debug("Line"+unicode(ln)+": There is already an element definition with name "+unicode(name))
        sys.exit(1)

def checkExists(d,name,ln):
    if not d.has_key(name):
        logger.debug("Line"+unicode(ln)+": There is no element definition with name "+unicode(name))
        sys.exit(1)
        
def checkLanguage(language,ln):
    if not language:
        logger.debug("Line"+unicode(ln)+": The first element definition in a file should be a language.")
        sys.exit(1)

def getKind(kindName,elements,ln):
    kind=None
    if kindName[:6]=="Core::":
        kind=core.getElement(kindName[6:])
    elif kindName[:5]=="SMD::":
        kind=smd.getElement(kindName[5:])
    elif kindName[:5]=="UML::":
        kind=uml.getElement(kindName[5:])
    else:
        checkExists(elements,kindName,ln)                
        kind=elements[kindName]
    if not kind:
        logger.debug("Line"+unicode(ln)+": Unkown type "+unicode(kindName))
        sys.exit(1)
    return kind

def natural2lang(text):
   
    language=None
    elements={}
    ln=0
    for line in text:
        ln=ln+1
        if not line:
            continue
        if line[0]=="#":
            continue
        
        words=string.split(line)
        if not words:
            continue
        kind=words[0]

        if kind not in ["operation","generalization","root","language","element","abstractElement","association","composition","attribute","enumeration","link"]:
            logger.debug("Line"+unicode(ln)+": Unknown element "+unicode(kind))
            sys.exit(3)
            
        if kind=="language":
            name=words[1]
            version=int(words[2])
            revision=int(words[3])
            language=coral.Language(name,version,revision)
            language.setXMLNS("http://www.abo.fi/"+name+"/"+str(version)+"."+str(revision))

        if kind=="enumeration":            
            checkLanguage(language,ln) # define language firts
            name=words[1]
            c=coral.EnumerationDefinition(language,name)
            for w in words[2:]:
                c.__addEnum__(w)
            checkRedefinition(elements,name,ln)
            elements[name]=c

        if kind=="element" or kind=="abstractElement":
            checkLanguage(language,ln) # define language firts
            name=words[1]
            c=coral.ElementDefinition(language,name)
            if kind=="abstractElement":
                c.setAbstract(1)
            checkRedefinition(elements,name,ln)
            elements[name]=c

        if kind=="generalization":
            checkLanguage(language,ln)
            checkExists(elements,words[1],ln)
            checkExists(elements,words[2],ln)
            c1=elements[words[1]]
            c2=elements[words[2]]
            #c1.addSubclass(c2) #BUG FIX
            c2.addSuperclass(c1)

        if kind=="operation":
            checkLanguage(language,ln)
            checkExists(elements,words[1],ln)
            c1=elements[words[1]]
            execfile(words[2]+".py")
            op=eval(words[3])
            c1.__addOperation__(coral.PyOperation(op, "Python", inspect.getsource(op), 0))
            
        if kind=="association":
            checkLanguage(language,ln)
            checkExists(elements,words[1],ln)
            c1=elements[words[1]]
            p1n=words[2]
            m1=strToMulty(words[3])
            checkExists(elements,words[4],ln)
            c2=elements[words[4]]
            p2n=words[5]
            m2=strToMulty(words[6])
            k = coral.kind_t.KIND_ASSOCIATION | coral.kind_t.KIND_BIDI
            if len(words)>7:
                if words[7]=="ordered":
                    k=k | coral.kind_t.KIND_ORDERED
                    
            c1.addPropertyRecursive(coral.Property(p1n,c2,p2n,m1[0],m1[1],k))
            c2.addPropertyRecursive(coral.Property(p2n,c1,p1n,m2[0],m2[1],k))

        if kind=="composition":
            checkLanguage(language,ln)
            checkExists(elements,words[1],ln)
            c1=elements[words[1]]
            p1n=words[2]
            m1=strToMulty(words[3])
            checkExists(elements,words[4],ln)
            c2=elements[words[4]]
            p2n=words[5]
            m2=strToMulty(words[6])            
            kinda = coral.kind_t.KIND_ASSOCIATION | coral.kind_t.KIND_BIDI
            kindc = coral.kind_t.KIND_COMPOSITION | coral.kind_t.KIND_BIDI
            if len(words)>7:
                if words[7]=="ordered":
                    kindc=kindc | coral.kind_t.KIND_ORDERED
                    
            c1.addPropertyRecursive(coral.Property(p1n,c2,p2n,m1[0],m1[1],kindc))
            c2.addPropertyRecursive(coral.Property(p2n,c1,p1n,m2[0],m2[1],kinda))

        if kind=="root":
            checkLanguage(language,ln)
            checkExists(elements,words[1],ln)
            c1=elements[words[1]]
            language.setRoot(c1)
            
        if kind=="link":
            checkLanguage(language,ln)
            checkExists(elements,words[1],ln)
            c1=elements[words[1]]
            name=words[2]
            kindName=words[3]
            
            atype=getKind(kindName,elements,ln)                   
                
            k = coral.kind_t.KIND_ASSOCIATION
            c1.addPropertyRecursive(coral.Property(name,atype,"", 1, 1, k))
   
        
        if kind=="attribute":
            checkLanguage(language,ln)
            checkExists(elements,words[1],ln)
            c1=elements[words[1]]
            name=words[2]
            kindName=words[3]
            m=(1, 1)
            if len(words)>4:
                m=strToMulty(words[4])

            atype=getKind(kindName,elements,ln)        
            k = coral.kind_t.KIND_COMPOSITION
            if len(words)>5:
                if words[5]=="ordered":
                    k=k | coral.kind_t.KIND_ORDERED
                    
            c1.addPropertyRecursive(coral.Property(name,atype,"", m[0], m[1], k))

                              
    return language


def main(args):
    if len(args) != 2:
        logger.debug("natural2smd: input_file.txt output_smd_model.xml")
        sys.exit(2)
    else:
        try:
            fd=open(args[0],"r")
            try:
                text=fd.readlines()
            finally:
                fd.close()
        except Exception,e:
            logger.debug(unicode(args[0])+":"+unicode(e))
            sys.exit(0)
            
        lang=natural2lang(text)
        
        smd=lang2smd.lang2smd(lang)
        print "Creating SMD model in", args[1]
        
        coral.saveModel(args[1], smd)

if __name__ == "__main__":
    import sys
    main(sys.argv[1:])

    
