#!/usr/bin/env python2 

import coral
metamodel=coral.lang.UML14
import pyclbr 
import os 
import os.path 
import string 
import types 
import re 
import sys 
import inspect
import popen2

 
class py2uml: 
 
    def __init__(self): 
        """ 
        Initialization of a new conversion object. 
        """ 
        self.layerNumber=1
        self.normaNumber=1

        self.generateAttributes=0  
        self.generatedAttributes=[] 
        self.generateMethods=0
        self.generateGeneralizations=0
        self.generateComponents=0
        self.includedComponents=[]
        self.excludedComponents=[]

        self.checkWFR = 0
        self.thisPacks={}
        self.testClasses=[]
        
        #path,sName=self.getOption() 
        #self.convert(path,sName)


 
 
    def convert(self, path, sName): 
        """ 
        Only 'public' method in the class. converts the given path into an UML model. 
        path has to exists and is an directory. sName is not None: otherwise None returned. 
        """ 
 
        if (path is None): 
            return None 
         
        if (not os.path.isdir(path)): 
            return None 
 
        elif (sName is None): 
            return None 
 
        else: 
            self.generatedAttributes=[] 
            coral.saveModel(sName,self.cpy2uml(path,genLayers=0,sfi=0)) 
         
    def printUsage(self): 
        print """ 
Usage: 
 
--input              python dir to convert 
--output             filename for output file 
--attributes         [optional, converts also the python attributes to model] 
--methods            [optional, converts also the python methods to model]
--generalizations    [optional, converts also the python generalizations to model]
--components         [optional, converts the text files as components]
--checkWFR           [optional, converts using well formed rules check]

If the --components option is selected the user can define which text file types
are processed as components with the following commands. As a default all the text
files will be processed as components.
NOTE! .py files are always considered as python modules, not as components.
NOTE! the following two options are mutually exclusive (if both are defined only
the excluded list is used)

--excludedComponents [optional, list the excluded components]
--includedComponents [optional, list the included components]
    
        
example: python py2uml.py --input /pModule --output model.xml
                          --attributes --methods
         python py2uml.py --input /pModule --output model.xml
                          --components --excludedComponents *.py?
 
        """ 
 
 
    def getOption(self):
        """
        Gets the options from input parameters. Assigns the corresponding class attributes.
        Returns the input path and output file.
        """
        path = sName = None 
        l=[] 

        for s in sys.argv: 
            l.append(s)

        if "--input" in l: 
            if(l.index("--input")+1<len(l)): 
                path=l[l.index("--input")+1] 
            else: 
                self.printUsage() 
                sys.exit() 
        else: 
            self.printUsage() 
            sys.exit() 
 
        if "--output" in l: 
            if(l.index("--output")+1<len(l)): 
                sName=l[l.index("--output")+1] 
            else: 
                self.printUsage() 
                sys.exit() 
        else: 
            self.printUsage() 
            sys.exit() 
             
        if "--attributes" in l: 
            self.generateAttributes=1 
        if "--methods" in l: 
            self.generateMethods=1

        if "--generalizations" in l:
            self.generateGeneralizations=1
            
        if "--checkWFR" in l:
            self.checkWFR = 1

        # disabled for now because saving stereotypes as an xml bugs in io.py
        if "--components" in l:
            self.generateComponents=1

        if self.generateComponents:
            if "--excludedComponents" in l:
                self.includedComponents = []
                self.excludedComponents = []
                startIndex=l.index("--excludedComponents")
                i=startIndex+1
                while(len(l)>i and l[i][:2]!="--"):
                    self.excludedComponents.append(l[i])
                    i+=1
                    
            elif "--includedComponents" in l:
                self.excludedComponents = []
                self.includedComponents = []
                startIndex=l.index("--includedComponents")
                i=startIndex+1
                while(len(l)>i and l[i][:2]!="--"):
                    self.includedComponents.append(l[i])
                    i+=1
                    
        return path, sName 
 
    def cpy2uml(self, path, model=None,genLayers=0,sfi=0): 
        """ 
        Converts the given path to an UML model. The path has to be valid.
        Note: If there is a same named .py file and folder with __init__.py in the same folder
              two same named packages are created to the model.
        """
        wDir = os.getcwd() 
        self.generatedAttributes=[]
        if not model:
            model=self.constructModel(path)
        uModel=model
        self.model=uModel

        uPack=self.constructDirectoryPackage(path,model,genLayers,sfi)
        uModel.ownedElement.append(uPack)
        if sfi:
            self.initSfiModel(uModel)
            self.addTag("correctness",uPack,"undefined")
            self.addTag("correctness",uModel,"undefined")
            self.createTestDependencies(uPack)
        ##
        if genLayers:
            self.checkIfLayer(path,uPack)
            self.createLayerDependencies(uPack)
        ## 
        
        #make the generalizations
     
        if self.generateGeneralizations:
            self.createGeneralizations(uModel,genLayers,sfi) 

 
        if self.generateAttributes and self.generatedAttributes: 
 
            c=self.anyClass(uModel) 
 
            if not c: # no class in the model, cannot set types for package attributes.
                return 
 
            for g in self.generatedAttributes: 
                if not g.type: 
                    g.type=c 

        

        if self.checkWFR:
            w = self.WFRCheck(uModel)
            if (w!=1):
                print w
            else:
                print "WFR ok"
            
        os.chdir(wDir)
        
        return uModel 
     
 
    def constructModel(self, path): 
        """ 
        Initializes new UML model with the name taken from the 'path'  
        """ 
        name="" 
        if path[-1:] == "/": 
            name=path[:-1] 
        else: 
            name=path 
 
        k=string.rfind(name,"/") 
        name=name[k+1:]     
        uModel = metamodel.Model() 
        uModel.name = name 
         
        return uModel 

    def WFRCheck(self, uModel):
        print "WFR Checking"
    
       
        try:
            uModel.isWellFormedRecursive()
            return 1
        except Exception,detail:

            return detail
            
        
        

    
     
    def constructDirectoryPackage(self, path, model=None, genLayers=0,sfi=0): 
        """ 
        Constructs an UML package from the given path. The Package will contain all 'Module' packages 
        and sub packages (created from sub directories). 
        require: the path has to be valid. The (python) package given as parameter is attached to model. 
        """         
        print "Constructing package from path: " + path

        self.model=model

        "version 2" 
        if (path[len(path)-1:len(path)] !="/"): 
            pathName=path+"/" 
        else: 
            pathName=path 
     
        files=os.listdir(pathName) 
 
        uPackage=metamodel.Package() 
        packName=string.split(pathName,"/") 
        pName=packName[len(packName)-2] 
        uPackage.name=pName 
         
        for name in files: 
            if(os.path.isdir(pathName+name) and self.isPackage(pathName+name)): 
                if os.access(pathName+name, os.R_OK): # Check for read permission
                    subPackage=self.constructDirectoryPackage(pathName+name,model,genLayers,sfi) 
                    if subPackage: 
                        uPackage.ownedElement.append(subPackage)
                        if genLayers:
                            self.checkIfLayer(pathName+name,subPackage) 
                        if sfi:
                            self.addTag("correctness",subPackage,"undefined")

                        ## 
            # adding the lib-tk and site-packages files 
            elif(os.path.isdir(pathName+name) and (name=="lib-tk" or name=="site-packages")): 
                subPackage=self.constructDirectoryPackage(pathName+name,model,genLayers,sfi)
                while subPackage.ownedElement:
                    uPackage.ownedElement.append(subPackage.ownedElement[0]) 

                 
            elif(name.endswith(".py")): 
                name = name[:len(name)-3] # remove the .py 
             
                if(name=="__init__"): 
                    clNames=self.readClassNames(pathName+name) 
                    pn=string.replace(pathName,"/",".") 
                 
                    for cName in clNames: 
                        newClass=metamodel.Class() 
                        uPackage.ownedElement.append(newClass)
                        newClass.name=cName
                        if sfi:
                            newClass.isAbstract=1
                        if sfi and newClass.name[0:4]!="test":
                            #print newClass.name
                            self.addTag("correctness",newClass,"undefined")
                        elif sfi:
                            supplierClass=self.readTestSupplier(pathName+name,cName)
                            self.addTag("testcase",newClass,supplierClass)
                            self.testClasses.append(newClass)
                            
                        if (self.generateAttributes): 
                            classAttributes=self.readClassAttributes(pathName+name,cName) 
                        
                            for aName in classAttributes: 

                                cAttribute=metamodel.Attribute(multiplicity=metamodel.Multiplicity())
                                cAttribute.multiplicity.range.add(metamodel.MultiplicityRange(multiplicity=cAttribute.multiplicity,lower=1,upper=1)) 
                                cAttribute.name=self.processVisibility(cAttribute,aName) 
                                cAttribute.type=newClass
                                cAttribute.ownerScope=metamodel.ScopeKind.sk_classifier
                                
                                newClass.feature.append(cAttribute) 
                                self.generatedAttributes.append(cAttribute) 

                            classAttributes1=self.readClassInstanceAttributes(pathName+name,cName)
                            for aName in classAttributes1:
                                
                                cAttribute=metamodel.Attribute(multiplicity=metamodel.Multiplicity()) 
                                cAttribute.multiplicity.range.add(metamodel.MultiplicityRange(multiplicity=cAttribute.multiplicity,lower=1,upper=1)) 
                                cAttribute.name=self.processVisibility(cAttribute,aName) 
                                cAttribute.type=newClass
                                cAttribute.ownerScope=metamodel.ScopeKind.sk_instance
                                
                                newClass.feature.append(cAttribute) 
                                self.generatedAttributes.append(cAttribute)                             
                       
                        if (self.generateMethods): 
                            classMethods,methodParameters=self.readClassMethods(pathName+name,cName) 
 
                            for mName in classMethods.keys():
                                
                                if mName=='invariants':
                                    
                                    self.addTag(mName,newClass,string.strip(classMethods[mName]))
                                    continue 
                                
                                cMethod=metamodel.Operation()
                                # handle the visibilities
                                methodName=mName
                                if methodName[:2]=="__" and methodName[-2:]=="__":
                                    pass
                                else:
                                    methodName=self.processVisibility(cMethod,mName)
                                    
                                #elif mName[:2]=="__":
                                #    methodName=mName[2:]
                                #    cMethod.visibility=metamodel.VisibilityKind().vk_protected
                                #elif mName[:1]=="_":
                                #    methodName=mName[1:]
                                #    cMethod.visibility=metamodel.VisibilityKind().vk_private
                                    
                                if string.find(methodName,")")!=-1:
                                    cMethod.name=string.split(methodName,")")[0]
                                else:
                                    cMethod.name=methodName
                                    
                                newClass.feature.append(cMethod)

                                #Check for documentation
                                classMethods[mName]=self.processDocumentation(cMethod,classMethods[mName])

                                
                                #Check for pre/post conditions
                                classMethods[mName]=self.processConditions(cMethod,classMethods[mName])
                                
                                cMethod.specification=classMethods[mName] 
                                #newClass.feature.append(cMethod)
                                for param in methodParameters[mName]:
                                    s=string.split(param,'=')
                                    pname=s[0]
                                    defValue=None
                                    if len(s)==2:
                                        defValue=s[1]
                                    p=metamodel.Parameter()
                                    p.name=pname
                                    cMethod.parameter.append(p)
                                    if defValue:
                                        p.defaultValue.body=defValue
                                        # type
                                    p.type=newClass
                                    if model:
                                        pp=model.ownedElement.select(lambda x: x.oclIsKindOf(metamodel.Package) and \
                                                                     x.name=='python2_2')
                                        if len(pp)==1:
                                            tp=pp[0].ownedElement.select(lambda x: x.oclIsKindOf(metamodel.Package)and \
                                                                         x.name=='pythonTypes')
                                            if len(tp)==1:
                                                ic=tp[0].ownedElement.select(lambda x: x.oclIsKindOf(metamodel.Class) and \
                                                                             x.name=='InstanceType')
                                                if len(ic)==1:
                                                    p.type=ic[0]
                                                        
                    if pathName[-1]=='/':
                        self.thisPacks[pathName[:-1]]=uPackage 
                    else:
                        self.thisPacks[pathName]=uPackage
                else: 
            
                    if os.access(pathName+name+".py", os.R_OK): # Check for read permission 
                         subPackage=self.constructFilePackage(pathName+name,model,genLayers,sfi) 
                         if subPackage: 
                             uPackage.ownedElement.append(subPackage)
                             if sfi:
                                 self.addTag("correctness",subPackage,"undefined")
            elif self.generateComponents:
                com=self.constructComponent(pathName,name,uPackage)
        return uPackage 

    def constructComponent(self,path,name,pack):
        if not self.model:
            print "cannot handle file",path,": no model specified"
            return

        oldCwd=os.getcwd()
        os.chdir(path)

        if self.excludedComponents:
            for x in self.excludedComponents:
                sto,stw,ste = popen2.popen3("dir "+x)
                output=sto.read()
                error=ste.read()
                if error!="":                    
                    continue
                if string.find(output,name)!=-1:
                    os.chdir(oldCwd)
                    return
                

        else:
            ok=0
            checkList=self.includedComponents
            if not checkList:
                checkList.append("")
            for x in checkList:
                sto,stw,ste = popen2.popen3("dir "+x)
                output=sto.read()
                error=ste.read()
                if error!="":
                    pass                
                elif string.find(output,name)!=-1:
                    ok=1

            if not ok:
                os.chdir(oldCwd)
                return
        
        os.chdir(oldCwd)
        file=string.split(name,".",1)
        extension=""
        if len(file)==2:
            extension=file[1]
        name1=file[0]
        #try:
        sto,stw,ste = popen2.popen3("file "+path+name)
        st = sto.read()
        if st=="":
            st = ste.read()
            print "error processing file",path+file,":",st
            return
        st = string.split(st,":")
        st = st[1]

        if string.count(st," text")==1 and os.access(path+name,os.R_OK):
            
            fp = open(path+name)
            res="Extension:"+extension+"\n"+fp.read()
            fp.close()
            
            comp=metamodel.Component()
            comp.name=name1
            
            ster=None
            if extension=="cfg":
                ster=self.model.ownedElement.select(lambda l: l.oclIsKindOf(metamodel.Stereotype) and \
                                                    l.name=="configuration")                
                if not ster:
                    ster=metamodel.Stereotype()
                    ster.name="configuration"
                    ster.namespace=self.model
                else:
                    ster=ster[0]
            else:
                ster=self.model.ownedElement.select(lambda l: l.oclIsKindOf(metamodel.Stereotype) and \
                                                    l.name=="plain text")
                if not ster:
                    ster=metamodel.Stereotype()
                    ster.name="plain text"
                    ster.namespace=self.model
                else:
                    ster=ster[0]
                            
            comp.stereotype.append(ster)
            comp.namespace=pack
            self.addTag("componentContents",comp,res)
                
        else:
            print "cannot handle file :",path+name
            return                         
        #except:
        #    print "error in processing component :",path
        #   return
        
                     
             
    def constructFilePackage(self, fname, model=None,genLayers=0,sfi=0): 
        """ 
        Constructs an UML package from the given file. Adds all attributes, methods and classes to the packet. 
        require: fname has to exist.         
        """ 
         
        print "Constructing package from file: " + fname 
        uPackage = metamodel.Package() 
        packName=string.split(fname,"/") 
        pName=packName[len(packName)-1]
        if pName=="umlcoresupport":
            # check for Round Trip Engineering, leave the umlcoresupport file out of the model.
            return

        # we name the files with '_py' end to differ them from the normal packages generated from folders
        uPackage.name = pName
         
        rcNames = self.readClassNames(fname) 
  
        for cName in rcNames: 
 
            pn=string.replace(fname,"/",".") 

            
            uClass=metamodel.Class() 
            uClass.name=cName 
            if sfi:
                uClass.isAbstract=1
 
            if (self.generateMethods): 
                classMethods,methodParameters=self.readClassMethods(fname,cName)
                for method in classMethods.keys(): 
                    classMethod=metamodel.Operation()
                    # handle the visibilities
                    methodName=method
                    if methodName[:2]=="__" and methodName[-2:]=="__":
                        pass
                    else:
                        methodName=self.processVisibility(classMethod,method)
                        
                    #elif method[0:2]=="__":
                    #    methodName=mName[2:]
                    #    classMethod.visibility=metamodel.VisibilityKind().vk_protected
                    #elif method[0:1]=="_":
                    #    methodName=mName[1:]
                    #    classMethod.visibility=metamodel.VisibilityKind().vk_private
                        
                    if string.find(method,")")!=-1:
                        classMethod.name=string.split(methodName,")")[0]
                    else:
                        classMethod.name=methodName 
                    classMethod.specification=classMethods[method] 
                    uClass.feature.append(classMethod)
                    uClass.isAbstract=1
                    # parameters
                    for param in methodParameters[method]:
                        s=string.split(param,'=')
                        
                        pname=s[0]
                        defValue=None
                        if len(s)==2:
                            defValue=s[1]
                        p=metamodel.Parameter()
                        p.name=pname
                        classMethod.parameter.append(p)
                        if defValue:
                            p.defaultValue.body=defValue
                        # type
                        p.type=uClass
                        if model:
                            pp=model.ownedElement.select(lambda x: x.oclIsKindOf(metamodel.Package) and \
                                                         x.name=='python2_2')
                            if len(pp)==1:
                                tp=pp[0].ownedElement.select(lambda x: x.oclIsKindOf(metamodel.Package)and \
                                                          x.name=='pythonTypes')
                                if len(tp)==1:
                                    ic=tp[0].ownedElement.select(lambda x: x.oclIsKindOf(metamodel.Class) and \
                                                                 x.name=='InstanceType')
                                    if len(ic)==1:
                                        p.type=ic[0]
                                       
            if (self.generateAttributes): 
                # read the class attributes 
                classAttrs=self.readClassAttributes(fname,cName) 
                for attr in classAttrs: 
                     
                    classAttribute=metamodel.Attribute(multiplicity=metamodel.Multiplicity()) 
                    classAttribute.multiplicity.range.add(metamodel.MultiplicityRange(multiplicity=classAttribute.multiplicity,lower=1,upper=1)) 
 
                    classAttribute.type=uClass 
                    classAttribute.name=self.processVisibility(classAttribute,attr)
                    classAttribute.ownerScope=metamodel.ScopeKind.sk_classifier
                    uClass.feature.append(classAttribute) 
                    self.generatedAttributes.append(classAttribute) 

                classAttrs1=self.readClassInstanceAttributes(fname,cName)
                for attr in classAttrs1:
                    
                    classAttribute=metamodel.Attribute(multiplicity=metamodel.Multiplicity()) 
                    classAttribute.multiplicity.range.add(metamodel.MultiplicityRange(multiplicity=classAttribute.multiplicity,lower=1,upper=1)) 
 
                    classAttribute.type=uClass 
                    classAttribute.name=self.processVisibility(classAttribute,attr) 
                    classAttribute.ownerScope=metamodel.ScopeKind.sk_instance
                    uClass.feature.append(classAttribute) 
                    self.generatedAttributes.append(classAttribute)
                    
            uPackage.ownedElement.append(uClass) 
            #if genLayers and uClass.name[0:4]!="test":
                #print uClass.name
                #self.addTag("correctness",uClass,"undefined")
        self.thisPacks[fname]=uPackage
        return uPackage 

    def createGeneralizations(self,model,genLayers=0,sfi=0):
        """
        Goes through the files of self.thisPacks dictionary, finds the generalizations and
        creates them to model given as parameter.

        ##########################################
        FIXME: this method is way too slow because of the pyclbr searches all the paths in sys.path + mPath
        #########################################
        """
        print 'constructing generalizations for model'

        self.layerNumber=1
        self.normalNumber=1
       
        for fn in self.thisPacks.keys():
            mName=''
            mPath=''
            i = string.rfind(fn, '/')
            if not i==-1:
                mName = fn[i:]
                mPath = fn[:i]
            else:
                mName=fn

            ## addition
            if mName=="/umlcoresupport":
                break
            ## addition
            pyclbr._modules={}
            
            vs=[]
            #####
            ## THIS NEEDS TO BE FIXED: IE. MADE FASTER
            ## goes through all the sys.path +mPath paths....
            #####
            for v in pyclbr.readmodule(mName, [mPath]).values():
                if isinstance(v,pyclbr.Class):
                    if v.module==mName:
                        vs.append(v)
            
            for c in vs:
                print ' -checking class',c.name

                if not len(c.super):
                    continue
                
                chi =None
                
                for e in self.thisPacks[fn].ownedElement:
                    if e.oclIsKindOf(metamodel.Class) and e.name==c.name:
                        chi=e
                if not chi:
                    print 'warning: class ',c.name,' not found in package ', self.thisPacks[fn].name
                    continue
                for cp in c.super:
                    if not isinstance(cp,pyclbr.Class):
                        # go through the file for import instances like 'from X import Y as A'
                        res=""
                        if string.count(cp,".")>0:
                            res=cp
                        elif os.path.isdir(fn):                          
                            res=self.searchImport(fn+"/__init__.py",cp)
                        elif os.path.isfile(fn+".py"):
                            res=self.searchImport(fn+".py",cp)
                        else:
                             print 'warning: unreachable parent ',cp,"--",fn
                        if res:
                            names=string.split(res,".")

                            #Do not search the python package for this kind of imports
                            #takes way too much time
                            
                            packages=model.ownedElement.select(lambda l: l.oclIsKindOf(metamodel.Package)\
                                                               and l.name!="python2_2")
                            allPackages=packages
                            pack=None
                            while packages:
                                pack=packages[0]
                                packa=pack.ownedElement.select(lambda l:l.oclIsKindOf(metamodel.Package))
                                for pa in packa:
                                    packages.append(pa)
                                    allPackages.append(pa)
                                packages=packages[1:]

                            classes=[]
                            for p1 in allPackages:
                                classes.extend(p1.ownedElement.select(lambda l:l.oclIsKindOf(metamodel.Class) and l.name==names[len(names)-1]))
                            for x in classes:
                                ok=1
                                ele=x
                                for y in range(len(names)-2):
                                    if ele.namespace.name!=names[len(names)-2-y]:
                                        ok=0
                                        break
                                    ele=ele.namespace

                                if ok:
                                    g=metamodel.Generalization()
                                    g.child=chi
                                    g.parent=x
                                    par=x

                                    self.nameGen(g,par,chi)
                                    
                                    ns=None
                                    cnspaces=[]
                                    cns=chi.namespace
                                    while cns:
                                        cnspaces.append(cns)
                                        cns=cns.namespace
                                    pns=x.namespace
                                    while pns:
                                        if not ns and (pns in cnspaces):
                                            ns=pns
                                        pns=pns.namespace
                                    g.namespace=ns
                                    
                                    break
                        continue


                    par=None
                    f=''
                    if string.find(cp.file,'/__init__.py')!=-1:
                        f=string.split(cp.file,'/__init__.py')[0]
                    elif cp.file[-3:]=='.py':
                        f=cp.file[:-3]

                    ## addition
                    if string.find(cp.file,"umlcoresupport.py")!=-1:
                        # check for Round Trip Engineering, leave the generalization to umlcoresupport classes out.
                        break
                    ## addition
                    if not os.path.normpath(f) in self.thisPacks.keys():
                        #print f
                        # didn't find the file in dictionary
                        pps=model.ownedElement.select(lambda x: x.oclIsKindOf(metamodel.Package) and (x.name=='python2_2' or x.name=='python2.2'))
                        if not len(pps):
                            print 'warning: no python package available in the model'
                            continue
                        pp=pps[0]
                        mods=pp.ownedElement.select(lambda x: x.oclIsKindOf(metamodel.Package)and x.name==cp.module)
                        if not len(mods):
                            print 'warning: ', cp.module, ' not available in python package'
                            continue
                        mod=mods[0]
                        cls=mod.ownedElement.select(lambda x: x.oclIsKindOf(metamodel.Class) and x.name==cp.name)
                        if not len(cls):
                            print 'warning: class',cp.name,'not available in module',cp.module
                            continue
                        par=cls[0]
                    else:
                        cls=self.thisPacks[os.path.normpath(f)].ownedElement.select(lambda x: x.oclIsKindOf(metamodel.Class) and x.name==cp.name)
                        if not len(cls):
                            print 'warning: class',cp.name,'not found in package',self.thisPacks[os.path.normpath(f)].name
                        par=cls[0]
                                           
                    g=metamodel.Generalization()
                    g.child=chi
                    g.parent=par

                    self.nameGen(g,par,chi)
                                                               
                    #find the namespace
                    g.namespace=self.getNamespace(chi,par)
                    
