view MPIWGThesaurus.py @ 41:9a23640f7f49

added getAllProjectsAndTagsAsCSV.
author casties
date Wed, 30 Oct 2013 17:43:03 +0100
parents 4342a81e0aa0
children b1f5d42bb93b
line wrap: on
line source

#Klasse zum Taggen und Anzeigen der Tags von Projekte bzw. allgemein Webseiten des Institutes
#Tags werden in der Instanz abgespeichert
#Personenname kommen aus dem Virtuoso-Triplestore , lokal erzeugte zusaetliche Name werden dort abgespeichert
#Fuer die Suche ueber die Personenname wird das MetaDataManagerRestlet benoetigt.
#TODO: Zur Zeit werden die entsprechenden Server URLs hier in der Klasse definiert.


# TODO: generell verwaltung der tags im triple store und nicht in zope.
# TODO: mache server und namespaces konfigurierbar im project


from OFS.Folder import Folder
from Globals import package_home
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from BTrees.OOBTree import OOBTree
from BTrees.OOBTree import OOSet
from AccessControl import ClassSecurityInfo

#import os
import re
import os.path
import logging
import time
import email.Utils
from types import ListType
import transaction
import random
import urllib2
import urllib

from SrvTxtUtils import utf8ify

class projectHolder:
            projectHolder=""
            projectName=""
            projectID=""
            persons=""
            tags={}
            
            def __init__(self,ID):
                self.projectID=ID
                self.tags={}
                
#Entry beschreibt jeweils einen Tag mit dem Namen "title", entries enthaelt eine Liste von Subtags (der Klasse Entry), die diesem Tag untergeordnet sind.
class Entry:
    """publicClass"""
    
    #===========================================================================
    # __init__
    #===========================================================================
    def __init__(self,title,entries=[]):
        self.title=title
        self.entries=entries
        
    def getTitle(self):
        """getTitle"""
        return self.title
    
#Beschriebt einen von einem Benutzer vorgeschlagenen Tag      
class SuggestedTag:
    """publicClass"""
    type=""
    userName=""
    def __init__(self,name,comment,type,userName):
        self.name=name
        self.comment=comment
        self.type=type
        self.userName=userName
        

class MPIWGThesaurus(Folder):
    """MPIWGThesaurus main folder"""
    security=ClassSecurityInfo()

    meta_type="MPIWGThesaurus"
   
    TMP_PERSON_NS="http://ontologies.mpiwg-berlin.mpg.de/tempObjects/person/"
    ONTOLOGY_NS="http://ontologies.mpiwg-berlin.mpg.de/authorities/namedIdentities/"
    personproviderURL="http://127.0.0.1:8280/MetaDataManagerRestlet/person/"
    #personproviderURL="http://virtuoso.mpiwg-berlin.mpg.de:8080/MetaDataManagerRestlet/person/"
    #PERSONS_LOOKUP_URL="http://127.0.0.1:8280/MetaDataManagerRestlet/search/persons"
    PERSONS_LOOKUP_URL="http://127.0.0.1:8280/MetaDataManagerRestlet/persons"
    EDIT_URL="http://127.0.0.1:8280/MetaDataManagerRestlet/edit?id="
    #PERSONS_LOOKUP_URL="http://virtuoso.mpiwg-berlin.mpg.de:8080/MetaDataManagerRestlet/person/"
    
    additionalNamesGraphURL="file://newpersonsFromProjects"
    
    #virtuosoServer="http://ontologies.mpiwg-berlin.mpg.de"
    virtuosoServer="http://virtuoso.mpiwg-berlin.mpg.de:8890"
    virtuosoDAV="/DAV/home/websiteuser/"
    virtuosoDAVUser="websiteuser"
    virtuosoDAVPW="w3s45us3"
    virtuosoGraph="file://newpersonsFromProjects"
    
    logpathDefault="/var/tmp/tagchanges.log"
    
    #BTrees fuer die Tags
    
    projectPersons= OOBTree() #project --> personen IDs
    projectObjects= OOBTree() #project --> objects
    projectHistoricalPlaces= OOBTree()
    projectSuggestedTags= OOBTree()
    persons2Projects= OOBTree() #personenID --> projects
    objects2Projects=OOBTree() #objects --> projects
    historicalPlaces2Projects=OOBTree()
    suggestedTags2Projects=OOBTree()
    personIDtoNames=OOBTree() # weist den personenIDs Klartextnamen aus dem Triplestore zu
    personsIDForSort=[] # liste personenID sortiert nach dem tupel (nachname,vorname)
    personsIDForSortFull=[] # liste (personenID,(nachname,vorname)) nicht sortiert!
   
    suggestedPersons= OOBTree(); #TODO: das sollte die ueberfluessig werde und nur im triple store stehen.
    
    tagList=[]
    
    #default liste fuer tags, wird ueber das Managementinterface ueberschrieben
    approachesTxt="""A
    ---
    ent1
    ---
    B
    ---
    enta
    entb
    entc
    """
    
    disciplines=[]
    disciplinesTxt="""A
   B
   C
    """
    
    periods=[]
    periodsTxt="""PA
   PB
   PC
    """
    
    spaces=[]
    spacesTxt="""SPA
    ---
    sPent1
    ---
    SPB
    ---
    SPenta
    SPentb
    SPentc
    """
    technologies=[]
    technologiesTxt="""TPA
    ---
    TPent1
    ---
    TPB
    ---
    TPenta
    TPentb
    TPentc
    """
    
    knowledgeTransfers=[]
    knowledgeTransfersTxt="""KTPA
    ---
    TPent1
    ---
    TPB
    ---
    TPenta
    TPentb
    TPentc
    """
    
    
    
    
    
    
    manage_options = Folder.manage_options+(
        {'label':'Thesaurus entries','action':'changeMPIWGThesaurusForm'},
        {'label':'Manage Thesaurus','action':'manageMPIWGThesaurus'},
        {'label':'Thesaurus Log','action':'manageMPIWGThesaurusLogs'},
        #{'label':'Change Publications Special','action':'changePublications_specialForm'},
        )
    
    def __init__(self,id):
        """init"""
        self.id=id
       
        
    def index_html(self):
        """index file"""
              
        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','index.html')).__of__(self)
        return pt()
    
    security.declareProtected('View management screens','changeMPIWGThesaurusForm')
    def changeMPIWGThesaurusForm(self):
        """form for changing the project"""
        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','changeMPIWGThesaurusForm.zpt')).__of__(self)
        return pt()
    
    security.declareProtected('View management screens','manageMPIWGThesaurus')
    def manageMPIWGThesaurus(self):
        """form for changing the project"""
        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','manageMPIWGThesaurus.zpt')).__of__(self)
        return pt()
    
    security.declareProtected('View management screens','manageMPIWGThesaurusLogs')
    def manageMPIWGThesaurusLogs(self):
        """form for changing the project"""
        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','manageMPIWGThesaurusLog.zpt')).__of__(self)
        return pt()
    
    def changeMPIWGThesaurusLog(self,logpath,RESPONSE=None):
        """change log file path"""
        self.logpath=logpath
        
        if RESPONSE is not None:
            redirect(RESPONSE,'manage_main')
     
     
    security.declareProtected('View management screens','changeMPIWGThesaurus')
    def changeMPIWGThesaurus(self,approachesTxt,disciplinesTxt,periodsTxt,spacesTxt,technologiesTxt,knowledgeTransfersTxt,RESPONSE=None):
        """change it"""
        self.approachesTxt=approachesTxt
        self.disciplinesTxt=disciplinesTxt
        self.periodsTxt=periodsTxt
        self.spacesTxt=spacesTxt
        self.technologiesTxt=technologiesTxt
        self.knowledgeTransfersTxt=knowledgeTransfersTxt
    
        if RESPONSE is not None:
            redirect(RESPONSE,'manage_main')
    
    
