import sys
import types

from time import time as _time

import sqlite

import gnserr

serverstatue = {
    'S_REGED': 1,
    'S_WORKING': 2,
    'S_PAUSED': 3,
    'S_STOPED': 4
    }

class Namepool:
    """
    Namepool: a name generater.
    """
    def __init__(self, mode = 'String' ,prefix='', postfix='', start=0, step=1):
        assert(mode in ['String', 'Integer', 'Long'])
        self.mode = mode
        if mode == 'String':
            self.prefix, self.postfix = prefix, postfix
        self.counter, self.step = start, step
    def get(self):
        r = self.hook[self.mode](self)
        self.counter += self.step
        return r
    hook = {
        'String': lambda self: self.prefix + str(self.counter) + self.postfix,
        'Integer': lambda self: int(self.counter),
        'Long': lambda self: long(self.counter)
        }

class Partition:
    def __init__(self, dbname=None):
        self.opendb(dbname)
        self.np = Namepool(mode = 'String',
            prefix='server://anonymous/s'+int(_time()).__str__()+'c'
            )
        self.idp = Namepool(mode = 'Long', start=_time()*1000)
    def opendb(self, dbname=None):
        if not dbname:
            raise gnserr.dbnameerr
        self.con = sqlite.connect(dbname, encoding='utf-8')
        return self
    def close(self):
        if not self.con.closed:
            self.con.close()
        return self
    def __del__(self):
        self.close()
    def create_db(self):
        assert((self.con) 
               and (not self.con.closed) 
               )
        cu = self.con.cursor()
        """
        sev_id: server's ident
        uri: server's uri, 129.0.0.1:8080, ftp://www.xxx.xxx/, ect. it's just a name.
        url: server's url, http://www.ddd.aaa:8080/, dns://kkk.ddd.ccc, ect. can figure out server's real address. 
        statue: server statue, work|pause|stop|death
        checktime: last update timestamp.
        """
        SQL_create_server_tb = \
		  """
		  create table servers (
		  sev_id int primary key, 
		  uri text(255),
                  url text not null,
		  statue int,
		  checktime int
		  )
		  """
        """
        res_id: resource id
        server: id of the server which countain the resource
        uri: resource uri
        """
        SQL_create_resource_tb = \
			   """
			   create table resources (
			   res_id long primary key,
			   server int,
			   uri varchar(255)
			   )
			   """
        cu.execute(SQL_create_server_tb)
        cu.execute(SQL_create_resource_tb)
        self.con.commit()
        return self
    def drop_db(self):
        cu = self.con.cursor()
        cu.executemany("drop table %s",
                       [('servers', ),
                        ('resources', )
                        ]
                       )
        self.con.commit()
        return self
    def dropall(self):
        self.drop_db()
        return self
    def addserver(self, serverinfo = None):
        cu = self.con.cursor()
        serverurl = serverinfo.get('url', None)
        if not serverurl:
            raise gnserr.urlerr(url)
        serveruri = serverinfo.get('uri', None)
        if serveruri:
            cu.execute("select count(*) from servers where uri='%(uri)s'"
                       %{'uri': serveruri})
            if int(cu.fetchone()[0]) >= 1:
                raise gnserr.haveserver(serveruri)
        else:
            serveruri = self.np.get()
        serverid = self.idp.get()
        cu.execute(
            """
            insert into servers
            (sev_id, uri, url, statue, checktime)
            values
            (%(sev_id)u,
            '%(uri)s',
            '%(url)s',
            %(statue)u,
            %(checktime)u
            )
            """%
            {'sev_id': serverid,
             'uri': serveruri,
             'url': serverurl,
             'statue': serverstatue['S_REGED'],
             'checktime': int(_time())
             }
            )
        self.con.commit()
        return serverid
    def dropserver(self, id):
        cu = self.con.cursor()
        cu.execute(
            """
            delete from servers
            where sev_id == %s
            """
            %(id)
            )
        self.con.commit()
        return self
    def _Pcase(self, case):
        wherecase = ' 1 '
        if len(case) <1 :
            raise ERROR
        for k, v in case.items():
            if type(v) in types.StringTypes:
                v = "'" + v + "'"
            wherecase += ' and '+ k +'=='+ str(v) +' '
        return wherecase
    def Qserver_case(self, case):
        wherecase = self._Pcase(case)
        cu = self.con.cursor()
        cu.execute("-- types long, str, str, int, long")
        cu.execute(
            """select sev_id, uri, url, statue, checktime
            from servers where %s"""
            %(wherecase)
            )
        res = cu.fetchall()
        res = map(dict, 
                  map(lambda x:
                      zip(('id', 'uri', 'url', 'statue', 'checktime'),x), 
                      res
                      )
                  )
        return res
    def Qserver4uri(self, uri):
        res = self.Qserver_case({'uri': uri})
        if len(res) > 1:
            raise gnserr.urierr(uri)        
        return res
    def Qserver4id(self, id):
        res = self.Qserver_case({'sev_id': id})
        if len(res) > 1:
            raise gnserr.urierr(uri)        
        return res
    def _Pattrs(self, attrs):
        if len(attrs) <1:
            raise ERROR
        assignments = ''
        for k, v in attrs.items():
            if type(v) in types.StringTypes:
                v = "'" + v + "'"
            assignments += ' '+k+'='+str(v)+','
        return assignments[:-1]
    def Sattrs4server(self, attrs, id):
        assignments = self._Pattrs(attrs)
        cu = self.con.cursor()
        cu.execute(
            """
            update servers
            set %s
            where sev_id = %s
            """
            %(assignments, id)
            )
        self.con.commit()
        return True
    def Sstatue4server(self, statue, id):
        res = self.Sattrs4server({'statue': statue}, id)
        return res
    def Surl4server(self, url, id):
        res = self.Sattrs4server({'url': url}, id)
        return res
    def QSattrs4server_case(self, attrs, case):
        wherecase = self._Pcase(case)
        assignments = self._Pattrs(attrs)
        cu = self.con.cursor()
        #cu.execute("begin  exclusive")
        cu.execute("-- types long")
        cu.execute(
            """
            select sev_id from servers
            where %s
            """
            %(wherecase)
            )
        res = cu.fetchone()
        if res:
            sid = res[0]
        else:
            return None
        cu.execute(
            """
            update servers set %s
            where sev_id=%s
            """
            %(assignments, sid)
            )
        #cu.execute("commit")
        #cu.execute("end")
        self.con.commit()
        return sid
