# (c) J.Y.Amihud 2023
# GPL-3 or any later version

# This is a http server that will serve files over network, for multiusering
# across the internet.

# Server side
from http.server import BaseHTTPRequestHandler, HTTPServer
from subprocess import *
import json
import os
import zlib
import sys
import time
import random
import mimetypes
import datetime
import hashlib
import urllib.request
import urllib.parse
import subprocess



# Colors are used to make the
clr = {
    "norm":"\033[00m", # Reset to normal
    "bold":"\033[01m", # Bold Text
    "ital":"\033[03m", # Italic Text
    "undr":"\033[04m", # Underlined
    "blnk":"\033[05m", # Blinking

    # Text
    "tdbl":"\033[30m", # Dark Black
    "tdrd":"\033[31m", # Dark Red
    "tdgr":"\033[32m", # Dark Green
    "tdyl":"\033[33m", # Dark Yellow
    "tdbu":"\033[34m", # Dark Blue
    "tdma":"\033[35m", # Dark Magenta
    "tdcy":"\033[36m", # Dark Cyan
    "tdwh":"\033[37m", # Dark White

    "tbbl":"\033[90m", # Bright Black
    "tbrd":"\033[91m", # Bright Red
    "tbgr":"\033[92m", # Bright Green
    "tbyl":"\033[93m", # Bright Yellow
    "tbbu":"\033[94m", # Bright Blue
    "tbma":"\033[95m", # Bright Magenta
    "tbcy":"\033[96m", # Bright Cyan
    "tbwh":"\033[97m", # Bright White

    # Background
    "bdbl":"\033[40m", # Dark Black
    "bdrd":"\033[41m", # Dark Red
    "bdgr":"\033[42m", # Dark Green
    "bdyl":"\033[43m", # Dark Yellow
    "bdbu":"\033[44m", # Dark Blue
    "bdma":"\033[45m", # Dark Magenta
    "bdcy":"\033[46m", # Dark Cyan
    "bdwh":"\033[47m", # Dark White

    "bbbl":"\033[100m", # Bright Black
    "bbrd":"\033[101m", # Bright Red
    "bbgr":"\033[102m", # Bright Green
    "bbyl":"\033[103m", # Bright Yellow
    "bbbu":"\033[104m", # Bright Blue
    "bbma":"\033[105m", # Bright Magenta
    "bbcy":"\033[106m", # Bright Cyan
    "bbwh":"\033[108m"  # Bright White
}

# TODO: Make this not stupidly hardcoded.

blender = "/home/vcs/Software/blender-3.3.0-linux-x64/blender"


try:
    PROJECT = sys.argv[2]
except:
    print("Please specify a port number and then project folder.")
    exit()

try:
    ORIGINAL_PROJECT = sys.argv[3]
except:
    print("Orignal Project Name Was Not Specified.")
    ORIGINAL_PROJECT = " not a folder that can exist "
    
def fileinfo(filename):

    fd = {}
    fd["md5"] = hashlib.md5(open(filename,'rb').read()).hexdigest()
    fd["filesize"] = os.path.getsize(filename)
    return fd
                
    