#    def getAllProjectsAndTagsAsCSV(self,archived=1):
#        """alle projekte auch die nicht getaggten"""
#        retList=[]
#        for project in self.getProjectFields('WEB_title_or_short'):
#            proj = project[0]
#            p_name = project[1]
#            retProj=[]
#            if (not proj.isArchivedProject() and archived==1) or (proj.isArchivedProject() and archived==2):
#                retProj.append(self.utf8ify(p_name))  
#                retProj.append(self.utf8ify(proj.getContent('xdata_01')))   
#                retProj.append("|".join([person[1] for person in self.thesaurus.getPersonsFromProject(proj.getId())]))
#                retProj.append("|".join([person[1] for person in self.thesaurus.getHistoricalPlacesFromProject(proj.getId())]))
#                retProj.append("|".join([person[1] for person in self.thesaurus.getObjectsFromProject(proj.getId())]))
#                retProj.append("|".join(self.thesaurus.getTags(proj.getId())))
#                retList.append("\t".join(retProj))
#
#        return "\n".join(retList);
#    
    def getProjectsAndTags(self):
        """projekte und tags"""
       
        
        projectTags={}
        for tag in self.tags.keys():
            logging.debug("getProjectsAndTags:"+tag)
               # <div class="level1_projects" tal:repeat="proj
               #              python:here.getProjectsWithTag('approaches',here.getTitle(level1))"><a tal:attributes="href
               #                                                         python:proj[0]"><span  tal:content="python:proj[1]">my proj</span><tal:x define="person python:proj[2]"><span
               #                                                                                                          class="person_projects" tal:content="person"/></tal:x></a></div>
               #</div>
            
            for subTag in self.tags.get(tag):
                projs = self.getProjectsWithTag(tag,subTag)
                if not isinstance(projs, ListType):
                    projs=[projs]
                
                for proj in projs:
                    if proj is None:
                        continue
                    projectID=proj[0]
                    logging.debug("PTS"+repr(projectTags))
                    project=projectTags.get(projectID,projectHolder(projectID))
                    project.projectName=proj[1]
                    project.persons=proj[2]
                    logging.debug(project)
                    logging.debug(tag)
                    logging.debug("PROTS"+repr(project.tags))
                    tagsOfType=project.tags.get(tag,OOSet())
                    logging.debug(tagsOfType)
                    tagsOfType.add(subTag.decode('utf-8'))
                                  
                    logging.debug("Adding %s to %s"%(subTag,projectID))
                    project.tags[tag]=tagsOfType
                    
                    projectTags[projectID]=project
                    logging.debug("Saved %s to %s"%(repr(list(tagsOfType)),projectID))
        logging.debug(projectTags)
        
        
        
        return projectTags
    
    def getProjectsAndTagsAsCSV(self):
        """get the projects as tab"""
        ret=""
        
        #genereate headers
        headers=['date','projectPath','projectName','researchers resp']
        headers.extend(list(self.tags.keys()))
        ret+="\t".join(headers)+"\n"
        
        projectTags = self.getProjectsAndTags()
        for projectID in projectTags.keys():
            retarray=[]
            splitted = projectID.split("/") # hiern nur die eingetliche ID ohne den Pfad
            if len(splitted)>0:
                projectIDShort=splitted[-1]
                retarray.append(self.lastChangeInThesaurus.get(projectIDShort,''))
            else:
                retarray.append('')
            retarray.append(projectID)
            project = projectTags.get(projectID)
            retarray.append(project.projectName)
            retarray.append(project.persons)
            
            for tagType in self.tags.keys():
                tags = project.tags.get(tagType,[''])
                retarray.append(";".join(tags))
            
            ret+="\t".join(retarray)+"\n"
                
        return ret
    

    def getAllProjectsAndTagsAsCSV(self,archived=1,RESPONSE=None):
        """alle projekte auch die nicht getaggten"""
        retList=[]
        headers=['projectId','sortingNumber','projectName','scholars','startedAt','completedAt','lastChangeThesaurusAt','lastChangeProjectAt','projectCreatedAt','persons','objects']
        headers.extend(list(self.tags.keys()))
        retList.append("\t".join(headers))
        
        projectTags = self.getProjectsAndTags()
        projects = self.getMPIWGRoot().getProjectFolder().getProjectsAsList(archived=archived)
        for proj in projects:
            p_name = proj.getLabel()
            retProj=[]
            #if (not proj.isArchivedProject() and archived==1) or (proj.isArchivedProject() and archived==2):
            retProj.append(utf8ify(proj.getId()))
            retProj.append(utf8ify(proj.getContent('xdata_05')))
            retProj.append(utf8ify(p_name))  
            retProj.append(utf8ify(proj.getContent('xdata_01')))
            retProj.append(utf8ify(proj.getStartedAt()))
            retProj.append(utf8ify(proj.getCompletedAt()))
            changeDate=self.lastChangeInThesaurus.get(proj.getId(),'') 
            n = re.sub("[:\- ]","",str(changeDate))
            retProj.append(n)
            retProj.append(utf8ify(getattr(proj,'creationTime','20050101000000')))  
            retProj.append("")#TODO: project created at   
            retProj.append(";".join([person[1] for person in self.getPersonsFromProject(proj.getId())]))
            #retProj.append(";".join([person[1] for person in self.thesaurus.getHistoricalPlacesFromProject(proj.getId())]))
            retProj.append(";".join([person[1] for person in self.getObjectsFromProject(proj.getId())]))
            retProj+=self.getTags(proj.getId(),projectTags)
            retList.append("\t".join(retProj))
        
        if RESPONSE:            
            RESPONSE.setHeader('Content-Disposition','attachment; filename="ProjectsAndTags.tsv"')
            RESPONSE.setHeader('Content-Type', "application/octet-stream")
      
        return "\n".join(retList);
    

    def getLogpath(self):
        return getattr(self,"logpath",self.logpathDefault) 
    
    def getLogfile(self,projectID="",date=""):
        
        # logfile format : YYYY-MM-TT HH:mm:ss\tUSER\ttype\tprojectid\CHANGED_TAG_or_OBJECT_or_PERSON 
        if not os.path.exists(self.getLogpath()):
            return ""
        
        fh = open(self.getLogpath(),"r")
        lines=fh.readlines()
    
        if (projectID!=""):
            ret=[]
            for line in lines:
                splitted=line.split("\t")
                if splitted[3]==projectID:
                    ret.append(line)
        
            lines=ret[0:]
            
        if (date!=""):
            ret=[]
            for line in lines:
                splitted=line.split("\t")
                if splitted[0]>=date:
                    ret.append(line)
        
            
            lines=ret[0:]
        
        txt= "".join(lines)
        fh.close()
            
       
            
            
        return txt
    
    #In der Anzeige soll der Name der zitierten Personen in Klartext angezeigt werden, ausserdem die Varianten, wie sie tatsaechlich
    #in den Projekten benutzt werden
    

    def addPersonAndFirstNameFromTripleStore(self, personID):
        mainName, sortName = self.getMainNameFromTripleStore(personID) # hole die hauptbezeichnung aus dem triplestore
        personNames = []
        logging.debug("get person:"+ personID)
        logging.debug("names:"+repr(mainName)+":"+ repr(sortName))
        
        projects=self.persons2Projects.get(personID)
        logging.debug(repr(projects))
        if projects is None:
            projects=[]
            
        for project in projects: #hole die personen aus dem projekte
            logging.debug("Found:project:" + project)
            namesInProject = self.projectPersons.get(project)
            for nameInProjectTuple in namesInProject:
                logging.debug(repr(nameInProjectTuple))
                nameInProject = nameInProjectTuple[1]
                logging.debug(nameInProjectTuple[0] + "??" + personID)
                if nameInProjectTuple[0] == personID:
                    logging.debug("changing")
                    if mainName == "": # es gibt keinen Eintrag im Triplestore fuer name (sollte eigentlich nicht sein, ist dann ein Fehler dort)
                        mainName = nameInProject #nimm dann aber den ersten aus den projekten
                    if nameInProject != mainName:
                        personNames.append(nameInProject)
        
        logging.debug(str(mainName) + "- foundalso :" + ",".join(personNames))
        self.personIDtoNames.update({personID:(mainName, personNames)})
        self.personsIDForSortFull.append((personID, sortName))
        
   
   
    def generateSortingOrderForPersonIDs(self):
        def sort(x,y):
            logging.debug("sort:")
            logging.debug((x[1][0],y[1][0]))
            return cmp(x[1][0],y[1][0])
            
        self.personsIDForSortFull.sort(cmp=sort)
           
        self.personsIDForSort=[x[0] for x in self.personsIDForSortFull]
                                      
        self.personIDtoNames=self.personIDtoNames # make clear that it has changed #TODO: change this to variablen with names _p
    
    security.declareProtected('View management screens','collectPersonNamesToIds')
    def collectPersonNamesToIds(self):
        """Ordne Namen aus dem Triplestore bzw. die vergebenenden Label den Personen-Ids zu."""
        #sollte z.B. gemacht werden, wenn im Triplestore editiert wurde.
        self.personIDtoNames=OOBTree() # loesche alle 
        self.personsIDForSort=[]
        self.personsIDForSortFull=[]
        for personID in self.persons2Projects:
            self.addPersonAndFirstNameFromTripleStore(personID)
            
          
            
                                    
        #sortiere personIDs nach erstmal nach Nachnamene TODO: sortiere nach name,vorname
        
        self.generateSortingOrderForPersonIDs();
