#!/usr/bin/python

import sqlite3
import time

import SimpleHTTPServer
import SimpleXMLRPCServer
from SocketServer import ThreadingMixIn
import threading
import os,sys,re

def connect(dbfile):
    conn = sqlite3.connect(':memory:')
    conn.cursor().execute("ATTACH DATABASE '%(dbfile)s' AS HSS;" % {'dbfile':dbfile})
    conn.commit()
    return conn

def dbquery(dbname,querytxt):
    conn = connect(dbname)
    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(dbname,querytxt):
    conn = connect(dbname)
    cur = conn.cursor()
    cur.execute(querytxt)
    conn.commit()

def render(dbname,usr=''):
    query = "SELECT * FROM HSS.REPORT"
    query = query.format(usr=usr)
    result = dbquery(dbname,query)
    return result

def refresh(dbname):
    query = "UPDATE HSS.HEARTBEAT SET ID=ID"
    dbupdate(dbname,query)

def event(dbname,id,usr,msg):
    assert False, 'input must be managed in order not to have injection'
    #assert usr,'variable "usr" must be something 1!'
    #query = "INSERT INTO HSS.EMIT (ID,USR,MSG) VALUES('{id}' ,'{usr}','{msg}')"
    #query = query.format(id=id,usr=usr,msg=msg)
    #dbupdate(dbname,query)
    return 'ok'

def history():
    assert False, 'not implemented'
    result = dbquery(dbname,'SELECT * FROM HSS.LOGGING')
    return "\n".join([ '%(USR)s@%(LEVEL)s : %(MSG)s' % d
                       for d in result ])


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

class Server(object):
    def __init__(self,dbname):
        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 id,usr,msg : event(dbname,id,usr,msg),'event')
        self.server.register_function(lambda usr : render(dbname,usr),'render')
        print "yosup engine server"
        self.thread = threading.Thread(target = self.server.serve_forever)
        self.thread.daemon = True
        self.thread.start()

class HeartBeat(object):
    def __init__(self,dbname, timing=0.1):
        self.online = True
        def timeloop():
            print("heartbeat initiated at "+str(1/timing)+" tick every seconds")
            while True:
                try:
                    if self.online:
                        refresh(dbname)
                        #event(dbname,'heartbeat','sys','boom');

                except Exception as e:
                    print e
                    print 'wait a sec'
                    time.sleep(1)
                time.sleep(timing)
        self.timethread = threading.Thread(target = timeloop)
        self.timethread.daemon = True
        self.timethread.start()

    def stop(self):
        self.online = False

    def start(self):
        self.online = True

#admin section
def admin(dbname,heartbeat):
    cli = []
    def _help():
        for name,_,how in cli:
            if how:
                print name,how
    cli.append(('help',_help," => show this"))
    def _restart():
        print("""restart""")
        os.execl(sys.executable, sys.executable, * sys.argv)
    cli.append(('restart', _restart," => restart the whole server"))
    def _history():
        print(history(dbname))
    cli.append(('history',_history," => show logging"))
    def _render():
        print(render(dbname,'test'))
    cli.append(('render( [a-zA-Z]+)?',_render," => show current rendering of user $1"))
    def _event():
        print(event(dbname,'test','test'))
    cli.append((r'event( [a-zA-Z]+ [a-zA-Z0-9_ ]+)?',_event," => send message $2 from user $1"))
    def _start():
        print "start heartbeat"
        heartbeat.start()
    cli.append(('start',_start," => initiate heartbeat if not already"))
    def _stop():
        print "stop heartbeat"
        heartbeat.stop()
    cli.append(('stop',_stop," => stop heartbeat"))
    def _tryhelp():
        print('try help')
    cli.append((True,_tryhelp,""))
    cli.append(('','','exit => to shutdown'))
    #the main loop
    command = raw_input("B==D ")
    while command != 'exit':
        for condition, functor,doc in cli:
            if isinstance(condition,str):
                predicate = lambda a : re.compile(condition).match(command)
            if isinstance(condition,bool):
                predicate = lambda a : condition
            if callable(condition):
                predicate = condition
            if predicate(command):
                functor()
                break
        command = raw_input("B==D ")
    print 'bye'

if __name__ == '__main__':
    import sys

    if sys.argv[1]:
        dbname = sys.argv[1]
        print dbname
        server = Server(dbname)
        heartbeat = HeartBeat(dbname)
        admin(dbname,heartbeat)
    else:
        print sys.argv
    
