#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-


# Glasnost
# By: Odile Bénassy <obenassy@entrouvert.com>
#     Romain Chantereau <rchantereau@entrouvert.com>
#     Nicolas Clapiès <nclapies@easter-eggs.org>
#     Pierre-Antoine Dejace <padejace@entrouvert.be>
#     Thierry Dulieu <tdulieu@easter-eggs.com>
#     Florent Monnier <monnier@codelutin.com>
#     Cédric Musso <cmusso@easter-eggs.org>
#     Frédéric Péters <fpeters@entrouvert.be>
#     Benjamin Poussin <poussin@codelutin.com>
#     Emmanuel Raviart <eraviart@entrouvert.com>
#     Sébastien Régnier <regnier@codelutin.com>
#     Emmanuel Saracco <esaracco@easter-eggs.com>
#
# Copyright (C) 2000, 2001 Easter-eggs & Emmanuel Raviart
# Copyright (C) 2002 Odile Bénassy, Code Lutin, Thierry Dulieu, Easter-eggs,
#     Entr'ouvert, Frédéric Péters, Benjamin Poussin, Emmanuel Raviart,
#     Emmanuel Saracco & Théridion
# Copyright (C) 2003 Odile Bénassy, Romain Chantereau, Nicolas Clapiès,
#     Code Lutin, Pierre-Antoine Dejace, Thierry Dulieu, Easter-eggs,
#     Entr'ouvert, Florent Monnier, Cédric Musso, Ouvaton, Frédéric Péters,
#     Benjamin Poussin, Rodolphe Quiédeville, Emmanuel Raviart, Sébastien
#     Régnier, Emmanuel Saracco, Théridion & Vecam
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.


__doc__ = """Glasnost NCards Server"""

__version__ = '$Revision$'[11:-2]


import fcntl
import new
import sys

glasnostPythonDir = '/usr/local/lib/glasnost-devel' # changed on make install
sys.path.insert(0, glasnostPythonDir)

import glasnost

from glasnost.common.NCardsCommon import *
import glasnost.common.faults as faults
import glasnost.common.context as context
import glasnost.common.tools_new as commonTools
import glasnost.common.xhtmlgenerator as X

from glasnost.server.ObjectsServer import register, ObjectServerMixin, \
        AdminServerMixin, ObjectsServer, VirtualServer
from glasnost.proxy.DispatcherProxy import getApplicationToken, registerVirtualServer

from glasnost.server.tools import *


applicationName = 'NCardsServer'
applicationRole = 'ncards'
dispatcher = None


def registerNCardClass(ncard):
    commonMixinClass = getCommonMixinClass(ncard)

    objectClass = new.classobj(
            commonMixinClass.objectClass.__name__,
            (ObjectServerMixin, commonMixinClass.objectClass),
            {})
    setattr(sys.modules['__main__'], objectClass.__name__, objectClass)
    register(objectClass)

    objectAdminClass = new.classobj(
            commonMixinClass.adminClass.__name__,
            (AdminServerMixin, commonMixinClass.adminClass),
            {})
    setattr(sys.modules['__main__'],
            objectAdminClass.__name__, objectAdminClass)
    register(objectAdminClass)


class AdminNCards(AdminServerMixin, AdminNCardsCommon):
    pass
register(AdminNCards)


class NCard(ObjectServerMixin, NCardCommon):
    pass
register(NCard)