#        def sort(x,y):
#            logging.debug("sort:")
#            logging.debug((x[1][0],y[1][0]))
#            return cmp(x[1][0],y[1][0])
#            
#        self.personsIDForSortFull.sort(cmp=sort)
#           
#        self.personsIDForSort=[x[0] for x in self.personsIDForSortFull]
#                                      
#        self.personIDtoNames=self.personIDtoNames # make clear that it has changed #TODO: change this to variablen with names _p
#    
    #Hole die Namen, die einer personID zugeordnet sind.
    def getNamesFromID(self,personID):
        personID=personID.rstrip().lstrip() #make sure no spaces
        logging.debug("<"+personID+">")
        retStr=""
        
        retStr+=self.personIDtoNames.get(personID,[personID])[0] # hole die Hauptbezeichnung, falls keine angeben ist, wird die ID ausgegeben, das is jedoch ein Felher in den Daten!!
        #additionalNames = self.personIDtoNames.get(personID,['',[]])[1]
        #if len(additionalNames)>0:
        #    retStr+=" ("+",".join(additionalNames)+","+")"
        return retStr
    
        
    #Hole die Hauptnamemsansetzung aus dem Triplestore ),falls vorhanden, wenn nicht ist der String leer.
    #ausserdem einen Namen zum sortieren, =  Tupel(nachname, vorname)
    def getMainNameFromTripleStore(self,personID):
        
        
        cmdString ="""select * where { <%s> <http://xmlns.com/foaf/0.1/name> ?name}"""%personID
    
        names= self.callSparql(cmdString)
        
        cmdString ="""select * where { <%s> <http://xmlns.com/foaf/0.1/lastName> ?name}"""%personID
    
        lastName= self.callSparql(cmdString)
        
        cmdString ="""select * where { <%s> <http://xmlns.com/foaf/0.1/firstName> ?name}"""%personID
    
        firstName= self.callSparql(cmdString)
        
        return names,(lastName,firstName)
    
    
    def callSparqlAll(self,cmdString):
        """list of results"""
        auth_handler = urllib2.HTTPBasicAuthHandler()
        auth_handler.add_password(realm='sparql',
                          uri=self.virtuosoServer+"/sparql",
                          user=self.virtuosoDAVUser,
                          passwd=self.virtuosoDAVPW)
                          
        opener = urllib2.build_opener(auth_handler)
        opener.addheaders = [('Content-Type','application/sparql-query')]
        
        logging.debug(cmdString)
        try:
            logging.debug(self.virtuosoServer+"/sparql?" + urllib.urlencode({'query':cmdString,'default-graph-uri':self.virtuosoGraph,'named-graph-uri':'','format':'text/csv'}))
            #r= opener.open(self.virtuosoServer+"/sparql", urllib.urlencode({'query':cmdString,'default-graph-uri':self.virtuosoGraph,'named-graph-uri':'','format':'text/csv'}))
            r= opener.open(self.virtuosoServer+"/sparql", urllib.urlencode({'query':cmdString,'default-graph-uri':'','named-graph-uri':'','format':'text/csv'}))
            namesTxt=r.read()
        except urllib2.URLError, e:
            logging.error(e.code)
            logging.error(e.read())
            
            
            return
        logging.debug(namesTxt)
        names=namesTxt.split("\n")
        if len(names) < 2: #in der ersten Zeile stehen bei der Rueckgabe die Spaltennamen, <2 heiss also es gibt keinen Eintrag
            return []
        
        ret=[]
        for name in names[1:]:
            line=[]
            for entry in name.split("\",\""):

                line.append(entry.replace('"',''));
            ret.append(line);
        return ret;
         
    def callSparql(self,cmdString):

        auth_handler = urllib2.HTTPBasicAuthHandler()
        auth_handler.add_password(realm='sparql',
                          uri=self.virtuosoServer+"/sparql",
                          user=self.virtuosoDAVUser,
                          passwd=self.virtuosoDAVPW)
                          
        opener = urllib2.build_opener(auth_handler)
        opener.addheaders = [('Content-Type','application/sparql-query')]
        
        logging.debug(cmdString)
        try:
            logging.debug(self.virtuosoServer+"/sparql?" + urllib.urlencode({'query':cmdString,'default-graph-uri':self.virtuosoGraph,'named-graph-uri':'','format':'text/csv'}))
            #r= opener.open(self.virtuosoServer+"/sparql", urllib.urlencode({'query':cmdString,'default-graph-uri':self.virtuosoGraph,'named-graph-uri':'','format':'text/csv'}))
            r= opener.open(self.virtuosoServer+"/sparql", urllib.urlencode({'query':cmdString,'default-graph-uri':'','named-graph-uri':'','format':'text/csv'}))
            namesTxt=r.read()
        except urllib2.URLError, e:
            logging.error(e.code)
            logging.error(e.read())
            
            
            return
        logging.debug(namesTxt)
        names=namesTxt.split("\n")
        if len(names) < 2: #in der ersten Zeile stehen bei der Rueckgabe die Spaltennamen, <2 heiss also es gibt keinen Eintrag
            return
         
        return names[1].replace('"','') # wir nehmen nur den ersten treffer
         
            
    security.declareProtected('View management screens','changeTags')            
    def changeTags(self,projectID,approaches=[],disciplines=[],periods=[],spaces=[],technologies=[],transfers=[],RESPONSE=None):
        """change tags"""
        self.changeTagFromList(projectID,"approaches", approaches)
        self.changeTagFromList(projectID,"disciplines", disciplines)
        self.changeTagFromList(projectID,"periods", periods)
        self.changeTagFromList(projectID,"spaces", spaces)
        self.changeTagFromList(projectID,"technologies", technologies)
        self.changeTagFromList(projectID,"transfers", transfers)
        
        self.projectObjects=self.projectObjects #necessesary to make the object persistent after the first call
        self.projectHistoricalPlaces=self.projectHistoricalPlaces #necessesary to make the object persistent after the first call
        self.projectPersons=self.projectPersons #necessesary to make the object persistent after the first call
        self.projectSuggestedTags=self.projectSuggestedTags
        
        self.persons2Projects=self.persons2Projects
        self.objects2Projects=self.objects2Projects
        self.historicalPlaces2Projects=self.historicalPlaces2Projects
        self.suggestedTags2Projects=self.suggestedTags2Projects;
        
        self.suggestedPersons=self.suggestedPersons;
        
    security.declareProtected('View management screens','deleteAllTags')                    
    def deleteAllTags(self):
        """deleteAllTags - TODO: take this out!!,"""
        setattr(self,"tags",None)
        
        return "DONE!"
    
    security.declareProtected('View management screens','deleteAllPersons')                    
    def deleteAllPersons(self):
        """deleteAllTags - TODO: take this out!!,"""
        self.projectPersons= OOBTree()
        self.persons2Projects= OOBTree()
        self.personIDtoNames=OOBTree()
        self.suggestedPersons= OOBTree(); #TODO: das sollte die ueberfluessig werde und nur im triple store stehen.
    
        
        return "DONE!"
    
    security.declareProtected('View management screens','deleteAllObjects')                    
    def deleteAllObjects(self):
        """deleteAllTags - TODO: take this out!!,"""
        logging.debug("delete all objects")
        self.projectObjects= OOBTree()
        self.objects2Projects=OOBTree()
    
        
        return "DONE!"
    
    def changeTagFromList(self,projectID,tagType,tagList):
        
        logging.debug("changing:"+projectID)
        logging.debug("asking tag::"+tagType)
        if type(tagList) is not ListType:
            tagList=[tagList]
        
    
        tags = getattr(self,"tags",None)
        if tags is None:
            logging.debug("Create new tags")
            tags=OOBTree()
            setattr(self,"tags",tags)
        
    
        tagsStored=tags.get(tagType,None)
        if tagsStored is None:
            tagsStored=OOBTree();
        
        
        
        for tag in tagsStored.keys(): #gehe durch alle gespeichteren tags
            logging.debug("checking:"+tag)
            projectsOfTag = tagsStored.get(tag,None)
            logging.debug(projectsOfTag)
            if projectsOfTag is None:
                projectsOfTag=OOSet()
            
            if tag in tagList: #dieser ist getagged
                projectsOfTag.update([projectID]);
                self.storeChange("added",projectID,tag)
                tagList.remove(tag); 
            else:
                if projectsOfTag.has_key(projectID):
                    projectsOfTag.remove(projectID);
                    self.storeChange("remove",projectID,tag)
                    
            tagsStored.update({tag:projectsOfTag});
        
        for tag in tagList: # alle Tags, die nicht abgearbeitet worden sind, muessen noch angelegt werden
            logging.debug("adding:"+tag)
            newApproach=OOSet()
            newApproach.update([projectID]);
            tagsStored.insert(tag, newApproach);
        
        tags.update({tagType:tagsStored})
        
        transaction.commit()
        
    def getTitle(self,entry):
        return entry.title
    
    def thes_quote(self,txt):
        import md5
        logging.debug("@*%s*@"%txt)
        return md5.md5(txt.lower()).hexdigest()

    
    def formatTag(self,tag):
        splitted= tag.split("_")
        return splitted[-1]
    
    def getEntriesFormatted(self,entries,formatType):
        if not hasattr(self,'levelFormatted'):
            pt=PageTemplateFile('zpt/levelFormatted', globals()).__of__(self)
            return pt(level1_entries=entries,type=formatType)
        
        pt = getattr(self,'levelFormatted')
        return pt(level1_entries=entries,type=formatType)
    
        
        #return self.levelFormatted(level1_entries=entries,type=formatType)
        
    def getEntries(self,entry):
        #logging.debug("GETENTRY:"+repr(entry))
        return entry.entries
    
    #nimmt ein eine Text der Form 
    # TAG1
    # ---
    # SUBTAG1_1
    # SUBTAG1_2
    # ---
    # TAG2
    # ---
    # SUBTAG2_1
    # SUBTAG2_2
    #....
    # und erzeugt daraus eine entsprechende Liste von Entries
    def getEntriesFromTxt(self,txt):
       
        apps=[]
        lines=txt.split("\n");
        level=False
        for line in lines:
            line=line.rstrip().lstrip()
            if line=="":
                continue
            if line=="---":
                
                if level:
                    level=False
                else:
                    level=True
            else:
                if not level:
                    entry=Entry(line,[])
                    apps.append(entry)
                else:
                    entry.entries.append(Entry(line))
                
        return apps[0:]
    
    def getApproaches(self):
        
        self.tagList=self.getEntriesFromTxt(self.approachesTxt)    
        return self.tagList
    
  
    def getTagsAsHash(self,projectID,tagType=None):
        """get all  tags as hash or None if no tag exists"""
        retHash={}
        
        tagCnt=0
        tags = getattr(self,"tags",None)
        
        if tags is None:
            return;
        
        #falls nicht gesetzt
        if tagType is None:
            tagTypes = tags.keys()
        else:
            tagTypes = [tagType]
        
        for tagType in tagTypes:
            tagsStored=tags.get(tagType,None)
            
            if tagsStored is None:
                # WTF: was: return
                continue
            
            retHash[tagType]=[]

            for tag in tagsStored.keys(): #gehe durch alle gespeichteren approached
                logging.debug("checking:"+tag)
                currentTag = tagsStored.get(tag,None)
                if currentTag is None:
                    continue
                if currentTag.has_key(projectID):
                    tagCnt+=1
                    retHash[tagType].append("""%s"""%tag)
                    
            if len(retHash[tagType]) == 0:
                # empty tag list
                del retHash[tagType]
            
        if tagCnt==0:
            return None
        
        return retHash
    
    
    
    
    
    def getTagsJSON(self,projectID,tagType,RESPONSE=None):
        """get all selected tagList"""
        #logging.debug("asking:"+projectID)
        #logging.debug("asking tag::"+tagType)
        retList=[]
        tags = getattr(self,"tags",None)
        if tags is None:
            return;
        
        tagsStored=tags.get(tagType,None)
        if tagsStored is None:
            return;
        
        for tag in tagsStored.keys(): #gehe durch alle gespeichteren approached
            logging.debug("checking:"+tag)
            currentTag = tagsStored.get(tag,None)
            if currentTag is None:
                continue
            if currentTag.has_key(projectID):
                retList.append(""" "%s" """%tag)
        
        if RESPONSE:
            RESPONSE.setHeader('Content-Type', "application/json")
        
        logging.debug(retList)
        return "["+",".join(retList)+"]"
    
    
    
  
    def getTags(self,projectID,projectTags,RESPONSE=None):
        """get all selected tagList"""
        
        #projectTags = self.getProjectsAndTags()
        #logging.debug(projectTags)
        
        project = projectTags.get(projectID)
        if project is None:
            project = projectTags.get("/en/research/projects/"+projectID) #TODO fix this projectTag list from getProjectsAndTags()contains  fullpath
        if project is None:
            return []    
        retarray=[]    
        for tagType in self.tags.keys():
                tags = project.tags.get(tagType,[''])
                retarray.append(utf8ify(";".join(tags)))
            
            
        return retarray       
