#!/usr/bin/python
import time
import threading
import os
import sys
import re
import shutil
import struct
import socket
import mimetypes
import SimpleHTTPServer
import SimpleXMLRPCServer
import BaseHTTPServer
import SocketServer
import multiprocessing
import zipfile
import json
import xmlrpclib
"""TODO



"""

"""INDEX

   HTTP 50gg
   SQL 150gg
   THREAD 
   ADMIN 277gg
"""

"""HTTP

minimalist python web backend
only python 2.7 included library
support assets from zip file
have http get api endpoint (WIP)
have xml2rpc posting capability
"""
def Http(zfile,
        get=lambda path: path,
        funcLst= [('hello',lambda a : 'hello')],
        port=57005,
        beacon=True):

    class Beacon(object):
        def __init__(self, timing=0.1):
	    if timing < 1:
		print "beacon initiated at ",1.0/timing," tick every seconds"
	    else:
		print "beacon initiated at 1 tick every ",timing," seconds"
            self.timing = timing
	    self.start()
            self.ip = '224.1.1.1'
            self.port = 57005

            def timeloop():
	        while True:
		    try:
		        if self.online:
		            self.sock.sendto("B==D", (self.ip, self.port))
		        else:
			    time.sleep(0.25)
		    except Exception as e:
		        print e
		        print 'wait a sec'
		        time.sleep(1)
		    time.sleep(timing)
	        print "beacon interrupted"

	    self.timethread = threading.Thread(target = timeloop)
	    self.timethread.daemon = True
	    self.timethread.start()

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

        def start(self):
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            self.sock.settimeout(self.timing)
            ttl = struct.pack('b',1)
            self.sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)
            print "beacon start"
            self.online = True

    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 !!!
            """
            print 'http get'
            if '/api/' in self.path:
                #todo something here
                #like query route
                self.send_response(200)
                self.send_header('Content-Type', 'application/json')
                self.end_headers()
                response = get('/api/')
                self.wfile.write(response)
            else:
		print self.path
                if self.path == '/':
                    path = 'www/main.html'
                else:
                    path = 'www' + self.path
                path = 'app/'+path
                try:
                    content, encoding = mimetypes.MimeTypes().guess_type(path)
                    if content is None:
                        content = "application/octet-stream"
                    #info = os.stat(path)
		    zwww = zipfile.ZipFile(zfile, 'r')
                    info = zwww.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 = zwww.open(path,'r')
                    shutil.copyfileobj(f, self.wfile)
                    f.close()
		    zwww.close()
                except Exception as e:
		    print e
                    self.send_error(404, "file not found")

    print "prepare xml rpc http server"
    class HtmlRpcServer(object):
        def __init__(self,port=port,funcLst=funcLst):
            if beacon:
                print "init beacon"
            self.beacon = Beacon()
	    print "init xml-rpc/rest/http server"
            self.server = SimpleXMLRPCServer.SimpleXMLRPCServer(("", port),
                                                           requestHandler=RequestHandler,
                                                           allow_none=True,
                                                           logRequests=True)
            for name,functor in funcLst:
                self.server.register_function(functor,name)
            self.server.register_function(lambda a : [ name for name,_ in funclst ])
            self.server.register_introspection_functions()
            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,beacon
    return fn()

"""CLIENT
"""

def Query(ip='224.1.1.1', port=57005):
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
    sock.settimeout(3.5)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(('',port))
    group = socket.inet_aton(ip)
    mreq = struct.pack('4sL',group, socket.INADDR_ANY)
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
    data, address = sock.recvfrom(10240)
    return data, address
    
def List(ip='localhost',port=57005):
    with xmlrpclib.ServerProxy('http://'+ip+':'+port+'/rpc2') as proxy:
        proxy.list()

"""ADMIN
"""
def Admin(zfile="app.zip", 
          sfile="save.db"):
    Dic = multiprocessing.Manager().dict()
    Que = multiprocessing.Queue()
    Dic['api'] = { "hello" : "world" }

    http = Http(zfile,
		lambda path: "http get "+ path,
		[
		])

    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"))
    def _repak():
        print "repaking the whole shit to",zfile
	os.remove(zfile);
	ziph = zipfile.ZipFile(zfile,'w',zipfile.ZIP_DEFLATED)
	for root, dirs, files in os.walk('app'):
	    for file in files:
                path = os.path.join(root,file)
	        ziph.write(path)
        ziph.close()
    cli.append(('repak',_repak, " => re package app/ dir to app.zip"))
    def _query():
        print "query beacon"
        msg = Query()
        print msg
    cli.append(('query',_query, "query beacon for service"))
    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
    """
    Admin()

   
