#!/usr/bin/python
import time
import threading
import os
import sys
import re
import shutil
import mimetypes
import SimpleHTTPServer
import SimpleXMLRPCServer
import BaseHTTPServer
import SocketServer
import multiprocessing
import sqlite3
import zipfile
import json

"""TODO

admin, command parameter (emit poke ...) (get poke)
thread, pulse
"""

"""SQLITE
"""
class Sql(object):
    def __init__(self,dbfile):
        self.dbfile=dbfile
        self.conn = False

    def _connect(self):
        if not self.conn:
            self.conn = sqlite3.connect(':memory:',
                                        check_same_thread=False,
                                        isolation_level=None)
            self.conn.cursor().execute("ATTACH DATABASE '%(dbfile)s' AS HSS;" % {'dbfile':self.dbfile})
            self.conn.commit()
        return self

    def _query(self,querytxt):
        self._connect()
        result=[]
        try:
            cur = self.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 _update(self,querytxt):
        self._connect()
        try:
            cur = self.conn.cursor()
            cur.execute(querytxt)
            self.conn.commit()
        except Exception as e:
            print(e)
        return self

    def _haveTable(self,name):
        sql = "SELECT name FROM sqlite_master WHERE type='table' AND name='"+name+"'"
        return bool(self._get(sql))

    @staticmethod
    def compile(dbname,querytxt):
        try:
            os.remove(dbname)
        except:
            pass
        conn = sqlite3.connect(dbname)
        try:
            cur = conn.cursor()
            cur.executescript(querytxt)
            conn.commit()
            def printsql(query):
                cur.execute(query)
                for row in cur.fetchall():
                    print row
            print "compiled"
            print "list of table"
            printsql("""select name,type
                           from sqlite_master 
                           where type in ('table','view')""")
                           #and name in ('EM','GT','HB','FSM','KV')""")
            print "kv store"
            printsql("select * from kv")
            print "predicate engine"
            printsql("select * from prd")
            printsql("select * from prdd")
            print "done"
        except Exception as e:
            print(e)
        return conn

    def get(self,_id):
        sql = "select MSG from HSS.GT where ID='"+_id+"'"
        result = self._query(sql)
        return result

    def emit(self,_id,msg):
        sql = "insert into HSS.EM(ID,MSG) values('"+_id+"','"+msg+"')"
        self._update(sql)

    def pulse(self):
        sql = "insert into HSS.HB(T) values(CURRENT_TIMESTAMP)"
        self._update(sql)
"""HTTP
"""

def _get(uri):
    return {'api' : 'rest'}

def _post(uri,data):
    print uri
    print data

def Http(zfile,
        get=_get,
        post=_post,
        funcLst= [('hello',lambda a : 'hello')],
        port=57005):
    print "load static files"
    www = zipfile.ZipFile(zfile, 'r')
    for name in www.namelist():
        print name
    print "prepare rest api and directory mapping"
    class RequestHandler(
                         SocketServer.ThreadingMixIn,
                         BaseHTTPServer.BaseHTTPRequestHandler,
                         SimpleXMLRPCServer.SimpleXMLRPCRequestHandler,
                         #SimpleHTTPServer.SimpleHTTPRequestHandleri
                         ):
        """
        XML rpc server
        """
        rpc_paths = ('/RPC2',)

        def do_HEAD(self):
            print self.path
            print self.headers
            print self.headers.getheader('content-type')
            print self.headers.getheader('content-length')


        def do_GET(self):
            self.do_HEAD()
            """
            rest api !!!
            """
            if '/api/' in self.path:
                self.send_response(200)
                self.send_header('Content-Type', 'application/json')
                self.end_headers()
                response = get('/api/')
                self.wfile.write(response)
            else:
                path = 'www/main.html'
                try:
                    content, encoding = mimetypes.MimeTypes().guess_type(path)
                    if content is None:
                        content = "application/octet-stream"
                    #info = os.stat(path)
                    info = www.getinfo(path)
                    self.send_response(200)
                    self.send_header("Content-Type", content)
                    self.send_header("Content-Encoding", encoding)
                    #self.send_header("Content-Length", info.st_size)
                    self.send_header("Content-Length",info.file_size)
                    self.end_headers()
                    #f = open(path, 'rb')
                    f = www.open(path,'r')
                    shutil.copyfileobj(f, self.wfile)
                    f.close()
                except Exception as e:
                    self.send_error(404, "file not found")

        def do_POST(self):
            """
            will simply put in queue every post
            it is eventqueue only env
            """
            self.do_HEAD()
            print self.rfile
            post(self.rfile)
            self.send_response(200)
            self.end_headers()
    print "prepare xml rpc http server"
    class HtmlRpcServer(object):
        def __init__(self,port=port,funcLst=funcLst):
            self.server = SimpleXMLRPCServer.SimpleXMLRPCServer(("", port),
                                                           requestHandler=RequestHandler,
                                                           allow_none=True,
                                                           logRequests=False)
            self.server.register_introspection_functions()
            self.server.register_function(lambda  : "hello world!!!", 'hello')
            for name,functor in funcLst:
                self.server.register_function(functor,name)
            self.thread = threading.Thread(target = self.server.serve_forever)
            self.thread.daemon = True
            self.thread.start()
    print "initialise server"
    
    def fn():
        server = HtmlRpcServer()
        return server
    return fn()