#        logging.debug("asking:"+projectID)
#        
#        
#        apps = self.getApproaches()+ self.getDisciplines();
#        retList=[]
#        for tagType in self.tags.keys():
#        
#            logging.debug("asking tag::"+repr(tagType))
#            
#            tags = getattr(self,"tags",None)
#            if tags is None:
#                continue;
#            
#            tagsStored=tags.get(tagType,None)
#            if tagsStored is None:
#                continue;
#            
#            for tag in tagsStored.keys(): #gehe durch alle gespeichteren approached
#                logging.debug("checking:"+tag)
#                currentTag = tagsStored.get(tag,None)
#                if currentTag is None:
#                    continue
#                if currentTag.has_key(projectID):
#                    retList.append(""" "%s" """%tag)
#        
#        if RESPONSE:
#            RESPONSE.setHeader('Content-Type', "application/json")
#        
#        logging.debug(retList)
#        return retList
    
    def getDisciplines(self):
        
        self.disciplines=self.getEntriesFromTxt(self.disciplinesTxt)    
        return self.disciplines
    
    
    def getObjectsJSON(self,term="",RESPONSE=None):
        """ get all stored objects as json list starting with term"""
        term=term.lower();
        logging.debug("Asking:"+term)
        #objectList=["baus","berg","lurg"]
        objects = self.objects2Projects;

        objectList= [x for x in objects.keys()]   
       
        logging.debug("Create:"+repr(objectList))    
        retList=[]
        for object in objectList:
            if object.find(term)>-1:
                retList.append(""" "%s" """%object)
        ret="["
        ret+=",".join(retList)
        ret+="]"
        logging.debug("Objects:"+ret)
        if RESPONSE:
            RESPONSE.setHeader('Content-Type', "application/json")
        return ret
        
        
    def getHistoricalPlacesJSON(self,term="",RESPONSE=None):
        """ get all stored historicalPlaces as json list starting with term"""
        term=term.lower();
        logging.debug("Asking:"+term)
        #historicalPlaceList=["baus","berg","lurg"]
        historicalPlaces = self.historicalPlaces2Projects;

        historicalPlaceList= [x for x in historicalPlaces.keys()]   
       
        logging.debug("Create:"+repr(historicalPlaceList))    
        retList=[]
        for historicalPlace in historicalPlaceList:
            if historicalPlace.find(term)>-1:
                retList.append(""" "%s" """%historicalPlace)
        ret="["
        ret+=",".join(retList)
        ret+="]"
        logging.debug("historicalPlaces:"+ret)
        if RESPONSE:
            RESPONSE.setHeader('Content-Type', "application/json")
        return ret
        
        
    def getPeriods(self):
        
        self.periodes=self.getEntriesFromTxt(self.periodsTxt)    
        return self.periodes
    
    def getSpaces(self):
        
        self.spaces=self.getEntriesFromTxt(self.spacesTxt)    
        return self.spaces
    
    def getTechnologies(self):
        
        self.technologies=self.getEntriesFromTxt(self.technologiesTxt)    
        return self.technologies
    
    def getKnowledgeTransfers(self):
        
        self.knowledgeTransfers=self.getEntriesFromTxt(self.knowledgeTransfersTxt)    
        return self.knowledgeTransfers
    
    
    def getObjectsFromProject(self,projectID):
        return self.getFromProject(self.projectObjects,projectID);
    
    def getHistoricalPlacesFromProject(self,projectID):
        return self.getFromProject(self.projectHistoricalPlaces,projectID);
    
    def getSuggestedTagsFromProject(self,projectID):
        return self.getFromProject(self.projectSuggestedTags,projectID);
 
    
    def getPersonsFromProject(self,projectID):
        #hole alle personenID die zu einem Projekt gehoeren.
        #zurueckgegeben wird ein OOSet()
        return self.getFromProject(self.projectPersons,projectID);
    
    def getFromProject(self,objects,projectID): 
        #holt die zu projectID gehoerigen objekte aus dem objects-set. 
        #oder legt einen neuen leeren Satz zu dieser ProjektID an.
        #zuruecgegeben wird ein OOSet()
        if objects.has_key(projectID): #wenn zu der ProjektID schon etwas abgespeichter ist, gieb es zurueck
            logging.debug("key exists:"+projectID)
            persons=objects.get(projectID);
        else: # andernfalls lege einen neuen Satz an.
            persons=OOSet()
            objects.update({projectID:persons})
            logging.debug("key does not exists:"+projectID)
            
        
        return persons
    
    def getHistoricalPlacesFromProjectAsHTML(self,projectID):
        """gertobjects"""
        return self.getFromProjectAsHTML(self.projectHistoricalPlaces, projectID, "HistoricalPlace");
 
    def getObjectsFromProjectAsHTML(self,projectID):
        """gertobjects"""
        return self.getFromProjectAsHTML(self.projectObjects, projectID, "Object");
    
    def getPersonsFromProjectAsHTML(self,projectID):
        """getpersons"""
        return self.getFromProjectAsHTML(self.projectPersons, projectID, "Person");
       
        
    def getFromProjectAsHTML(self,objects,projectID,type):
        """getpersons"""
        ret=""
        if objects.has_key(projectID):
            persons=objects.get(projectID);
        else:
            persons=OOSet()
            
        
        for person in persons:
            ret+="""<div class="removeButton">
        <span>%s </span><div style="display:inline" class="remove%s"><span style="display:none" class="removeValue">%s</span>remove</div>
        </div>"""%(person[1],type,person[0])
            
            