class GNScore:
    def __init__(self):
        self.pdict = dict()
    def addPartition(self, pname, describe):
        if self.pdict.has_key(pname):
            raise ERROR
        self.pdict[pname] = [Partition(pname).create_db(), describe]
        return True
    def dropPartition(self, pname):
        if not self.pdict.has_key(pname):
            raise ERROR
        self.pdict.get(pname)[0].dropall()
        return True
    def setPartition(self, pname, describe):
        if not self.pdict.has_key(pname):
            raise ERROR
        self.pdict[pname][1] = describe
    def addServer(self, sinfo):
        if not self.pdict.has_key(sinfo.get('part','')):
            raise ERROR
        self.pdict.get(sinfo.get('part')
                       )[0].addserver(sinfo)

def test_Partition(tempdbname):
    import pprint
    pp = pprint.PrettyPrinter(indent=4)

    p=Partition(dbname=tempdbname)
    p.create_db()
    try:
        sid=list()
        sinfo = {
            'uri': 'hello://ddd.1',
            'url': '127.0.0.1:8081',
            }
        sid.append(p.addserver(sinfo))
        sinfo['uri'] = 'hello://dd.2'
        sid.append(p.addserver(sinfo))
        del sinfo['uri']
        sid.append(p.addserver(sinfo))
        pp.pprint(sid)
        pp.pprint(p.Qserver4uri('hello://ddd.1'))
        pp.pprint(p.Qserver4id(sid[1]))
        pp.pprint(p.Qserver_case({'1':1}))
        p.Sstatue4server(10, sid[1])
        p.Surl4server('hello://abc.def/', sid[1])
        pp.pprint(p.Qserver4id(sid[1]))
        p.dropserver(sid[1])
        pp.pprint(p.Qserver_case({'1':1}))
        sid = p.QSattrs4server_case({'statue': 20},
                                    {'statue': 1}
                                    )
        pp.pprint(p.Qserver4id(sid))
    finally:
        p.drop_db()
        p.close()

def test_GNScore():
    gns = GNScore()
    gns.addPartition("test", "test Partition")
    gns.dropPartition("test")
    sinfo = {
        "part": "test",
        "uri": "test://server1",
        "url": "127.0.0.1:8080"
        }
    gns.addServer(sinfo)
    sinfo['uri'] = 'test://server2'
    gns.addServer(sinfo)
    gns.qserver()
    
if __name__ == "__main__":
    test_Partition("testdb.sdb")
    test_GNScore()