##                    ns=None
##                    cnspaces=[]
##                    cns=chi.namespace
##                    while cns:
##                        cnspaces.append(cns)
##                        cns=cns.namespace
##                    pns=par.namespace
##                    while pns:
##                        if not ns and (pns in cnspaces):
##                            ns=pns
##                        pns=pns.namespace
##                    g.namespace=ns

    def nameGen(self,g,par,chi):
        childL=self.getLayer(chi)
        parentL=self.getLayer(par)
        if childL and parentL:
            g.name="layerGen"+string.capitalize((parentL.name)[0])+\
                    (parentL.name)[1:]+string.capitalize((par.name)[0])+\
                    (par.name)[1:]+string.capitalize((childL.name)[0])+\
                    (childL.name)[1:]+string.capitalize((chi.name)[0])+\
                    (chi.name)[1:]+str(self.layerNumber)
            self.layerNumber+=1
        else:
            g.name="generalization"+str(self.normalNumber)
            self.normalNumber+=1

    def getLayer(self,ele):
        namesp=ele
        while 1:
            if namesp.taggedValue.select(lambda l: l.name=="Layer"):
                return namesp
            if namesp.namespace:
                namesp=namesp.namespace
            else:
                break
        return

    def processVisibility(self,feat,name):
        methodName=name
        if name[:2]=="__":
            methodName=name[2:]
            feat.visibility=metamodel.VisibilityKind().vk_protected
        elif name[:1]=="_":
            methodName=name[1:]
            feat.visibility=metamodel.VisibilityKind().vk_private
        return methodName

    def processDocumentation(self,operation, body):
        """
        """
        tmp = string.split(body, '\n')
        body=''
        doc = ''
        inDoc = 0
        for x in tmp:
            if string.find(x,'"""') == 0:
                if not inDoc and x == tmp[0]:
                    doc = doc + x[3:] +"\n"
                    inDoc = 1
                    continue
                else:
                    inDoc = 0
                    continue
                
            if inDoc:
                doc = doc + x + "\n"
            
            if not inDoc:
                body = body + x + "\n"
        if doc!='':
            self.addTag("documentation",operation,doc)
        return body

    def processConditions(self,operation, body):
        """
        search pre/post Conditions ans adds them to operation
        and removes them from operation body
        """
        
        tmp = string.split(body, '\n')
        body = ''
        inPre = 0
        inPost= 0
        condBody = ''
       
        for x in tmp:
            y = string.lstrip(x)
            if y == "self.invariants()" or y == "preCondition()" or y == "postCondition()":
                continue
            
            if inPre:
                if string.find(x," ")==0: # or string.find(x,"\t")==0:
                    
               
                    condBody = condBody +x.lstrip(" ") +"\n"
                  
                else:
                    inPre=0
                    self.addTag('preCondition', operation, string.strip(condBody))
                    condBody=''
            
            if x == "def preCondition():":
                inPre = 1
               

            if inPost:
                if string.find(x," ")==0  or string.find(x,"\t")==0:
                    condBody = condBody + x.lstrip(' ') +"\n"
                else:
                    inPost=0
                    self.addTag('postCondition',operation,string.strip(condBody))
                    condBody=''
                    
            if x == "def postCondition():":
                inPost = 1

            if not inPre and not inPost:
                body = body+x+'\n'

        return string.strip(body)

    def searchImport(self,fname,asname):
        """
        searches the given file for imports of type 'from X import Y as A' for the occurances
        where A equals asname
        -returns the whole path X.Y
        """
        inCommentFlag=0
        res=""

        inFile = open(fname,"r") 
        while 1: 
            s = inFile.readline() 
            if (s == ""): 
                break
            
            commentPos=string.find(s,"\"\"\"")
            if commentPos!=-1 and string.count(s,"\"\"\"")<2:
                if inCommentFlag:
                    inCommentFlag=0
                else:
                    inCommentFlag=1
                    
            if not inCommentFlag:
                fromPlace=string.find(s,"from ")
                importPlace=string.find(s," import ")
                asPlace=string.find(s," as "+asname)
                if fromPlace!=-1 and importPlace!=-1 and asPlace!=-1 and fromPlace<importPlace and importPlace<asPlace:
                    commentPlace=string.find(s,"#")
                    strPlace=string.find(s,"\"")
                    str1Place=string.find(s,"'")
                    if (commentPlace!=-1 and commentPlace<importPlace) or (strPlace!=-1 and strPlace<importPlace) or \
                           (str1Place!=-1 and str1Place<importPlace):
                        continue
                    else:
                        temp=string.split(s,"from ")[1]
                        s1=string.split(temp," import ")
                        s2=string.split(s1[1]," as ")
                        res=s1[0]+"."+s2[0]
                        return res
                    
                
                
            

     
    def anyClass(self,package): 
        """ Searches for a class from the given package. Returns a class if one or more exists, 
        else returns None. """ 
        if not isinstance(package,metamodel.ModelElement):
            return
 
        if (package.oclIsKindOf(metamodel.Package) and \
            package.namespace) or \
            package.oclIsKindOf(metamodel.Class)  or \
            package.oclIsKindOf(metamodel.Model): 
     
            if package.oclIsKindOf(metamodel.Class): 
                return package 
 
            element=package 
            while (not element.oclIsKindOf(metamodel.Model) or element.namespace): 
                element=element.namespace 
 
            if element.oclIsKindOf(metamodel.Model): 
 
                namespaces=[element] 
                while namespaces: 
                    ns=namespaces.pop() 
 
                    classes=ns.ownedElement.select(lambda x : x.oclIsKindOf(metamodel.Class)) 
                    if classes: 
                        return classes[0] 
 
                    packages=ns.ownedElement.select(lambda x : x.oclIsKindOf(metamodel.Package)) 
                    namespaces.extend(packages) 
             
        return 
     
 
    def isPackage(self, path): 
        """ 
        Tests wether the path is a package (contains __init__.py) 
        Returns 1 if the given path is a package else returns 0 
        """ 

        if not os.access(path, os.R_OK): # Check for read permission 
            return 0 
         
        files = os.listdir(path)       
        for fname in files: 
            if (fname == "__init__.py"): 
                return 1   
        return 0 
 
    def readPackageMethods(self,fname):
        # DEPRECATED - uml doesn't allow operations to be attached to packages
        
        """ 
        Reads through the fname file and returns all the methods outside classes 
        """ 
        inFile = open(fname + ".py","r") 
        methodNames = [] 
        inClassFlag=0        
        inCommentFlag=0 
        ignoreFlag=0
        
         
        while 1: 
            s = inFile.readline() 
            if (s == ""): 
                break 

            if ignoreFlag:
                ignoreFlag=0
                continue

            if string.find(s,"# AUTOMATICALLY GENERATED CODE - HIDE IN ROUND TRIP ENGINEERING")!=-1:
                ignoreFlag=1
                continue

            classPos=string.find(s,"class") 
            commentPos=string.find(s,"\"\"\"") 
 
            firstLetter=string.find(s," ") 
            isFirstNewline=string.find(s,"\n") 
            isFirstCommentMark=string.find(s,"#") 
            isSomeSpecialMark=-1 
            if string.find(s,"\r")==0 or string.find(s,"\v") or string.find(s,"\f"): 
                isSomeSpecialMark=0 
 
            if(classPos==0): 
                inClassFlag=1 
            elif(commentPos!=-1 and string.count(s,"\"\"\"")<2): 
                if(inCommentFlag): 
                    inCommentFlag=0 
                else: 
                    inCommentFlag=1 
 
            elif(firstLetter!=0 and isFirstNewline!=0 and isFirstCommentMark!=0 and isSomeSpecialMark!=0): 
 
                inClassFlag=0 
            defPos=string.find(s,"def ") 
            if ((defPos==0 or (defPos>0 and not inClassFlag)) and not inCommentFlag): 
                defInTheMiddleFlag=0 
                # check wether some characters exists before the keyword def 
                for x in range(defPos): 
                    if(s[x]!=" "): 
                        defInTheMiddleFlag=1 
 
                if(not defInTheMiddleFlag): 
                    modLine=string.replace(s[defPos:],"("," ") 
                    sepWords=string.split(modLine," ") 
                    methodNames.append(sepWords[1]) 
                 
        return methodNames 
 
    def readClassMethods(self,fname,cname): 
        """ 
        Reads through the fname file and returns all the methods inside defined class

        Returns

        tuple, containing two dictionaries:
          - The first one contains method names as keys and method body as a value
          - The second one contains method names as keys and list of parameters
            as a value 
        """ 
        inFile = open(fname + ".py","r") 
        methodNames = {}
        methodParameters={}
        inClassFlag=0        
        inCommentFlag=0 
        currentDef="" 
        c=0 
        reduce=0 
        defTab=-1 
        operIndent=0               # operation indentation
        methodBody=""              # body of method is stored here
        start=0
        ignoreFlag=0               # flag wether next iteration should be ignored

        defaultName=""             # in case of polymorphic operation - use the original name
        nameCount=0                # flag for saving the name for next iteration
        nameIter=0                 # give all polymorphic operations an unique ending so that
                                   # they can be stored in the dictionary
 
        while 1: 
            c+=1 
            s = inFile.readline() 
 
            if (s == ""): 
                if inClassFlag and currentDef: 
                    methodNames[currentDef]=methodBody 
                break

            if ignoreFlag:
                ignoreFlag=0
                continue

            if string.find(s,"# AUTOMATICALLY GENERATED CODE - HIDE IN ROUND TRIP ENGINEERING")!=-1:
                ignoreFlag=1
                continue

            if string.find(s,"UMLClass.__init__")!=-1:
                # do not add the generated __init__ call to UMLClass
                continue

            if string.find(s,"# AUTOMATICALLY GENERATED POLYMORPHIC OPERATION :")!=-1:
                defaultName=string.strip(string.split(s,"OPERATION :")[1])+")"+str(nameIter)
                nameIter+=1
                nameCount=0
            elif nameCount==2:
                defaultName=""
            nameCount+=1
            
            classPos=string.find(s,"class "+cname) 
            commentPos=string.find(s,"\"\"\"")
             
            isFirstNewline=string.find(s,"\n") 
            isFirstCommentMark=string.find(s,"#") 
            isSomeSpecialMark=-1 
            if string.find(s,"\r")==0 or string.find(s,"\v")==0 or string.find(s,"\f")==0: 
                isSomeSpecialMark=0 
 
            s=s[reduce:] 
            firstLetter=string.find(s," ") 
            tab=string.find(s,"\t") 
 
            if(classPos==0):
                 inClassFlag=1 
            elif(commentPos!=-1 and string.count(s,"\"\"\"")<2):
 
                if(inCommentFlag): 
                    inCommentFlag=0 
                else: 
                    inCommentFlag=1
 
            elif(classPos>0): 
                charBefore=0 
                for x in range(classPos): 
                    if(s[x]!=" "): 
                        charBefore=1 
                if(not charBefore): 
                    inClassFlag=1 
                    reduce=classPos 
             
 
                 
            elif((firstLetter!=0 and tab!=0) and isFirstNewline!=0 and isFirstCommentMark!=0 and isSomeSpecialMark!=0 and string.find(s,"\"")!=0): 
                if inClassFlag: #leaving the examined class body 
                    inClassFlag=0
                    if currentDef:
                        methodNames[currentDef]=methodBody 
                reduce=0 
              
            defPos=string.find(s,"def ") 
 
            if (((defPos>0 and inClassFlag)) and not inCommentFlag): 
                defInTheMiddleFlag=0 
                # check wether some characters exists before the keyword def 
                for x in range(defPos): 
                    if(s[x]!=" " and s[x]!="\t"): 
                        defInTheMiddleFlag=1 
 
                 
                if(not defInTheMiddleFlag and defTab<0): 
                    modLine=string.replace(s[defPos:],"("," ")
                    paramLine = None


                    if string.find(s,')') != -1:
                        paramLine = string.split(string.split(s,'(')[1],')')[0]
                    else:
                        paramLine = string.split(s,'(')[1]
                        while 1:
                            line = inFile.readline()
                            paramLine += string.split(line,')')[0]
                            if string.find(line,')') != -1:
                                break
                    
                    sepWords=string.split(modLine," ") 
                    if defaultName:
                        currentDef=defaultName
                        methodBody = ''
                    else:
                        currentDef=sepWords[1]
                        methodBody = ''
                    defTab=defPos
                    
                    params =string.split(paramLine,",")
                    
                    temp=[]
                    for p in params:
                        p = string.replace(p,'*',' ')
                        p = string.replace(p,'\n',' ')
                        p = string.strip(p)
                        temp.append(p)
                    params=temp
                    if 'self' in params:    
                        params.remove('self')
                        
                    methodParameters[currentDef] = params
                    
                    start=1 
                     
                elif not defInTheMiddleFlag and defPos==defTab: 
                    modLine=string.replace(s[defPos:],"("," ") 
                    sepWords=string.split(modLine," ")
                    paramLine = None

                    if string.find(s,')') != -1:
                        paramLine = string.split(string.split(s,'(')[1],')')[0]
                    else:
                        paramLine = string.split(s,'(')[1]
                        while 1:
                            line = inFile.readline()
                            paramLine += string.split(line,')')[0]
                            if string.find(line,')') != -1:
                                break
                                  
                    if currentDef:
                        methodNames[currentDef]=methodBody 
                    methodBody=""
                    if defaultName:
                        currentDef=defaultName
                    else:
                        currentDef=sepWords[1]
                    
                    params =string.split(paramLine,',')
                    temp=[]
                    for p in params:
                        p = string.replace(p,'*',' ')
                        p = string.replace(p,'\n',' ')
                        p = string.strip(p)
                        temp.append(p)
                    params=temp
                    if 'self' in params:    
                        params.remove('self')
                    methodParameters[currentDef] = params
                    start=1 
                else: 
                    if inCommentFlag and string.find(string.strip(s),"\"\"\"")==0: 
                        methodBody=methodBody+string.strip(s)
 
                    else: 
 
                        if start and string.strip(s)!="": 
 
                            operIndent=string.find(s,string.strip(s)) 
                            start=0 
                        if string.find(string.strip(s),"#")==0:
                             methodBody=methodBody+s 
                        elif string.count(s,"\"\"\"")==2 and string.find(string.strip(s),"\"\"\"")==0:
                             methodBody=methodBody+string.lstrip(s) 

                        else:
                            methodBody=methodBody+s[operIndent:] 
                             
            elif inClassFlag and classPos!=0: 
                if inCommentFlag and string.find(string.strip(s),"\"\"\"")==0: 
                    methodBody=methodBody+string.strip(s)

                elif string.find(string.strip(s),"#")==0: 
                    methodBody=methodBody+s
                     
                elif string.count(s,"\"\"\"")==2 and string.find(string.strip(s),"\"\"\"")==0: 
                    methodBody=methodBody+string.lstrip(s)

                else: 
                    if start and string.strip(s)!="": 
                        operIndent=string.find(s,string.strip(s)) 
                        start=0 
                    methodBody=methodBody+s[operIndent:]

            else: 
                start=0 
                 
        return methodNames,methodParameters 
 
    def readClassInstanceAttributes(self,fname,cname): 
        """ 
        Reads through the file fname and returns all the instance attributes found
        inside class cname __init__ method
        if sfi option on:
        -search instance attributes from the automatically generated __init__
        -search classifier attributes normally
        -if __init__ is defined without the marking keywords 'AUTOMATICALLY ...' no instance classifiers
         are generated (they will be in the __init__ operation specification instead)
        else:
        -instance attributes from __init__

        """ 
         
        inFile=open(fname+".py","r") 
        attrNames=[] 
        inClassFlag=0 
        notInComment=1
        ignoreFlag=0
        inInit=0
 
        indentationLength=0 
        while 1: 
            s=inFile.readline() 
             
            if(s==""): 
                break 


            #if ignoreFlag:
            #    ignoreFlag=0
            #    #continue

            if string.find(s,"# AUTOMATICALLY GENERATED CODE - HIDE IN ROUND TRIP ENGINEERING")!=-1:
                ignoreFlag=1
                continue
 
            firstChar=s[0] 
  
            if(firstChar!=" " and firstChar!="\n" and inClassFlag==1): 
                inClassFlag=0 
                break 
             
            classPos=string.find(s,"class "+cname) 
            if(classPos==0): 
                inClassFlag=1 
 
            elif(classPos>0): 
                charBefore=0 
                for x in range(classPos): 
                    if(s[x]!=" "): 
                        charBefore=1 
                if(not charBefore): 
                    inClassFlag=1 
 
            elif(inClassFlag and string.count(s,"\"\"\"")==1): 
                if(notInComment):                     
                    notInComment=0 
                else: 
                    notInComment=1 
 
            elif(inClassFlag):
                if(indentationLength==0): 
                    for x in range(len(s)): 
                        if(s[x]!=" "): 
                            break 
                        else:                             
                            indentationLength+=1 
 
                if(firstChar!="\n" and len(s)>indentationLength+1 and s[indentationLength+1]!=" "): 
                    s=s[indentationLength:] 

                if inInit and ignoreFlag:
                    if(notInComment): 
                        withoutComment=string.split(s,"#")[0] 
 
                        words=string.split(withoutComment,"=") 
 
                        for x in range(len(words)-1): 
                            if(string.find(words[x],"[")<0 and string.find(words[x],"(")<0):  #don't add the duplicates 
                                words[x]=string.strip(words[x]) 
                                #drop the array element out if it has more words than one and if it contains " or ' 
                                if(string.find(words[x]," ")<0 and string.find(words[x],"\"")<0 and string.find(words[x],"'")<0): 
                                    if(words[x]!=""): #drop the empty elements out 
                                        attrs=string.split(words[x],",") #find the multiple attributes 
                                        for elem in attrs:
                                            if string.find(elem,"self.")==0:
                                                elem=string.split(elem,"self.")[1]
                                                attrNames.append(string.strip(elem))                     
 
                #now s is def, attribute or classDescription
                if(s[0]!=" " and s[0]!="\n" and s[0]!="\""):                
                    if string.find(s,"def __init__")==0:
                        inInit=1
                    else:
                        inInit=0
                        ignoreFlag=0
        
        return attrNames

    
    def readClassAttributes(self,fname,cname): 
        """ 
        Reads through the fname file and returns all the classifier attributes inside class cname 

        """
         
        inFile=open(fname+".py","r") 
        attrNames=[] 
        inClassFlag=0 
        notInComment=1
        ignoreFlag=0
 
        indentationLength=0 
        while 1: 
            s=inFile.readline() 
             
            if(s==""): 
                break 


            if ignoreFlag:
                ignoreFlag=0
                continue

            if string.find(s,"# AUTOMATICALLY GENERATED CODE - HIDE IN ROUND TRIP ENGINEERING")!=-1:
                ignoreFlag=1
                continue
 
            firstChar=s[0] 
  
            if(firstChar!=" " and firstChar!="\n" and inClassFlag==1): 
                inClassFlag=0 
                break 
             
            classPos=string.find(s,"class "+cname) 
            if(classPos==0): 
                inClassFlag=1 
 
            elif(classPos>0): 
                charBefore=0 
                for x in range(classPos): 
                    if(s[x]!=" "): 
                        charBefore=1 
                if(not charBefore): 
                    inClassFlag=1 
 
            elif(inClassFlag and string.count(s,"\"\"\"")==1): 
                if(notInComment):                     
                    notInComment=0 
                else: 
                    notInComment=1 
 
            elif(inClassFlag):
                #if cname=="class3":
                #    print s,
                if(indentationLength==0): 
                    for x in range(len(s)): 
                        if(s[x]!=" "): 
                            break 
                        else:                             
                            indentationLength+=1 
 
                if(firstChar!="\n" and len(s)>indentationLength+1 and s[indentationLength+1]!=" "): 
                    s=s[indentationLength:] 
 
                #now s is def, attribute or classDescription 
                if(s[0]!=" " and s[0]!="\n" and s[0]!="\"" and string.find(s,"def ")!=0): 
                    if(notInComment): 
                        withoutComment=string.split(s,"#")[0] 
 
                        words=string.split(withoutComment,"=") 
 
                        for x in range(len(words)-1): 
                            if(string.find(words[x],"[")<0 and string.find(words[x],"(")<0):  #don't add the duplicates 
                                words[x]=string.strip(words[x]) 
                                #drop the array element out if it has more words than one and if it contains " or ' 
                                if(string.find(words[x]," ")<0 and string.find(words[x],"\"")<0 and string.find(words[x],"'")<0): 
                                    if(words[x]!=""): #drop the empty elements out 
                                        attrs=string.split(words[x],",") #find the multiple attributes 
                                        for elem in attrs: 
                                            attrNames.append(string.strip(elem)) 
                             


        
        return attrNames 
 
 
    def readPackageAttributes(self,fname):
        """ 
        Reads through the fname file and returns all the attributes outside classes 
        """
        # DEPRECATED - uml doesn't allow operations to be attached to packages        
        infile=open(fname+".py","r") 
        inCommentFlag=0 
        attributes=[]
        ignoreFlag=0
 
        while 1: 
            s=infile.readline() 
             
            if(s==""): 
                break 

            if ignoreFlag:
                ignoreFlag=0
                continue

            if string.find(s,"# AUTOMATICALLY GENERATED CODE - HIDE IN ROUND TRIP ENGINEERING")!=-1:
                ignoreFlag=1
                continue
             
            firstChar=s[0] 
 
 
            if(s[0]!=" " and s[0]!="\n"): 
                if(string.find(s,"\"\"\"")>=0 and string.count(s,"\"\"\"")==1): 
                    if(inCommentFlag): 
                        inCommentFlag=0 
                    else: 
                        inCommentFlag=1 
 
                if(not inCommentFlag): 
                    withoutComment=string.split(s,"#")[0] 
 
                    words=string.split(withoutComment,"=") 
 
                    for x in range(len(words)-1): 
                        if(string.find(words[x],"[")<0 and string.find(words[x],"(")<0):  #don't add the duplicates 
                            words[x]=string.strip(words[x]) 
                            #drop the array element out if it has more words than one or if it contains " or ' 
                            if(string.find(words[x]," ")<0 and string.find(words[x],"\"")<0 and string.find(words[x],"'")<0): 
                                if(words[x]!=""): #drop the empty elements out 
                                    attrs=string.split(words[x],",") 
                                    for elem in attrs: 
                                        attributes.append(string.strip(elem)) 
                             
        return attributes 
                 
 
    def readClassNames(self, fname): 
        """ 
        Reads through the fname file and returns all the class names 
        """ 
        inFile = open(fname + ".py", "r") 
        cNames=[]
        inCommentFlag=0 
        importDic={} 
         
        while 1: 
            s = inFile.readline() 
            # flags for if and else in first indentation
            prevIf=0                            
            prevElse=0 
  
            if (s == ""): 
                break 
 
            classIsFirstWord=0 
 
            classPos=string.find(s,"class") 
            if(classPos==0): 
                classIsFirstWord=1 

            commentPos=string.find(s,"\"\"\"") 
             
            if(commentPos!=-1 and string.count(s,"\"\"\"")<2): 
                if(inCommentFlag): 
                    inCommentFlag=0 
                else: 
                    inCommentFlag=1 
                     
            elif(classPos>0): 
                charBefore=0 
                for x in range(classPos): 
                    if(s[x]!=" "): 
                        charBefore=1 
                if(not charBefore): 
                    classIsFirstWord=1 
                    s=s[classPos:] 
           
            if (not inCommentFlag and classIsFirstWord and string.split(s," ")[0]=="class"): 
 
                 
                s=re.sub('\s','',s) 
                cname = s[5:len(s)-1] 
             
                i = string.find(cname,"(") 
                if (i != -1): # remove the inherited classes 
                    cname = cname[0:i] 
                     
                cNames.append(cname)      

        return cNames 

    def checkIfLayer(self, fname, element): 
        """ 
        Reads through the fname file and returns all the class names 
        """ 
        if fname[-1]=="/":
            fname=fname[:-1]
        if not os.path.isfile(fname+"/__init__.py"):
            return
        inFile = open(fname + "/__init__.py", "r") 
        while 1: 
            s = inFile.readline() 
            if (s == ""): 
                break
            if string.find(s,"#_type_ == layer")==0:
                temp=string.split(s,"_succs_ == ")
                succsStr=""
                if len(temp)==2:
                    succsStr=temp[1]
                    succsStr=string.split(succsStr,"\n")[0]
                    
                #layer tag
                self.addTag("Layer",element,succsStr)
                