#            ret+="""<div>
#        <input type="checkbox" name="persons_remove"
#         value="%s">
#        <span>%s</span>
#        </div>"""%(person[0],person[1])
#        
        logging.debug(type+":"+ret)
        return ret
    
    security.declareProtected('View management screens','removeHistoricalPlaceFromProject')                    
    def removeHistoricalPlaceFromProject(self,projectID,value):
        """remove"""
        logging.debug("removeHP:"+projectID+":"+value);
        
        HistoricalPlaces = self.getHistoricalPlacesFromProject(projectID)
        for HistoricalPlace in HistoricalPlaces.keys():
           
            logging.debug("trying:"+repr(HistoricalPlace[0])+"::"+repr(value)+"__")
            if HistoricalPlace[0]==value:
                logging.debug("---removed!")
                HistoricalPlaces.remove(HistoricalPlace)
        
        self.projectHistoricalPlaces.update({projectID:HistoricalPlaces})
        retstring = self.getHistoricalPlacesFromProjectAsHTML(projectID)
        logging.debug(retstring)
        return retstring
    
    security.declareProtected('View management screens','removeObjectFromProject') 
    def removeObjectFromProject(self,projectID,value):
        """remove"""
        logging.debug("remove:"+projectID+":"+value);
        
        
        self.storeChange("removeObject",projectID,value)
        
        objects = self.getObjectsFromProject(projectID)
        for object in objects.keys():
           
            logging.debug("trying:"+repr(object[0])+"::"+repr(value)+"__")
            if object[0]==value:
                logging.debug("---removed!")
                objects.remove(object)
        
            #now also delete the project from the object.
                objectsOfPerson=self.objects2Projects.get(object[0])
               

                if projectID in list(objectsOfPerson):
                    objectsOfPerson.remove(projectID)
                    #self.persons2Projects.update({person:projectsList})
                    if (len(objectsOfPerson)==0): #loesche person aus der liste wenn keine Projekte dazu existieren.
                        del self.objects2Projects[object[0]]
             
        self.projectObjects.update({projectID:objects})
        retstring = self.getObjectsFromProjectAsHTML(projectID)
        logging.debug(retstring)
        return retstring
    
    security.declareProtected('View management screens','removePersonFromProject') 
    def removePersonFromProject(self,projectID,value):
        """remove a person from the projeckt"""
        logging.debug("remove:"+projectID+":"+value);
        self.storeChange("removePerson",projectID,value)
        
        persons = self.getPersonsFromProject(projectID) # hole alle personen die mit dem Projekt verbunden sind.
        for person in persons.keys():
           
            logging.debug("trying:"+repr(person[0])+"::"+repr(value)+"__")
            if person[0]==value:#person ist die zuloeschende, dann raus damit
            
                logging.debug("---removed!")
                persons.remove(person)
                
                #now also delete the project from the person.
                projectsOfPerson=self.persons2Projects.get(person[0])
                logging.debug(projectsOfPerson)
                if projectID in list(projectsOfPerson):
                    projectsOfPerson.remove(projectID)
                    #self.persons2Projects.update({person:projectsList})
                    if (len(projectsOfPerson)==0): #loesche person aus der liste wenn keine Projekte dazu existieren.
                        del self.persons2Projects[person[0]]
             
                     
        #self.projectPersons.update({projectID:persons})
        retstring = self.getPersonsFromProjectAsHTML(projectID)
        logging.debug(retstring)
        return retstring
    

    #fuegt die neue Person zur personIDtoNames hinzu, fuer die spaetere Anzeige in der Personenliste
    def addNameTOPersonIDNames(self,personID,label):
        personName = self.personIDtoNames.get(personID)
        if personName==None: # Anlegen falls noch nicht existent
            personName=(label,[])
        else:
            if (not label in personName[1]) and (not label==personName[0]): # hinzufuegen falls der neuen name noch nicht als bezeichnugn fuer personID eingetragen ist
                personName[1].append(label) 
    
        self.personIDtoNames.update({personID:personName})
        
    security.declareProtected('View management screens','addPersonToProject')     
    def addPersonToProject(self,projectID,value,label):
        """ add a person so the project"""
        self.storeChange("addPerson",projectID,value+":"+label)
        
        persons=self.getPersonsFromProject(projectID);
        
        logging.debug("adding:"+projectID+":"+value+":"+label);
      
        persons.insert([value,label])
        self.projectPersons.update({projectID:persons})
        
        for personTuple in persons:
            #hole die abgespeicherten Projekte zu einer Person
            person=personTuple[0] #hole die ID
            
            
            if getattr(self,"persons2Projects",None)==None:
                setattr(self,"persons2Projects",OOBTree())
         
            projects = self.persons2Projects.get(person,None)
            logging.debug("found projects:"+ repr(projects))
            if projects is None: #person hatte noch keine projekte
                projects=OOSet();
                
            projects.insert(projectID )
            logging.debug("update:"+person)
            self.persons2Projects.update({person:projects})
            
            self.addPersonAndFirstNameFromTripleStore(person)
            self.generateSortingOrderForPersonIDs();
               
        self.addNameTOPersonIDNames(value,label)
        retstring = self.getPersonsFromProjectAsHTML(projectID)
        logging.debug(retstring)
        transaction.commit()
        return retstring
    
    
    
    def rearangePersonIDsHTML(self,REQUEST=None):
        """setze neue ID zu personen"""
        ret=[]
        for personID in self.persons2Projects.keys():
            logging.debug(personID)
            
            masterID,name=self.findMasterIDAndName(personID.rstrip().lstrip())
            logging.debug("        masterID -appending")
            logging.debug(repr(name))
            if len(name)==0:
                name=['']
            ret.append((personID,self.personIDtoNames.get(personID,[''])[0],masterID,self.personIDtoNames.get(masterID,name)[0]))   
                                      
    
        if REQUEST:
            pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','rearrangePersons.zpt')).__of__(self)
            return pt(changeList=ret,lookupUrl=self.PERSONS_LOOKUP_URL,editURL=self.EDIT_URL);
        else:
            return ret; 
        
    def rearangePersonIDs(self,REQUEST):
        """unify a list of persons"""
        
        argv=REQUEST.form;
        logging.debug(repr(argv))
        changes=argv['changes']
        if isinstance(changes,str):
            changes=[changes]
        
        changeList=self.rearangePersonIDsHTML()
        personToMaster={}
        logging.debug("changelist:"+repr(changeList))
        #aendere person2project
        for change in changes:
            changeItem=changeList[int(change)];
            masterID=argv['newID_'+change].lstrip().rstrip() #make sure no spaces
            personID=changeItem[0]
            
            personToMaster[personID]=masterID
            masterIDProjects = self.persons2Projects.get(masterID,None);
            if masterIDProjects==None:
                masterIDProjects=OOSet();
                #ret.append((personID,self.personIDtoNames.get(personID,[''])[0],masterID,self.personIDtoNames.get(masterID,[''])[0]))   
                
            oldProjects= self.persons2Projects.get(personID)
            logging.debug("personID:"+repr(personID))
            logging.debug("masterID:"+repr(masterID))
            logging.debug("keys:"+repr(self.persons2Projects.keys()))
            logging.debug("oldProjects:"+repr(oldProjects))
            masterIDProjects.update(oldProjects)
            self.persons2Projects.update({masterID:masterIDProjects})
            self.persons2Projects.pop(personID)
            
            self.addPersonAndFirstNameFromTripleStore(masterID) #addpersontotiplestore
            
            logging.debug("Change:" +personID+":"+ masterID)
            
            if personID!=masterID:
                self.addSameAsRelationToTripleStore(personID,masterID)
            
        #aendere nun projectperson
        logging.debug(personToMaster)
        for project in self.projectPersons.keys():
            personsNew=OOSet()
            
            persons=self.projectPersons.get(project)
            for person in persons:
                personsNew.insert([personToMaster.get(person[0],person[0]),person[1]])
                logging.debug("REPLACE in:"+project+":" +repr(person)+" by "+ repr(personToMaster.get(person[0],person[0])))
            self.projectPersons.update({project:personsNew})
            
        self.generateSortingOrderForPersonIDs(); #now sort the new names
        return personToMaster
    #fuehre personen zusammen die ueber owl:sameAs verbunden sind
    def getUnifyPersonsList(self,REQUEST=None):
        """vereinheitlichung der personen auf eine ID aus der GND, wenn moeglich"""
        ret=[]
        for personID in self.persons2Projects.keys():
            masterID,name=self.findMasterIDAndName(personID)
            logging.debug("masterID:"+masterID)
            if (masterID is not None) and (masterID is not "") and (not personID==masterID):
                #masterIDProjects = self.persons2Projects.get(masterID,None);
                ##if masterIDProjects==None:
                #    masterIDProjects=OOSet();
                logging.debug("        masterID -appending")
                logging.debug(repr(name))

            
                ret.append((personID,self.personIDtoNames.get(personID,[''])[0],masterID,self.personIDtoNames.get(masterID,name)[0]))   
                #masterIDProjects.update(self.persons2Projects.get(personID));
                #self.persons2Projects.update({masterID:masterIDProjects});
                                        
    
        if REQUEST:
            pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','unifyPersons.zpt')).__of__(self)
            return pt(changeList=ret);
        
        else:
            return ret; 
    
    def unifyPersons(self,changes,REQUEST=None):
        """unify a list of persons"""
        
        if isinstance(changes,str):
            changes=[changes]
        
        changeList=self.getUnifyPersonsList();
        personToMaster={}
        logging.debug("changelist:"+repr(changeList))
        #aendere person2project
        for change in changes:
            changeItem=changeList[int(change)];
            masterID=changeItem[2]
            personID=changeItem[0]
            
            personToMaster[personID]=masterID
            masterIDProjects = self.persons2Projects.get(masterID,None);
            if masterIDProjects==None:
                masterIDProjects=OOSet();
                #ret.append((personID,self.personIDtoNames.get(personID,[''])[0],masterID,self.personIDtoNames.get(masterID,[''])[0]))   
                
            oldProjects= self.persons2Projects.get(personID)
            logging.debug("personID:"+repr(personID))
            logging.debug("masterID:"+repr(masterID))
            logging.debug("keys:"+repr(self.persons2Projects.keys()))
            logging.debug("oldProjects:"+repr(oldProjects))
            masterIDProjects.update(oldProjects)
            self.persons2Projects.update({masterID:masterIDProjects})
            self.persons2Projects.pop(personID)
            
            self.addPersonAndFirstNameFromTripleStore(masterID) #addpersontotiplestore
            
            logging.debug("Change:" +personID+":"+ masterID)
            
        #aendere nun projectperson
        logging.debug(personToMaster)
        for project in self.projectPersons.keys():
            personsNew=OOSet()
            
            persons=self.projectPersons.get(project)
            for person in persons:
                personsNew.insert([personToMaster.get(person[0],person[0]),person[1]])
                logging.debug("REPLACE in:"+project+":" +repr(person)+" by "+ repr(personToMaster.get(person[0],person[0])))
            self.projectPersons.update({project:personsNew})
            
        self.generateSortingOrderForPersonIDs(); #now sort the new names
        return personToMaster
        
        
    
    def findMasterIDAndName(self,ressourceID):
        queryString="""select * 
FROM <file://mpiwg_persons_dnb.rdf>  
FROM <file://mpiwg_persons_2.rdf> 
FROM <file:///GND.rdf> 
FROM <http://identifiedNames>
where {
?person <http://www.w3.org/2002/07/owl#sameAs> <%s>.

?ident <http://ontologies.mpiwg-berlin.mpg.de/authorities/namedIdentities/identifies_NamedEntity> ?person. 
?gnd crm:P1_is_identified_by ?ident.

?gnd <http://RDVocab.info/ElementsGr2/dateOfBirth> ?birthDate.
?gnd <http://RDVocab.info/ElementsGr2/dateOfDeath> ?deathDate.
?person <http://xmlns.com/foaf/0.1/name> ?name.
?person <http://xmlns.com/foaf/0.1/lastName> ?lastName.
?person <http://xmlns.com/foaf/0.1/firstName> ?firstName.
} 
"""%ressourceID
        entries = self.callSparqlAll(queryString);
        if len(entries)>0:
            return entries[0][0],entries[0][5:8] #nur den ersten Treffer und nur die personID
        
    
        return None,None
        
    security.declareProtected('View','getPersonsWithProjectIDs') 
    def getPersonsWithProjectIDs(self,check=False):
        """holt die getaggted Personen mit Projekten"""
        persons = self.persons2Projects;
        ret={}
        
        logging.debug("Check Person:"+repr(persons.keys()))
        personsList=[x for x in persons.keys()]
        
        def sort(x,y):
            try:
                sortNrx=self.personsIDForSort.index(x)
            except:
                logging.warn("couldn't find personsIDForSort:"+x)
                sortNrx=0
            
            try:
                sortNry=self.personsIDForSort.index(y)
            except:
                logging.warn("couldn't find personsIDForSort:"+y)
                sortNry=0
            #logging.debug("INSORT***")
            #logging.debug((sortNrx,sortNry))
            return cmp(sortNrx,sortNry)
        
        logging.debug("SORT***")
        logging.debug(self.personsIDForSort) 
        logging.debug("SORT.list")
        logging.debug(personsList) 
        personsList.sort(cmp=sort)
        #for person in persons.keys():
        logging.debug("AFTERSORT***")
        logging.debug(personsList) 
        for person in personsList:
            logging.debug("Check:"+person)
            #TODO: person muss duch den namen von provider geholt werden
            retlist=[]
            projectsList=persons.get(person)
            if projectsList is None:
                projectsList=[]
            for projectID in list(projectsList): #list notwendig da projectList in der folgenden iteration veraendert wird.
                if check: #teste ob im Projekt noch ein Verweis auf den Namen steht
                    #sollte eigentlich nicht sein.
                    personsProjects=self.getPersonsFromProject(projectID)
                    logging.debug("persons check mode")
                    personsProjectsCheck=[x[0] for x in personsProjects]
                    if not person in personsProjectsCheck: #falls es so ist korrigiere die Projektliste der Person
                        #loesche die person von projectListe
                        projectsList.remove(projectID)
                        persons.update({person:projectsList})
                        
                retlist.append(self.getProjectDetails(projectID))
            
            if check and (len(projectsList)==0): #loesche person aus der liste wenn keine Projekte dazu existieren.
                del persons[person]
                
            ret[person]=retlist[0:]
       
        logging.debug("AFTERSORT-ret***")
        logging.debug(ret.keys()) 
        return ret,personsList
    
    def getHistoricalPlacesWithProjectIDs(self):
        """holt die getaggted Personen mit Projekten"""
        HistoricalPlaces = self.HistoricalPlaces2Projects;
        ret={}
        logging.debug("Check HistoricalPlace:"+repr(HistoricalPlaces.keys()))
        for HistoricalPlace in HistoricalPlaces.keys():
            logging.debug("Check:"+HistoricalPlace)
            #TODO: HistoricalPlace muss duch den namen von provuder geholt werden
            list=[]
            for projectID in HistoricalPlaces.get(HistoricalPlace):
                list.append(self.getProjectDetails(projectID))
            
            ret[HistoricalPlace]=list[0:]
        return ret
    
    def getObjectsWithProjectIDsSortedkeys(self):
        
        def sortF(x,y):
            return cmp(x.lower(),y.lower())
        keys = [x for x in self.getObjectsWithProjectIDs().keys()]
        keys.sort(sortF)
        return keys
    
    def getObjectsWithProjectIDs(self):
        """holt die getagten Personen mit Projekten"""
        objects = self.objects2Projects;
        ret={}
        logging.debug("Check Object:"+repr(objects.keys()))
        for object in objects.keys():
            logging.debug("Check:"+object)
            #TODO: object muss duch den namen von provuder geholt werden
            list=[]
            for projectID in objects.get(object):
                list.append(self.getProjectDetails(projectID))
            
            ret[object]=list[0:]
            
        logging.debug(ret)
        return ret
    
    security.declareProtected('View management screens','listAllSuggestedTags')     
    def listAllSuggestedTags(self):
        """list all tags"""
        ret="<html><body>"
        for projectID in self.projectSuggestedTags:
            ret+="<h3>"+projectID+"</h3><table>"
            for tags in self.projectSuggestedTags.get(projectID):
                ret+="<tr><td>"+tags[0]+"</td><td>"+tags[1].type+"</td><td>"+tags[1].comment+"</td><td>"+tags[1].userName+"</td></tr>"
            ret+="</table>"
        ret+="</body></html>"
        logging.debug(ret);
        return ret
    
    security.declareProtected('View management screens','suggestTag')     
    def suggestTag(self,projectID,tagName,tagComment,tagType,tagUserName):
        """suggest a new tag"""
        """ add a person so the project"""
        SuggestedTags=self.getSuggestedTagsFromProject(projectID);
        
        logging.debug("suggested:"+projectID+":"+tagName);
        
     
        #TODO: Im moment noch keine Zuordnung zu einer ID.
        newTag = SuggestedTag(tagName,tagComment,tagType,tagUserName)
        SuggestedTags.insert([tagName,newTag])
        self.projectSuggestedTags.update({projectID:SuggestedTags})
        
       
        
        for SuggestedTagTuple in SuggestedTags:
            #hole die abgespeicherten Projekte zu einer Person
            person=SuggestedTagTuple[0] #hile die ID
            
            
            if getattr(self,"SuggestedTags2Projects",None)==None:
                setattr(self,"SuggestedTags2Projects",OOBTree())
         
            projects = self.SuggestedTags2Projects.get(person,None)
                   
            if projects==None:
                projects=OOSet();
            
            projects.insert(projectID )
            logging.debug("update:"+person)
            self.SuggestedTags2Projects.update({person:projects})
        
        
        
        #retstring = self.getSuggestedTagsFromProjectAsHTML(projectID)
        #logging.debug(retstring)
        
        
        
        #return retstring
        
    security.declareProtected('View management screens','addHistoricalPlaceToProject')     
    def addHistoricalPlaceToProject(self,projectID,value):
        """ add a person so the project"""
        HistoricalPlaces=self.getHistoricalPlacesFromProject(projectID);
        
        logging.debug("adding:"+projectID+":"+value);
        
     
        #TODO: Im moment noch keine Zuordnung zu einer ID.
        HistoricalPlaces.insert([value,value])
        self.projectHistoricalPlaces.update({projectID:HistoricalPlaces})
        
       
        
        for HistoricalPlaceTuple in HistoricalPlaces:
            #hole die abgespeicherten Projekte zu einer Person
            person=HistoricalPlaceTuple[0] #hile die ID
            
            
            if getattr(self,"HistoricalPlaces2Projects",None)==None:
                setattr(self,"HistoricalPlaces2Projects",OOBTree())
         
            projects = self.HistoricalPlaces2Projects.get(person,None)
                   
            if projects==None:
                projects=OOSet();
            
            projects.insert(projectID )
            logging.debug("update:"+person)
            self.HistoricalPlaces2Projects.update({person:projects})
        
        
        
        retstring = self.getHistoricalPlacesFromProjectAsHTML(projectID)
        logging.debug(retstring)
        
        
        
        return retstring
    
    security.declareProtected('View management screens','addObjectToProject')     
    def addObjectToProject(self,projectID,value):
        """ add a person so the project"""
        objects=self.getObjectsFromProject(projectID);
        
        logging.debug("adding:"+projectID+":"+value);
        
        self.storeChange("addObject",projectID,value)
     
        #TODO: Im moment noch keine Zuordnung zu einer ID.
        objects.insert([value,value])
        self.projectObjects.update({projectID:objects})
        
       
        
        for objectTuple in objects:
            #hole die abgespeicherten Projekte zu einer Person
            person=objectTuple[0] #hile die ID
            
            
            if getattr(self,"objects2Projects",None)==None:
                setattr(self,"objects2Projects",OOBTree())
         
            projects = self.objects2Projects.get(person,None)
                   
            if projects==None:
                projects=OOSet();
            
            projects.insert(projectID )
            logging.debug("update:"+person)
            self.objects2Projects.update({person:projects})
        
        
        
        retstring = self.getObjectsFromProjectAsHTML(projectID)
        logging.debug(retstring)
        
        
        
        return retstring
    
    
    def getProjectsWithTag(self,tagType,tagName):
        tags = getattr(self,"tags",None)
        if tags is None:
            logging.debug("can't find Tags")
            return []
    
        tagsStored=tags.get(tagType,None)
        if tagsStored is None:
            logging.debug("can't find Tag:"+tagType)
            return []
        
        projects = tagsStored.get(tagName,None)
        if projects is None:
            logging.debug("can't find any projects for Tag:"+tagName+"("+tagType+")")
            return []
        
        ret=[]
        for project in projects:
            logging.debug("found:"+project)
            proj =self.getProjectDetails(project);
            if proj is not None:
                ret.append(proj)

        return ret
    
    def getProjectDetails(self,projectId):
        pf = self.getMPIWGRoot().getProjectFolder()
        project=pf.get(projectId,None)
        if project is None:
            logging.debug("no project!! " +projectId)
            return None
        
        link=projectId
        
        title=project.getContent("WEB_title")
        #persons=project.getPersonKeyList()
        persons=project.getContent('xdata_01')
        logging.debug("%s %s %s"%(link,title,persons))
        
        thumb = project.getThumbUrl()
       
        return link,title,persons,thumb
    
