#
# The kind_t from coral/core/AbstractElementDefinition.h
#

def implies(a,b):
    return not a or b

class kind_t:
    KIND_ORDERED = 1
    KIND_BAG = 2
    KIND_BIDI = 4
    KIND_NOSERIALIZE = 8
    KIND_ANONYMOUS = 16
    KIND_COMPOSITION = 32
    KIND_ASSOCIATION = 64
    
MODELCOPY_DONT_CREATE_NEW_UUIDS = 1
MODELCOPY_DONT_ATTACH_TO_PARENTS = 2
MODELCOPY_DONT_SKIP_PYOBJECTS = 4
MODELCOPY_DONT_KEEP_ASSOCIATIONS_OUTSIDE_SUBTREE = 8

TRANSACTION_REDO = 0
TRANSACTION_UNDO = 1
TRANSACTION_ORDINARY = 2

MODELDIFFERENCE_IGNORE_DIAGRAM_INFORMATION = 1
MODELDIFFERENCE_ONLY_DIAGRAM_INFORMATION = 2

#
# The Coral CORE metamodel
#
__core = Language.__getLanguage__("CORE", 0, 1)
Name = __core.getElement("Name")
String = __core.getElement("String")
Boolean = __core.getElement("Boolean")
Integer = __core.getElement("Integer")
UnlimitedInteger = __core.getElement("UnlimitedInteger")
UnlimitedReal = __core.getElement("UnlimitedReal")
Float = __core.getElement("Float")
Double = __core.getElement("Double")
coralPyObj = __core.getElement("coralPyObj")

AnyElement = __core.getElement("AnyElement")
AnyAbstractElement = __core.getElement("AnyAbstractElement")
PresentationElement = __core.getElement("PresentationElement")

#
# XML namespaces
#

def __fixXMLNS(thelist):
    # Add reverse mappings from XML namespaces to metamodels
    import re
    for __i in thelist:
        __lines = []
        try:
            __f = open(__i, "r")
        except:
            continue
        try:
            __lines=__f.readlines()
        finally:
            __f.close()
        if len(__lines)>2:
            __name=""
            __major=-1
            __minor=-1
            __filename=""
            __xmlns = []
            for __l in __lines:
                __m = re.search("^name\s+(.*)", __l)
                if __m:
                    __name = __m.group(1)
                __m = re.search("^file\s+(.*)", __l)
                if __m:
                    __filename = __m.group(1)
                __m = re.search("^version\s+(.*)", __l)
                if __m:
                    __major = int(__m.group(1))
                __m = re.search("^revision\s+(.*)", __l)
                if __m:
                    __minor = int(__m.group(1))
                __m = re.search("^xmlns\s+(.*)", __l)
                if __m:
                    __xmlns.append(__m.group(1))
            if __filename == "":
                print "ERROR Language " + __name + str(__major) + str(__minor) + " has no filename defined in its manifest.txt!"
                continue
            if __filename[0] != "/":
                __filename = os.path.split(__i)[0] + os.sep + __filename
            if __name == "" \
               or __xmlns == []:
                continue
            for __x in __xmlns:
                _coral.addXMLNSRmap(__x, __filename, __name, __major, __minor)

#
# Add languages found under
# coral/lang/*
# and
# ~/.coral/coral/lang/*
# to the kernel's knowledge
#
import glob
__fixXMLNS(glob.glob(installation_path + "/coral/lang/*/manifest*.txt"))
import configuration
_user_home = configuration.getUserHome()
__fixXMLNS(glob.glob(_user_home + "/.coral/coral/lang/*/manifest*.txt"))
del configuration
del _user_home
del glob

class __PythonLanguageProxy:
    def __getattr__(self,name):
        assert(len(name)>=3)
        # UML_1_4 ?
        i = name.split("_")
        if (len(i)==3):
            return Language.__getLanguage__(i[0], int(i[1]), int(i[2]))
        # UML14 ?        
        return Language.__getLanguage__(name[:-2], int(name[-2:-1]), int(name[-1:]))

    def __call__(self,name,version,revision):
        return Language.__getLanguage__(name, int(version), int(revision))

lang = __PythonLanguageProxy()

