# Part of VCStudio
# GPLv3 or later

# This file will visualize the rendering process

import os
import sys
import json
import time

if len(sys.argv) == 1:
    project = input("Project: ")
else:
    project = sys.argv[1]

def get_runtime_data(project):

    # This will read a specific .json file from the system.

    template = {"to_render":True,
                "current_progress":"Fra: 69 | Mem: 420 |Sample: 69/420"}
    try:
        with open(project+"/render_runtime.json") as json_file: 
            data = json.load(json_file)
    except:
        data = template.copy()

    return data

def save_runtime_data(data, project):
    with open(project+"/render_runtime.json", 'w') as fp:
        json.dump(data, fp, indent=4)


# 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
}

# A function that insures a specific width of the printed part
def wdth(x, n):

    # Convert Data to String
    mode = "normal"
    if type(x) == bool and x == True:
        x = "V"
        mode = "bdgr"
    elif type(x) == bool and x == False:
        x = "X"
        mode = "bdrd"
    else:
        x = str(x)

    # Turn emogis
    #x = emote(x)

    # Some characters are too wide. They do not obey the
    # monospace of the terminal, thus making it not pretty.

    # This is the string of characters which are checked to
    good = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&'’()*+,-./:;<=>?@[\]^_`{|}~ йцукенгшщзхъфывапролджэячсмитьбюЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮёЁ"

    # let's filter the string
    y = x
    
    
    x = ""
    for i in y:
        if i in good:
            x = x + i
        else:
            x = x + "▓"

    # Now let's print what we've got.
    if len(y) < n:
        fac = n-len(y)
        fac1 = int(round(fac/2))
        fac2 = fac1
        while fac1 + fac2 > fac:
            fac2 -=1
        while fac1 + fac2 < fac:
            fac2 +=1
        x = (" "*fac1)+x+(" "*fac2)
    elif len(y) > n:
        if n > 10:
            x = x[:n-3]+"..."
        else:
            x = x[:n]
    if mode == "normal":
        return x
    else:
        return clr[mode]+clr["bold"]+x+clr["norm"]

def tsize():

    # This funtion will get the size of the terminal and
    # return it to the variables provided width, height

    # On some systems this may not work. So there is a
    # try function.

    try:
        # Getting the size of the terminal
        import os
        w, h = os.get_terminal_size()

        # Sometimes when the terminal width is either
        # even or odd. It breaks code for some other
        # thing written differenly. For example:

        # You may have an even width ( like 84 ) when
        # writing a function. And then it works on different
        # widths as well like 62 and 80 and 48. All of them
        # are still even. Then you scale the terminal to be
        # something off like 63 and the function breaks. You
        # have one character too much or one character too little.

        # This is why I do not want to have a difference. And
        # force width to be one less, if it's not divisible by 2.

        if not w % 2:
            w = w - 1

        return w, h

    except:

        # If, by any reason the terminal can't get it's size.
        # We want to return some size regardless.

        w = 60
        h = 20

        return w, h

    
def table(data, number=True):

    # This function will present data in a pretty table thing.

    # So let's first of all get the size of the terminal
    w, h = tsize()

    if number:
        w = w - 4

    # Then let's draw the categories for this we need to extract
    # it's sizes. If there is no 'size' variable the sizes of
    # each category will be spread equally.

    size = [] # Here the size will go as pure character value.

    if "size" in data:
        for i in data["size"]:
            size.append(int(( w - 10 ) / sum(data["size"]) * i))

    while sum(size) < w - 10:
        size[-1] += 1

    # printing categories
    nb = ""
    if number:
        nb = "    "
    s = "    "+clr["bdma"]+" "+clr["tbwh"]+nb

    for n, item in enumerate(data["categories"]):
        s = s + wdth(item.upper(), size[n])
    print(s+clr["bdma"]+" "+clr["norm"])

    size[-1] += 1

    # printing items
    for b, i in enumerate(data["data"]):

        # dark bright sequence thingy
        if b % 2:
            d = "b"
        else:
            d = "d"
        nb = ""
        if number:
            nb = clr["tbwh"]+wdth(b,4)
        s = "    "+clr["bdma"]+" "+nb+clr["norm"]+clr["b"+d+"bu"]#+clr["tbwh"]
        for n, item in enumerate(i):
            s = s +clr["b"+d+"bu"]+ clr["tbwh"]+wdth(item, size[n]-1)+clr["bdma"]+" "
        print(s+clr["norm"])

def center(line, c="bdma", blink=False):

    # This funtiocn will bring a given string of text
    # in the center of the terminal with a nice backgroud
    # around it.


    w, h = tsize()

    if blink:
        blink = clr["blnk"]
    else:
        blink = ""

    if len(line) % 2:
        line = line + " "

    if len(line) < w - 11:
        print("    "+clr[c],
          wdth(" ", int((w-10)/2 - (len(line)/2))),
          clr["bold"]+clr["tbwh"]+blink+line,
          wdth(" ", int((w-10)/2 - (len(line)/2))-1),
          clr["norm"])
    else:
        print("    "+clr[c],
              clr["bold"]+clr["tbwh"]+blink+wdth(line,w-10),
          clr["norm"])

running_for = 0
lastframe = 0
maxtime = 1000000
        
while True:

    running_for = running_for + 1

    runtime = get_runtime_data(project)
    if not runtime.get("to_render"):
        break
    
    x,y = tsize()

    if y > 8:
        print("\n\n")

    process = runtime.get("current_progress", "").split(" | ")
    try:
        del runtime["current_progress"]
    except:
        pass

    data_print = {"categories":list(runtime.keys()),
                          "size":[1]*(len(runtime)),
                          "data":[list(runtime.values())]}

    table(data_print, False)
    
    data_print = {"categories":[""]*(len(process)),
                          "size":[1]*(len(process)),
                          "data":[process]}

        
    
            
    table(data_print, False)
    center("")


    # Latest frames data

    filename = runtime.get("current_file", "")
    folder = filename[:filename.rfind("/")]+"/extra"
    savefile = folder+filename[filename.rfind("/"):]+".json"
    
    try:
        with open(project+savefile) as json_file: 
            data = json.load(json_file)
    except:
        data = {}

    listoftimesx = data.get("analytics", {}).get(data.get("save_folder", ""), [])
    listoftimes = {}
    minframe = data.get("start_frame", 0)
    for i in listoftimesx:
        try:
            listoftimes[int(i)] = listoftimesx[i]
        except:
            pass
    try:
        maxframe = max(list(listoftimes.keys()))
    
        
    
        if maxframe > lastframe:
            lastframe = maxframe
            running_for = 0
        maxtime  = max(list(listoftimes.values()))
        maxtime = max(maxtime, running_for*1000000)

        print()


        for i in range(max(minframe,maxframe-y+16), maxframe+1):
            
            amount = int((x-14)/(maxtime-minframe)*(listoftimes[i]-minframe))
        
        
            print("    ",wdth(i, 4), "▒"*amount)
    except Exception as e:
        #print(e)
        maxframe = 0
        #maxtime = 1
        lastframe = maxframe
        running_for = 0

    amount = int((x-14)/maxtime*running_for*1000000)
        
    print("    " , wdth(maxframe+1, 4), "█"*amount)

    
    amount = int((x-14)/(data.get("end_frame", maxframe+1)-minframe)*(maxframe+1-minframe))

    print()
    print("     "+clr["tbma"]+wdth(data.get("end_frame", maxframe+1), 4)+" "+("█"*amount)+clr["norm"])
    
    time.sleep(1)
    os.system("clear")