class NCardsServer(NCardsCommonMixin, ObjectsServer):
    def addDispatcher(self, newDispatcherId):
        ObjectsServer.addDispatcher(self, newDispatcherId)
        virtualServer = self.getVirtualServer(
                '/'.join((newDispatcherId, 'ncards')))
        for object in virtualServer.objects.values():
            vsId = commonTools.makeApplicationId(newDispatcherId, object.role)
            self.registerSub(object, vsId)

    def addObjectXmlRpc(self, objectImport):
        objectId = ObjectsServer.addObjectXmlRpc(self, objectImport)
        if commonTools.extractRole(objectId) == 'ncards':
            virtualServerId = context.getVar('applicationId')
            virtualServer = self.getVirtualServer(virtualServerId)
            object = virtualServer.loadObjectCore(objectId)
            newDispatcherId = commonTools.extractDispatcherId(virtualServerId)
            vsId = commonTools.makeApplicationId(newDispatcherId, object.role)
            self.registerSub(object, vsId)
        return objectId

    def modifyObjectXmlRpc(self, objectImport):
        objectId = objectImport['id']
        version = ObjectsServer.modifyObjectXmlRpc(self, objectImport)
        if commonTools.extractRole(objectId) == 'ncards':
            virtualServerId = context.getVar('applicationId')
            virtualServer = self.getVirtualServer(virtualServerId)
            object = virtualServer.loadObjectCore(objectId)
            newDispatcherId = commonTools.extractDispatcherId(virtualServerId)
            vsId = commonTools.makeApplicationId(newDispatcherId, object.role)
            self.registerSub(object, vsId)
        return version

    def registerSub(self, object, vsId):
        try:
            registerVirtualServer(self.hostName, self.port, vsId) 
        except faults.RoleNotInProfiles:
            return
        registerNCardClass(object)
        newVirtualServer = self.initVirtualServer(vsId)
        self.virtualServers[vsId] = newVirtualServer
        newVirtualServer = self.loadVirtualServer(newVirtualServer)
        self.virtualServers[vsId] = newVirtualServer
        context.push(applicationId = vsId)
        context.getVar('applicationTokens')[vsId] = getApplicationToken()
        context.pull()

    def getApplicationNameFromVirtualServer(self, virtualServer):
        dispatcherId = commonTools.extractDispatcherId(
                virtualServer.virtualServerId)
        role = commonTools.extractRole(virtualServer.virtualServerId)
        virtualServer = self.virtualServers['/'.join((dispatcherId, 'ncards'))]
        for o in virtualServer.objects.values():
            if o.role == role:
                applicationName = o.objectsName + 'Server'
                return applicationName
        raise 'aie'


    def getObjectEmail(self, objectId):
        clientToken = context.getVar('clientToken')
        clientId = getApplicationId(clientToken)
        clientRole = commonTools.extractRole(clientId)
        if clientRole != 'identities':
            raise faults.ApplicationAccessDenied(clientId)
        
        virtualServerId = context.getVar('applicationId')
        virtualServer = self.getVirtualServer(virtualServerId)
        object = virtualServer.loadObjectCore(objectId)
        emailAddress = object.getEmail()
        if not emailAddress:
            return '' # or raise something ?

        return emailAddress


    def loadVirtualServer(self, virtualServer):
        # ObjectsServer.loadVirtualServer; modified to user ncard.objectName
        # instead of self.applicationName
        role = commonTools.extractRole(virtualServer.virtualServerId)
        applicationName = self.applicationName
        if role != 'ncards':
            applicationName = self.getApplicationNameFromVirtualServer(
                    virtualServer)

        context.push(
                applicationId = virtualServer.virtualServerId,
                dispatcherId = commonTools.extractDispatcherId(
                        virtualServer.virtualServerId),
                emptyVirtualServer = virtualServer,
                )
        if self.useDataFile:
            try:
                pickleFilePath = os.path.join(
                        virtualServer.dataDirectoryPath,
                        applicationName + '.pickle')
                xmlFilePath = os.path.join(
                        virtualServer.dataDirectoryPath,
                        applicationName + '.xml')
                print 'pickleFilePath:', pickleFilePath
                rcFile = None
                if os.access(xmlFilePath, os.F_OK):
                    rcFile = open(xmlFilePath, 'rb')
                    import gnosis.xml.pickle as glasnostPickle
                    glasnostPickle.setParanoia(0)
                elif os.access(pickleFilePath, os.F_OK):
                    import cPickle as glasnostPickle
                    rcFile = open(pickleFilePath, 'rb')
                if rcFile is None:
                    self.fillEmptyVirtualServer(virtualServer)
                else:
                    fcntl.lockf(rcFile, fcntl.LOCK_SH)
                    version = self.readFileVersion(rcFile)
                    print 'file:',  rcFile
                    try:
                        data = glasnostPickle.load(rcFile)
                    except AttributeError:
                        self.fillEmptyVirtualServer(virtualServer)
                        data = virtualServer
                    fcntl.lockf(rcFile, fcntl.LOCK_UN)
                    isReadOnly = 0
                    if not os.access(rcFile.name, os.W_OK):
                        print '\t(read-only file)'
                        isReadOnly = 1
                    rcFile.close()
                    if isinstance(data, VirtualServer):
                        virtualServer = data
                    else:
                        virtualServer.initFromOldData(data)
                    virtualServer.isReadOnly = isReadOnly
                    self.upgradeVirtualServer(virtualServer, version)
            finally:
                context.pull()
        return virtualServer

    
    def registerToDispatcher(self):
        ObjectsServer.registerToDispatcher(self)
        for virtualServer in self.virtualServers.values():
            newDispatcherId = commonTools.extractDispatcherId(
                    virtualServer.virtualServerId)
            for object in virtualServer.objects.values():
                vsId = commonTools.makeApplicationId(newDispatcherId, object.role)
                self.registerSub(object, vsId)


    def saveVirtualServer(self, virtualServer):
        if not self.useDataFile:
            return
        if virtualServer.isReadOnly:
            return
        
        role = commonTools.extractRole(virtualServer.virtualServerId)
        applicationName = self.applicationName
        if role != 'ncards':
            applicationName = self.getApplicationNameFromVirtualServer(
                    virtualServer)

        import pickle as glasnostPickle
        if not os.access(virtualServer.dataDirectoryPath, os.F_OK):
            os.mkdir(virtualServer.dataDirectoryPath)
            os.chmod(virtualServer.dataDirectoryPath, 0750)
        rcFilePath = os.path.join(
                virtualServer.dataDirectoryPath,
                applicationName + '.pickle')
        virtualServer.lock.acquire()
        newRcFilePath = rcFilePath + '.new'
        rcFile = open(newRcFilePath, 'wb')
        os.chmod(newRcFilePath, 0640)
        rcFile.write(glasnost.fileVersionNumber + '\n')
        glasnostPickle.dump(virtualServer, rcFile, 1)
        rcFile.close()
        os.rename(newRcFilePath, rcFilePath)
        virtualServer.lock.release()
        xmlFilePath = os.path.join(
                virtualServer.dataDirectoryPath,
                applicationName + '.xml')
        if os.access(xmlFilePath, os.F_OK):
            os.remove(xmlFilePath)

    def getObjectIdByRole(self, role):
        virtualServerId = context.getVar('applicationId')
        virtualServer = self.getVirtualServer(virtualServerId)
        for object in virtualServer.objects.values():
            if object.role == role:
                return object.id
        raise faults.MissingItem(role)

    def registerPublicMethods(self):
        ObjectsServer.registerPublicMethods(self)
        self.registerPublicMethod('getObjectEmail')
        self.registerPublicMethod('getObjectIdByRole')

    def pushContext(self, virtualServerId, clientToken, userToken):
        ObjectsServer.pushContext(self, virtualServerId, clientToken, userToken)
        context.setVar('applicationId', virtualServerId)

ncardsServer = NCardsServer()


if __name__ == "__main__":
    ncardsServer.launch(applicationName, applicationRole)