class handler(BaseHTTPRequestHandler):

    def start_page(self, code):
        
        self.send_response(code)

    def do_GET(self):

        # Basic security measure
        self.path = self.path.replace("/..", "/")
        self.path = self.path.replace("//", "/")

        if self.path == "/":
            self.start_page(200)
            self.wfile.write(b"Welcome to Blender-Pipeline Http Server.\nUse /list/[Folder Name] to list contents of a specific folder.\nUse /download/[File Name] to download the file.\nUse /blend/[Blender File Name] to see Blend File Dependencies.")


        elif self.path.startswith("/list/"):
            
            foldername = self.path[5:]
            folder = PROJECT+foldername
            
            walk = list(os.walk(folder))[0]
            # folders
            data = {"folders":walk[1],
                    "files":{}}
            
            for i in walk[2]:
                fd = fileinfo(folder+"/"+i)
                data["files"][i] = fd
            

            senddata = json.dumps(data).encode("utf-8")
            self.start_page(200)
            self.send_header('Content-type', 'application/json')
            self.end_headers()
            self.wfile.write(senddata)

        # THIS WAS A GOOD IDEA ON PAPER, BUT WITH A 100 GB PROJECT
        # IT TOOK FOREVER TO DO THIS FOR ONE PART OF THIS PROJECT.
            
        # elif self.path.startswith("/tree/"):
        #     foldername = self.path[5:]
        #     folder = PROJECT+foldername
            
        #     walk = list(os.walk(folder))
        #     data = {"folders":[],
        #             "files":{}}
        #     for i in walk:
        #         fol = i[0].replace(PROJECT, "")[1:]
        #         data["folders"].append(fol)
        #         for fil in i[2]:
                    
        #             fd = fileinfo(PROJECT+"/"+fol+"/"+fil)
        #             data["files"][fol+"/"+fil] = fd

        #     senddata = json.dumps(data).encode("utf-8")
        #     self.start_page(200)
        #     self.send_header('Content-type', 'application/json')
        #     self.end_headers()
        #     self.wfile.write(senddata)
                
        elif self.path.startswith("/blend/"):

            filename = self.path[6:]
            fullfilename = PROJECT+filename

           
            if os.path.exists(fullfilename):
                try:
                    linked = subprocess.check_output([blender, "-b", fullfilename, "-P", os.getcwd()+"/network/get_linked_files.py"]).decode("utf-8")
                except:
                    linked = ""

                linked = linked[linked.find("!START_DATA!")+13:linked.rfind("!END_DATA!")]

                linked = linked.split("\n")
                while "" in linked:
                    linked.remove("")

                parsed = []
                for i in linked:

                    # This is a little weird, sometimes the files have the full URL
                    # to the data.
                    
                    if i.startswith(PROJECT):               # This is good when the server is on the same machine as the orignal project
                        parsed.append(i[len(PROJECT):])

                    elif i.startswith(ORIGINAL_PROJECT): # This is when the server is a mirror
                        parsed.append(i[len(ORIGINAL_PROJECT):])
                    
                    else:
                        backward =  i.count("/..")
                        foldername = filename[:filename.rfind("/")]
                        f = foldername
                        for g in range(backward):
                            f = f[:f.rfind("/")]

                        cleanname = f+i.replace("//..", "").replace("/..", "").replace( "//", "/")
                        parsed.append(cleanname)


                data = {"files":{}}
                for f in parsed:
                    try:
                        fd = fileinfo(PROJECT+"/"+f)
                        data["files"][f] = fd
                    except Exception as e:
                        print(e)
                        

                linked = json.dumps(data)
                    
                self.start_page(200)
                self.send_header('Content-type', 'application/json')
                self.end_headers()
                self.wfile.write(linked.encode("utf-8"))

            else:
                self.start_page(404)
                self.wfile.write(b"File: "+filename.encode("utf-8")+b" doesn't exist on server.")
            
        elif self.path.startswith("/download/"):

            filename = self.path[9:]
            fullfilename = PROJECT+filename

            
            
            if os.path.exists(fullfilename):
                self.start_page(200)
                self.send_header('Content-type', mimetypes.guess_type(filename))
                self.end_headers()
                f = open(fullfilename, "rb")
                f = f.read()
                self.wfile.write(f)
            else:
                self.start_page(404)
                self.wfile.write(b"File: "+filename.encode("utf-8")+b" doesn't exist")
            
        elif self.path.startswith("/download_z/"):

            filename = self.path[11:]
            fullfilename = PROJECT+filename

            
            
            if os.path.exists(fullfilename):
                self.start_page(200)
                self.send_header('Content-type', mimetypes.guess_type(filename))

                f = open(fullfilename, "rb")
                f = f.read()
                z = zlib.compress(f)

                self.send_header('Content-length', len(z))
                self.end_headers()
                
                self.wfile.write(z)
            else:
                self.start_page(404)
                self.wfile.write(b"File: "+filename.encode("utf-8")+b" doesn't exist")
            
            
try:
    PORT = int(sys.argv[1])
except:
    print("Please specify a port number and then project folder.")
    exit()

serve = HTTPServer(("", PORT), handler)

serve.serve_forever()