"""
Session manager class for gnuviech-admin tool backend
(c) 2006 Jan Dittberner <jan@dittberner.info>
$Id$
"""
import Settings
import os, sha, time, logging, psycopg2
from threading import Timer

SESSIONTIMEOUT=120 # 2 minutes

class InvalidLoginError(Exception):
    """
    Exception class for invalid logins.
    """
    pass

class InvalidSessionError(Exception):
    """
    Exception class for invalid sessions.
    """
    pass

class Session:
    def __init__(self, id, login):
        self.id = id
        self.login = login
        self._timeoutTimer = None

    def settimeoutTimer(self, timeoutTimer):
        self._timeoutTimer = timeoutTimer
        self._timeoutTimer.start()

    def gettimeoutTimer(self):
        return self._timeoutTimer

class SessionManager:
    """
    The Sessionmanager provides methods for login and session handling.
    """
    def __init__(self, dbconn):
        self._sessions = {}
        self._dbconn = dbconn
        self._hashobj = sha.new(str(time.time()))
        self.logger = logging.getLogger('SessionManager')

    def listSessions(self):
        return self._sessions.keys()
    
    def newSession(self, login, password):
        cr = self._dbconn.cursor()
        cr.execute('SELECT * FROM sysuser WHERE name=%(login)s AND md5pass=md5(%(password)s)' %
                   {'login': psycopg2.QuotedString(login),
                    'password' : psycopg2.QuotedString(password)})
        self._dbconn.commit()
        result = cr.fetchall()
        if cr.rowcount == 1:
            self._hashobj.update("%s,%s" % (time.time(), login))
            sessionid = self._hashobj.hexdigest()
            self._sessions[sessionid] = Session(sessionid, login)
            self.updateSession(sessionid)
            self.logger.info('New session with id %s created for %s' %
                             (sessionid, login))
            return sessionid
        self.logger.info('Login for %s failed' % login)
        raise InvalidLoginError

    def updateSession(self, sessionid):
        self.logger.debug("update session %s" % sessionid)
        try:
            session = self.getSession(sessionid)
        except InvalidSessionError, ev:
            pass
        else:
            if session.gettimeoutTimer() is not None:
                session.gettimeoutTimer().cancel()
            session.settimeoutTimer(Timer(SESSIONTIMEOUT, self.deleteSession,
                                          args=[sessionid]))
    
    def getSession(self, sessionid):
        if self._sessions.has_key(sessionid):
            return self._sessions[sessionid] 
        raise InvalidSessionError()

    def deleteSession(self, sessionid):
        self.logger.debug("delete session %s" % sessionid)
        try:
            session = self.getSession(sessionid)
        except InvalidSessionError:
            print "invalid session"
        else:
            if session.gettimeoutTimer() is not None:
                session.gettimeoutTimer().cancel()
            del(self._sessions[sessionid])
        self.logger.debug("%d sessions remaining" % len(self.listSessions()))