##                tag=metamodel.TaggedValue()
##                tagDef=metamodel.TagDefinition()
##                tagDef.multiplicity.range.add( \
##                metamodel.MultiplicityRange(multiplicity=tagDef.multiplicity,lower=1,upper=1))
##                tag.name="Layer"
##                tagDef.name="Layer"
##                element.namespace.ownedElement.append(tag)
##                element.namespace.ownedElement.append(tagDef)
##                tag.type=tagDef
##                element.taggedValue.append(tag)
                return 1

        return 0

    def initSfiModel(self,model):
        if not model:
            return
        tagDefs=["correctness","application","Layer","testcase",
                "LayerDependency","LayerPackageDependency","componentContents",
                 'invariants','preCondition','postCondition','documentation']

        stereoTypes=["plain text","configuration"]

        for x in tagDefs:
            tagDef=model.ownedElement.select(lambda l: l.oclIsKindOf(metamodel.TagDefinition) and \
                                         l.name==x)
            if len(tagDef)==0:
                tagDef=metamodel.TagDefinition()
                tagDef.multiplicity.range.add( \
                metamodel.MultiplicityRange(multiplicity=tagDef.multiplicity,lower=1,upper=1))
                tagDef.name=x
                model.ownedElement.append(tagDef)        

    def addTag(self,name,element,value=None):
        tagDefs=["correctness","application","Layer","testcase",
                "LayerDependency","LayerPackageDependency","componentContents",
                 'invariants','preCondition','postCondition','documentation']        

        tag=metamodel.TaggedValue()
        if not name in tagDefs:
            return

        tagDef=self.model.ownedElement.select(lambda l: l.oclIsKindOf(metamodel.TagDefinition) and \
                                         l.name==name)
        if len(tagDef)==0:
            tagDef=metamodel.TagDefinition()
            tagDef.multiplicity.range.add( \
                metamodel.MultiplicityRange(multiplicity=tagDef.multiplicity,lower=1,upper=1))
            tagDef.name=name
            self.model.ownedElement.append(tagDef)
        else:
            tagDef=tagDef[0]

        tag.name=name
        if value:
            tag.dataValue=value

        if element.namespace:
            element.namespace.ownedElement.append(tag)
            
        elif element.oclIsKindOf(metamodel.Operation):
            element.owner.ownedElement.append(tag)
            
        else:
            #case of model
            element.ownedElement.append(tag)
            
            
        tag.type=tagDef

        element.taggedValue.append(tag)

        
    def createLayerDependencies(self,package):
        layers=package.ownedElement.select(lambda l:len(l.taggedValue.select(lambda ll:ll.name=="Layer")))
        for x in layers:
            tag=x.taggedValue.select(lambda l:l.name=="Layer" and l.dataValue!="")
            if tag:
                tag=tag[0]
                succs=string.split(tag.dataValue,":")
                for y in range(len(succs)):
                    suc=layers.select(lambda l:l.name==succs[y])
                    if len(suc)==1:
                        dep=metamodel.Dependency()
                        dep.supplier.append(x)
                        dep.client.append(suc[0])
                        dep.name="layerDep"+x.name+suc[0].name
                        dep.namespace=package
                        self.addTag("LayerDependency",dep)


    def createTestDependencies(self,pack):
        print "creating test dependencies"
        if not self.testClasses:
            return
        for x in self.testClasses:
            testTag=x.taggedValue.select(lambda l: l.name=="testcase")[0]
            if testTag.dataValue:
                depName=testTag.dataValue
                path=string.split(depName,".")
                if path[0]!=pack.name:
                    return
                curEle=pack
                del path[0]
                for y in path:
                    selection=curEle.ownedElement.select(lambda l: l.name==y)
                    if not selection:
                        return
                    curEle=selection[0]

                dep=metamodel.Dependency()
                dep.client.append(x)
                dep.supplier.append(curEle)
                dep.name="testDep"+string.capitalize(curEle.name[0])+curEle.name[1:]


                # TODO, make a method from the next piece (used in generalization creation also)
                #find the namespace
                dep.namespace=self.getNamespace(x,curEle)
                