#        $.post("addNewPerson",{"projectID":
#                     $('#projectID').val(),
#                     "personName":$("#suggest_newPerson").val(),
#                     "personComment":$("#suggest_newPerson_comment").val()}
#               
#              );         
#    
    
    security.declareProtected('View management screens','addAndCreateNewPerson')     
    def addAndCreateNewPerson(self,projectID,personName,personComment,personUserName):
        """adds anew person to the project which is not in the authority file"""
        
        id = random.randint(0, 1000000); 
        idstring="http://ontologies.mpiwg-berlin.mpg.de/tempObjects/person/"+str(id)
        while self.suggestedPersons.has_key(idstring):
            id = random.randint(0, 1000000); 
            #idstring="http://ontologies.mpiwg-berlin.mpg.de/tempObjects/person/"+str(id);
            idstring=self.TEMP_PERSON_NS+str(id);
            
            
        self.suggestedPersons.update({idstring:(personName,personComment,projectID,personUserName)})
        self.createTempPersonInVirtuoso(projectID, idstring, personName, personComment) #TODO: add suername to the triplestore
        return self.addPersonToProject(projectID, idstring, personName);
       
    def addSameAsRelationToTripleStore(self,personID,masterID):
        cmdString ="insert in GRAPH <"+self.virtuosoGraph+">  {"
        cmdString +="<%s> <http://www.w3.org/2002/07/owl#sameAs> <%s>."%(personID,masterID)
        cmdString +="<%s> <http://www.w3.org/2002/07/owl#sameAs> <%s>."%(masterID,personID)
        cmdString+="}"

        auth_handler = urllib2.HTTPBasicAuthHandler()
        auth_handler.add_password(realm='sparql',
                          uri=self.virtuosoServer+"/sparql",
                          user=self.virtuosoDAVUser,
                          passwd=self.virtuosoDAVPW)
                          
        opener = urllib2.build_opener(auth_handler)
        opener.addheaders = [('Content-Type','application/sparql-query')]
        
        logging.debug(cmdString)
        try:
            r= opener.open(self.virtuosoServer+"/sparql", urllib.urlencode({'query':cmdString,'default-graph-uri':self.virtuosoGraph,'named-graph-uri':None}))
            logging.debug(r.read())
        except urllib2.URLError, e:
            logging.error(e.code)
            logging.error(e.read())
            return
        
        
    security.declareProtected('View management screens','createTempPersonInVirtuoso')     
    def createTempPersonInVirtuoso(self,projectID,personURI, personName,personComment):
        """add a new person to the triple store of tempory persons"""
        triples=[];
        personID="<"+personURI+">"
        triples.append((personID,"<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>","<http://ontologies.mpiwg-berlin.mpg.de/authorities/namedIdentities/Person>"))
        triples.append((personID,"<http://erlangen-crm.org/110404/P3_has_note>",'"'+personComment+'"'))
        triples.append((personID,"<http://xmlns.com/foaf/0.1/name>",'"'+personName+'"'))
        triples.append((personID,"<http://ontologies.mpiwg-berlin.mpg.de/general/isMentionedOn>","<http://www.mpiwg-berlin.mpg.de/en/research/projects/"+projectID+">"))
        
        cmdString ="insert in GRAPH <"+self.virtuosoGraph+">  {"
        for triple in triples:
            cmdString+=" ".join(triple)+"."
        
        cmdString+="}"

        auth_handler = urllib2.HTTPBasicAuthHandler()
        auth_handler.add_password(realm='sparql',
                          uri=self.virtuosoServer+"/sparql",
                          user=self.virtuosoDAVUser,
                          passwd=self.virtuosoDAVPW)
                          
        opener = urllib2.build_opener(auth_handler)
        opener.addheaders = [('Content-Type','application/sparql-query')]
        
        logging.debug(cmdString)
        try:
            r= opener.open(self.virtuosoServer+"/sparql", urllib.urlencode({'query':cmdString,'default-graph-uri':self.virtuosoGraph,'named-graph-uri':None}))
            logging.debug(r.read())
        except urllib2.URLError, e:
            logging.error(e.code)
            logging.error(e.read())
            return
        
        opener2 = urllib2.build_opener()
       
        personIDencoded=urllib.quote(personURI,safe="")
        graphEncoded=urllib.quote(self.additionalNamesGraphURL,safe="")
        url = self.personproviderURL+"id/"+personIDencoded+"/"+graphEncoded
         
        try:
            request = urllib2.Request(url);
            request.get_method = lambda : 'PUT'
            r= opener2.open(request);
            logging.debug(r.read())
        except urllib2.URLError, e:
            logging.error(e.code)
            logging.error(e.read())
            return
       
        return
    
    #  self.storeChange("removePerson",projectID,value)    
    def storeChange(self,typeString,projectID,value):
        
        from time import gmtime,strftime
        fl = open(self.getLogpath(),"a")
        person = self.REQUEST.AUTHENTICATED_USER.getId()
        date = strftime("%Y-%m-%d %H:%M:%S", gmtime())
        writeString ="\t".join((date,person,typeString,projectID,value))
        fl.write(writeString+"\n")
        fl.flush()
        fl.close()
        
        lastChangeInThesaurus = getattr(self,'lastChangeInThesaurus',OOBTree())
        lastChangeInThesaurus.update({projectID:date})
        self.lastChangeInThesaurus=lastChangeInThesaurus
        
def redirect(RESPONSE,url):
        """mache ein redirect mit einem angehaengten time stamp um ein reload zu erzwingen"""
        
        timeStamp=time.time()
        
        if url.find("?")>-1: #giebt es schon parameter
            addStr="&time=%s"
        else:
            addStr="?time=%s"
            
        RESPONSE.setHeader('Last-Modified',email.Utils.formatdate().split("-")[0]+'GMT')
        logging.error(email.Utils.formatdate()+' GMT')
        RESPONSE.redirect(url+addStr%timeStamp)
        
def manage_addMPIWGThesaurusForm(self):
    """form for adding the project"""
    pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addMPIWGThesaurusForm.zpt')).__of__(self)
    return pt()



def manage_addMPIWGThesaurus(self,id,RESPONSE=None):
    """add it"""
    newObj=MPIWGThesaurus(id)

    self._setObject(id,newObj)


    if RESPONSE is not None:
        redirect(RESPONSE,'manage_main')