"""THREAD
"""

def _beat():
    pass

class Thread(object):
    def __init__(self,functor=_beat, timing=0.1):
        self.online = False
        self.functor = functor
        def timeloop():
            if timing < 1:
                print "thread initiated at ",1.0/timing," tick every seconds"
            else:
                print "thread initiated at 1 tick every ",timing," seconds"
            while True:
                try:
                    if self.online:
                        if self.functor:
                            self.functor = self.functor()
                        else:
                            self.online = None
                    else:
                        time.sleep(0.25)
                except Exception as e:
                    print e
                    print 'wait a sec'
                    time.sleep(1)
                time.sleep(timing)
            print "thread interrupted"
        self.timethread = threading.Thread(target = timeloop)
        self.timethread.daemon = True
        self.timethread.start()

    def stop(self):
        print "stop"
        self.online = False

    def start(self):
        print "start"
        self.online = True

"""ADMIN
"""
def Admin():
    pay = {
        'db' : None,
        'th' : 'Thread()'
    }
    def _th():
        pay['db'].pulse()
        return _th
    pay['th'] = Thread(_th,5)
    Sql.compile('hss.db',open('hss.sql','r').read())
    pay['db'] = Sql('hss.db')

    cli = []
    def _help():
        for name,_,how in cli:
            if how:
                print name,how
    cli.append(('help',_help," => show this"))
    def _play():
        import webbrowser
        webbrowser.open('localhost:57005/www/main.html',2,True)
        print "webbrowser triggered"
    cli.append(('play',_play," => start game"))
    def _restart():
        print("""restart""")
        os.execl(sys.executable, sys.executable, * sys.argv)
    cli.append(('restart', _restart," => restart the whole server"))
    #threading
    def _start():
        print "start thread"
        pay['th'].start()
    cli.append(('start',_start," => initiate heartbeat if not already"))
    def _stop():
        print "stop thread"
        pay['th'].stop()
    cli.append(('stop',_stop," => stop heartbeat"))
    #database sqlite
    def _emit():
        default_id = 'testID'
        default_msg = 'anything'
        _id = raw_input("ID ("+default_id+"?): ")
        if not _id:
            _id = default_id
        _msg = raw_input("MSG ("+default_msg+"?): ")
        if not _msg:
            _msg = default_msg
        pay['db'].emit(_id,_msg)
        print "ok"
    cli.append(('emit',_emit," => emit message to database"))
    def _get():
        default_id = 'testID'
        _id = raw_input("ID ("+default_id+"?): ")
        if not _id:
            _id = default_id
        print pay['db'].get(_id)
    cli.append(('get',_get," => get data from database with id"))
    def _pulse():
        pay['db'].pulse()
        print "triggered one cycle"
    cli.append(('pulse',_pulse," => trigger one heartbeat into the database"))
    def _load(default_dbfilename='hss.db'):
        filename = raw_input("load db file ("+default_dbfilename+"?) : ")
        if not filename:
            filename = default_dbfilename
        pay['db'] = Sql(filename)
        print "loaded"
    cli.append(('load',_load," => load sqlite database"))
    def _compile(default_filename = 'hss.sql'):
        filename = raw_input("compile src file ("+default_filename+"?) : ")
        if not filename:
            filename = default_filename
        file = open(filename,'r')
        src = file.read()
        dbfilename = filename.replace('.sql','.db')
        db = Sql.compile(dbfilename,src)
        _load(dbfilename)
    cli.append(('compile',_compile," => compile sqlite code"))
    #default menu item
    def _tryhelp():
        print('try help')
    cli.append((True,_tryhelp,""))
    cli.append(('','','exit => to shutdown'))
    #the main loop
    command = raw_input("]]] ")
    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("]]] ")
    print 'bye'


if __name__ == '__main__':
    """MAIN
    """
    Dic = multiprocessing.Manager().dict()
    Que = multiprocessing.Queue()

    Dic['api'] = { "hello" : "world" }

    server = Http('www.zip')
    #heartbeat = Thread()
    Admin()

   