##                ns=None
##                cnspaces=[]
##                cns=x.namespace
##                while cns:
##                    cnspaces.append(cns)
##                    cns=cns.namespace
##                pns=curEle.namespace
##                while pns:
##                    if not ns and (pns in cnspaces):
##                        ns=pns
##                    pns=pns.namespace
##                dep.namespace=ns

    def getNamespace(self,ele1,ele2):
        ns=None
        cnspaces=[]
        cns=ele1.namespace
        while cns:
            cnspaces.append(cns)
            cns=cns.namespace
        pns=ele2.namespace
        while pns:
            if not ns and (pns in cnspaces):
                ns=pns
            pns=pns.namespace        
        return ns    
                

    def readTestSupplier(self,fileName,clName):

        if not os.path.isfile(fileName + ".py"):
            return
        
        inFile = open(fileName + ".py", "r") 
        readNext=0
         
        while 1: 
            s = inFile.readline() 
  
            if (s == ""): 
                break

            if readNext:
                if string.find(s,"# SOURCE :")!=-1:
                    source=string.split(s,"# SOURCE :")
                    source=source[1]                    
                    source=string.strip(source)
                    return source

            if string.find(s,"class "+clName)==0:
                readNext=1
            else:
                readNext=0


if __name__ == '__main__':    
    p=py2uml()
    path,sName=p.getOption() 
    p.convert(path,sName)

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
