#######################################################################The Database !!!!
import sqlite3,os,re

def allfilefrom(path,ext):
    for filename in ( (pth+'/'+name).replace('//','/')
             for pth,_,names in os.walk(path) 
             for name in names 
             if name.endswith(ext)
             if not name.startswith('.') ):
        yield filename,str(open(filename,'r').read())

def macroapply(src,macro):
    for reg, rep in macro.items():
        #print reg,rep
        p = re.compile(reg)
        m = p.search(src)
        #print m
        while m:
            b, e = m.span()
	    if p.groups == 1:
	            n = rep.format(name=m.group(1))
        	    #print('replace',src[b:e],' for ',n)
	            src = ''.join([ src[:b], n, src[e:] ])
	    elif p.groups == 2:
	            n = rep.format(name=m.group(1),view=m.group(2))
        	    #print('replace',src[b:e],' for ',n)
	            src = ''.join([ src[:b], n, src[e:] ])
            m = p.search(src)
    #print src
    return src

def dbexec(conn,script):
        cur = conn.cursor()
        try:
            cur.executescript(script)
	except Exception as e:
            print( script,e)


def dbcompile(dbfile,srcfile='src/sql/'):
    print("load all script")
    allscript = [ loaded for loaded in allfilefrom(srcfile,'.sql')]
    re_ismacro = re.compile('--MACRO:([^:]+):--')
    print("load macro")
    macrolst = []
    for filename,macro in allscript:
        m = re_ismacro.search(macro)
        if m:
            print ('macro '+filename)
            regex = m.group(1)
            macro = re.sub(re_ismacro,'',macro)
            macrolst.append((regex,macro))
    macro = dict(macrolst)
    conn =  sqlite3.connect(dbfile,check_same_thread=False)
    print("initiating the database")
    for filename, script in allscript:
        if not re_ismacro.search(script):
            print ('loading '+filename)
            script = macroapply(script,macro)
            dbexec(conn,script)
    return conn

def dbquery(dbfile,querytxt):
    conn = sqlite3.connect(dbfile)
    result=[]
    try:
        cur = conn.cursor()
        cur.execute(querytxt)
        if cur.description:
            col = [ attr[0] for attr in cur.description ]
            result = [ dict(zip(col,row)) for row in cur.fetchall()]
    except Exception as e:
        print(e)
    return result

def dbupdate(dbfile,querytxt):
    conn = sqlite3.connect(dbfile)
    cur = conn.cursor()
    cur.execute(querytxt)
    conn.commit()

def render(dbfile,usr=''):
    query = "SELECT * FROM render WHERE usr IN('{usr}','all')"
    query = query.format(usr=usr)
    result = dbquery(dbfile,query)
    return result

def event(dbfile,usr,msg):
    assert usr,'variable "usr" must be something 1!'
    query = "INSERT OR REPLACE INTO event (usr,msg) VALUES('{usr}','{msg}')"
    query = query.format(usr=usr,msg=msg)
    dbupdate(dbfile,query)
    return 'ok'

def history(dbfile):
    result = dbquery(dbfile,'SELECT * FROM logging')
    print result


###########################################################################the interface!!!
import SimpleHTTPServer 
import SimpleXMLRPCServer
from SocketServer import ThreadingMixIn
import threading
import os,sys

class RequestHandler(ThreadingMixIn,
                     SimpleXMLRPCServer.SimpleXMLRPCRequestHandler,
                     SimpleHTTPServer.SimpleHTTPRequestHandler):
    rpc_paths = ('/RPC2',)

class Server(object):
    def __init__(self,dbfile):
        self.server = SimpleXMLRPCServer.SimpleXMLRPCServer(("", 57005),
                                                       requestHandler=RequestHandler,
                                                       allow_none=True,
                                                       logRequests=False)
        self.server.register_introspection_functions()
        self.server.register_function(lambda  : "hello world!!!", 'hello')
        self.server.register_function(lambda c,v : event(dbfile,c,v),'event')
        self.server.register_function(lambda c : render(dbfile,c),'render')
        print "yosup engine server"
        self.thread = threading.Thread(target = self.server.serve_forever)
        self.thread.daemon = True
        self.thread.start()

##########################################################the hearthbeat ! ! !

import time

class HeartBeat(object):
    def __init__(self,dbname):
        self.query = "UPDATE event SET msg='boom', utime=CURRENT_TIMESTAMP WHERE usr=='heartbeat'"
        self.online = True
        def timeloop():
            print("timer on")

            while self.online:
                try:
                    #dbupdate(dbname,self.query)
                    event(dbname,'heartbeat','boom');
                except Exception as e:
                    print e
                    self.online=False
                time.sleep(0.1)
        self.timethread = threading.Thread(target = timeloop)
        self.timethread.daemon = True
        self.timethread.start()

###########################################################the administrator !!!

def admin(dbname):
    cli = []
    #help show all function
    def _help():
        msg = """exit to exit
reload to reinitialise the database
restart to restart the whole program
history to list all input
yo [name] [msg] to send a msg
wazzup [name] to see msg"""
        print(msg)
        return
    cli.append((lambda name : name=='help',_help))
    #restart restart the whole program
    def _restart():
        print("""restart""")
        os.execl(sys.executable, sys.executable, * sys.argv)
    cli.append((lambda name : name == 'restart', _restart))
    #reload reinitialise the database
    def _reload():
        dbcompile(dbname)
    cli.append((lambda name : name == 'reload',_reload))
    #history
    def _history():
        print(history(dbname))
    cli.append((lambda name : name == 'history',_history))
    #wazzup
    def _render():
        print(render(dbname,'test'))
    cli.append((lambda name : name == 'render',_render))
    #yo
    def _event():
        print(event(dbname,'test','test'))
    cli.append((lambda name : name == 'event',_event))

    #default message for all other command
    def _tryhelp():
        print('try help')
    cli.append((lambda name : True,_tryhelp))
    #the main loop
    command = raw_input("""
yosup server supposely online
type exit to exit
try help
B==D """)
    while command != 'exit':
        for predicate, functor in cli:
            if predicate(command):
                functor()
                break
        command = raw_input("""B==D """)


#########################MAIN

if __name__ == '__main__':
    import re,sys

    if sys.argv[1]:
        dbname = sys.argv[1]+'::memory:?cache=shared&,mode=memory'
        dbconn = dbcompile(dbname)
        server = Server(dbname)
        heartbeat = HeartBeat(dbname)
        admin(dbname)

