from common import exception

import db
import pickle
import logging

log = logging.getLogger()

class SEDB(object):
    
    def __init__(self):
        self.sdb = db.sdb
        self.conn = self.sdb.getConnection()
        self.c = self.sdb.getCursor()
    

    def makePickle(self, args, kwargs):
        return pickle.dumps((args, kwargs))

    def unPickle(self, p):
        return pickle.loads(p)

    
    def getHosts(self):
        # Return an unorded lists of hostIDs
        q = """select hostid from hosts"""
        self.c.execute(q)

        list = []
        row = self.c.fetchone()
        while row != None:
            list.append(row[0])
            row = self.c.fetchone()

        return list

        
    def getHost(self, id):
        q = """select hostname from hosts where hostid=%s"""
        self.c.execute(q, (id,))

        r = self.c.fetchone()
        if r == None:
            return None
        else:
            return r[0]
    

    def getHostID(self, hostname):
        q = """select hostid from hosts where hostname=%s"""
        self.c.execute(q, (hostname,))

        r = self.c.fetchone()
        if r == None:
            return None
        else:
            return r[0]


    def addHost(self, hostname):
        q = """insert into hosts (hostname) values (%s)"""
        
        id = self.getHostID(hostname)
        if id != None:
            return id
        
        self.c.execute(q, (hostname,))
        self.conn.commit()

        return self.getHostID(hostname)


    def getUID(self, hostid):
        q = """select uuid from hosts where hostid = %s"""

        self.c.execute(q, (hostid,))
        ret = self.c.fetchone()

        if ret:
            return ret[0]
        else:
            return None


    def getHostByUUID(self, uuid):
        q = "select hostid from hosts where uuid = %s"

        self.c.execute(q, (uuid,))
        ret = self.c.fetchone()

        if ret:
            return ret[0]
        else:
            return None

        
    def setUID(self, hostid, uid):
        q = """update hosts set uuid = %s where hostid = %s"""

        self.c.execute(q, (uid, hostid))


    def setHostName(self, hostid, name):
        if self.getHost(hosid) == None:
            raise exception.DBError("Host ID %s does not exist" % hostid)

        q = "update hosts set hostname = %s where hostid = %s"
        self.c.execute(q, (name, hostid))

        
    def storeStateObject(self, name, args, kwargs):
        q1 = """select stateid from stateobjects where 
                name = %s and args = %s"""
        q2 = """insert into stateobjects (name, args) values (%s, %s)"""
        p = self.makePickle(args, kwargs)

        return self.__genericStoreObject(q1, q2, (name, p))
        
    
    def storeActionObject(self, name, args, kwargs):
        q1 = """select actionid from actions where 
                name = %s and args = %s"""
        q2 = """insert into actions (name, args) values (%s, %s)"""
        p = self.makePickle(args, kwargs)
        
        return self.__genericStoreObject(q1, q2, (name, p))


    def __genericStoreObject(self, select, insert, args):
        self.c.execute(select, args)
        ret = self.c.fetchone()
        if ret:
            return ret[0]

        self.c.execute(insert, args)
        self.conn.commit()

        self.c.execute(select, args)
        ret = self.c.fetchone()
        if ret:
            return ret[0]
        else:
            raise execption.DBError("Database inconsistancy.")

    
    def queuePut(self, hostid, action, args, kwargs):
        q =  """insert into actionqueue (actionid, queue, hostid, setid)
                select %s, ifnull(max(queue)+1, 0), %s, %s 
                    from actionqueue where hostid=%s
                """
        
        # XXX
        setid = -1
        actionid = self.storeActionObject(action, args, kwargs)
        
        self.c.execute(q, (actionid, hostid, setid, hostid))

        self.conn.commit()
        

    def queueGet(self, hostid):
        q = """select actionqueue.queueid, actionqueue.hostid, 
                   actionqueue.queue, actions.name, actions.args
               from actions, actionqueue
               where actions.actionid = actionqueue.actionid
               and actionqueue.hostid = %s
               order by actionqueue.queue asc limit 1"""

        self.c.execute(q, (hostid,))
        r = self.c.fetchone()

        if r == None:
            return None
        
        ret = {}
        args = self.unPickle(r[4])
        ret['queueID'] = r[0]
        ret['hostid'] = r[1]
        ret['name'] = r[3]
        ret['args'] = args[0]
        ret['kwargs'] = args[1]
        
        return ret


    def queueRemove(self, queueID):
        q = """delete from actionqueue where queueid=%s"""
        self.c.execute(q, (queueID,))
        self.conn.commit()
        

    def getState(self, stateid):
        # reurn (name, args, kwargs)
        
        q = """select name, args from stateobject where stateid = %s"""

        self.c.execute(q, ())
        r = self.c.fetchone()
        if r == None:
            return None

        name = r[0]
        args, kwargs = self.unPickle(r[1])
        return name, args, kwargs

    def getStateID(self, stateKey, args, kwargs):
        """Add a State to the system and return its ID"""
        # The beauty here is that we want to preserve order of args
        # but we don't care so much about the kswargs, just like python
        # The pickle objects will do this for us, and we compare them
        # as strings

        q1 = """select count(*) from stateobjects where
                name = %s and args = %s"""
        q2 = """insert into stateobjects (name, args) values (%s, %s)"""
        q3 = """select stateid from stateobjects where name = %s
                and args = %s"""
                
        p = self.makePickle(args, kwargs)
        self.c.execute(q1, (stateKey, p))
        r = self.c.fetchone()
        if r[0] == 0:
            self.c.execute(q2, (stateKey, p))
            self.conn.commit()

        self.c.execute(q3, (stateKey, p))
        r = self.c.fetchone()
        if r == None:
            raise exceptions.SQLite("Database error inserting state object")

        return r[0]

    def hasState(self, hostid, stateid):
        """Returns True if given host contains the given state, False 
           otherwise."""

        q1 = """select count(*) from sets where stateid = %s and hostid = %s"""

        self.c.execute(q1, (stateid, hostid))
        r = self.c.fetchone()
        if r[0] > 0:
            return True
        else:
            return False
        
    def setStateSet(self, hostid, stateid):
        q1 = """insert into sets (hostid, stateid, queue)
                select %s, %s, ifnull(max(queue)+1, 0)
                from sets where hostid=%s"""
    
        if not self.hasState(hostid, stateid):
            self.c.execute(q1, (hostid, stateid, hostid))
            self.conn.commit()
            log.info("setStateSet(): Host %s has state %s" % (hostid, stateid))
    
    def getStateSet(self, hostid):
        q = """select stateid, queue from sets
               where hostid = %s order by queue asc"""

        set = []
        self.c.execute(q, (hostid,))
        r = self.c.fetchone()
        while r != None:
            set.append(r[0])
            r = self.c.fetchone()

        return set
    