# Begin of "unification" patch
class __PythonMetamodelProxy:
    def __getattr__(self,name):
        if not name:
            return None
        
        L = getattr(lang, name)
        if not L:
            return None
        else:
            return L.getCorrespondingElement()

    def __call__(self,name,version,revision):
        return lang(name,version,revision).getCorrespondingElement()

meta = __PythonMetamodelProxy()

##def __browse__(self,name):
##    return self.elements.select(lambda e: e.name==name)[0]

##def __invoke__(self,*args,**kargs):
##    name=self.name
##    edclass=None

##    print "I am slow: ALG1"
##    p=self.package

##    while(not p.oclIsKindOf(lang.SMD01.Language)):
##          p=p.package

##    l = Language.__getLanguage__(unicode(p.name), int(p.version),int(p.revision))
         
##    if l:
##        edclass=l.getElement(unicode(name))            
##    return edclass(*args,**kargs)

##lang.SMD01.Package.__addOperation__(PyOperation(__browse__,"Python",inspect.getsource(__browse__),0))

##lang.SMD01.ElementDefinition.__addOperation__(PyOperation(__invoke__,"Python",inspect.getsource(__invoke__),0))

# Atom.oclIsKindOf should work with SMD elements

# return true of ElementDefinition a is a subtype of ElementDefinition b

def isSubType(a,b):
    while(a):
        if a==b:
            return True
        else:
            for s in a.superclasses:
                if isSubType(s,b):
                    return True
        return False

def oclIsKindOf(self,c):
    if isinstance(c,AbstractElementDefinition):
        return _coral.Atom_oclIsKindOf(self, c)
    else:
        return isSubType(self.__meta__, c)
                

Atom.oclIsKindOf= oclIsKindOf


# slot search by name

def getItemByPositionOrByName(self,q):
    if type(q)==type(""):
        return self.select(lambda e: e.name==q)[0]
    else:
        return _coral.Slot___getitem__(self, q)

Slot.__getitem__= getItemByPositionOrByName

# End of "unification" patch



# Don't use this crap.
def __import__(self,dict):
    # ugly hack to import a language into a namespace
    for x in self.__elements__():
        dict[x.getName()]=x
Language.__import__=__import__
        


TransactionManager=getTransactionManager()

def find(element,query):
    return element.__getAllParts__().select(query)

# User Projects

Project.addModel = (lambda self, e: e.__setProject__(self))
Project.saveToDocument= (lambda self: saveDocument(self))
                  
def loadDocument(*args,**kargs):
    prj=_coral.loadDocument(*args,**kargs)
    prj.setUserProject(True)
    return prj

def loadInternalDocument(*args,**kargs):
    prj = _coral.loadDocument(*args,**kargs)
    prj.setUserProject(False)
    return prj

def __addOperationsToInternalModel(language, langstring):
    for p in language.elements:
        for o in p.operations:
            code=""
            for l in o.code:
                code += str(l)+"\n"
            exec compile(code,"<string>","exec")
            eval(langstring+p.name).__addOperation__(PyOperation(eval(str(o.name)),"Python",str(o.name),0))    

# The kernel has a built SMD01 language. However, the user
# can define *additional* operations in the SMD01 metamodel.
# Currently ther kernel does not load them. This really ugly
# code does that
# The same goeas for the CORE01 metamodel

__addOperationsToInternalModel(meta.SMD01,"lang.SMD01.")
__addOperationsToInternalModel(meta.CORE01,"lang.CORE01.")


def newProject(metamodel,projectName=""):
    "create a project based on language"
    prj = Project()
    if projectName:
        prj.setFileName(prj)
    root = metamodel.root_ed()
    root.__setProject__(prj)
    return (prj,root)



#
# Convenient (debug?) shorthand to get a set of graphnodes that are
# connected to our element
#
def gfx(element):
    return element.xmidi_get_graphelements()


import site

copyright=site._Printer("copyright","""@@@COPYRIGHT@@@""")
license=site._Printer("license","""@@@LICENSE@@@""")
credits=site._Printer("credits","""@@@CREDITS@@@""")

# Hide all projects that have been used so far
for p in getAllProjects():
    p.setUserProject(False)
