import time, os, sys, socketserver
from struct import *

kBufSize = 1024

class MyTCPHandler(socketserver.BaseRequestHandler):
    """
    The request handler class for our server.

    It is instantiated once per connection to the server, and must
    override the handle() method to implement communication to the
    client.
    """

    def handle(self):
        # get bytes to the begining of file meta
        print("[new upload request received]")
        size_wanted = 2 + 2 + 12 + 8 + 8 + 1 + 4
        head = self.request.recv(size_wanted)
        header_parsed = unpack("<2BH12sqqBI", head)
        print("header hex: ", head.hex())
        print("parsed:")
        if header_parsed[0] == 0xBE and header_parsed[1] == 0xEF:
            print("\t[valid] magic header:", hex(header_parsed[0]), hex(header_parsed[1]))
        else:
            print("\t[invalid] magic header: ", hex(header_parsed[0]), hex(header_parsed[1]))
        if header_parsed[2] == 12:
            print("\t[valid] sn len: 12")
        else:
            print("\t[valid] sn len: ", header_parsed[2])
        print("\tsn: ", header_parsed[3])
        print("\ttss: ", header_parsed[4])
        print("\ttse: ", header_parsed[5])
        print("\ttype: ", header_parsed[6])
        print("\tnum: ", header_parsed[7])

        # get files meta plus crc
        size_wanted = header_parsed[7]*12 + 2
        filemeta =  self.request.recv(size_wanted)
        print("meta hex: ", filemeta.hex())
        meta_parsed = [x for x in iter_unpack("<qI", filemeta[:header_parsed[7]*12])]
        print("parsed:")
        for x in meta_parsed:
            print("\tfile ts: {}, size: {}".format(x[0], x[1]))
        # TODO: calc crc
        print("\t[valid]crc: ", unpack("<H", filemeta[header_parsed[7]*12:])[0])

        # iter filemeta to save files
        for x in meta_parsed:
            data = self.request.recv(4)
            sz = unpack("<I", data)
            if x[1] != sz[0]:
                print("[error] invalid file size in body")
                return
            else:
                print("receiving file: {}, len: {}".format(x[0], x[1]))
            size_wanted = x[1]
            with open(str(x[0])+ ".h264", "wb") as f:
                totalWritten = 0
                while size_wanted > 0: 
                    want = size_wanted if size_wanted <= kBufSize else kBufSize
                    # read and write max kBufSize bytes, so never get OOM
                    data = self.request.recv(want)
                    f.write(data)
                    size_wanted -= len(data)
            print("OK written file {}.h264:{}".format(x[0], x[1]))
        print("save all files done!")
        # TODO: verify magic tail

        # TODO: do ffmpeg convertions (raw h264 to mp4) and merge , saving database records,  sending events releted stuffs etc.


if __name__ == "__main__":
    HOST, PORT = "0.0.0.0", 10009

    # Create the server, binding to localhost on port 9999
    socketserver.TCPServer.allow_reuse_address = True
    with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
        # Activate the server; this will keep running until you
        # interrupt the program with Ctrl-C
        server.serve_forever()