# THIS FILE IS A PART OF VCStudio
# PYTHON 3

##############################################################################

 # Not all users have the ability or the desire to run a complex Graphical UI
 # to do simple tasks in the project. For example Windows users have no ability
 # to run Gtk applications in general. Even tho I dislike Window and do not 
 # condone the use of it. I don't want to make VCStudio completilly unusable
 # for them. For example let's say somebody will distribute a story.vcss file.
 # I want to give Windows users at least the ability to read the text of the
 # scene.
 
 # Also the console mode could be used for the rendering servers of big 
 # studios. Where running a GUI is just not practical. They usually have a
 # terminal only installation. And so some kind of way of working with project
 # should be possible from the terminal.

##############################################################################


import os
import re
import datetime
import threading

# Let's get a terminal size for prettier rendering.

try:
    w, h = os.get_terminal_size() 
except:
    w, h, = 50,50

from settings import settings
from settings import talk
from settings import oscalls
from project_manager import pm_project
from project_manager import pm_console

# Studio
from studio import analytics
from studio import story
from studio import studio_storyDeletionLayer
from studio import studio_storyLayer
from studio import studio_settingsLayer
from studio import studio_assetLayer
from studio import studio_analyticsLayer
from studio import studio_scriptLayer
from studio import studio_multiuserLayer

# UI modules
from UI import UI_testing
from UI import UI_color
from UI import UI_elements

# Network
from network import network_renders
from network import network_multiuser
from network import multiuser_terminal



commands1 = [
"help",#              - returns this help
"asset",#             - choose and asset
"assets",#            - list existsing assets
"scene",#             - read a scene
"scenes",#            - lists available scenes
"scenes_main_chain",# - list only scenes from the main chain
"shot",#              - choose a shot
"shots",#             - list shots of a given scene
"file",#              - open a file from a given asset or shot
"files",#             - list all files from a given asset or shot
"multiuser_start",#   - starts multiuser server for this project
"multiuser_stop",#    - stops multiuser
"multiuser_users",#   - list of users connected to multiuser
"multiuser_message",# - message users on multiuser
"vse",#               - starts a vse file
"vses",#              - lists all vse files
"render",#            - render a given file from a shot
"render_server",#     - become a render server for users on multiuser
"render_not_server",# - stop being a render server for users
"eval",             # - run a python expression
"exit"

]


pm_console.commands = commands1.copy()


def cls():
    #cleaning the terminal
    os.system("clear")
    
    
class make_win:
    
    # In order to make it work with all the standard functions build for the GUI
    # experience. Like export, multiuser and such. Yes multiuser will be supported
    # here fully. We have to be able to access the win.<anything> object. BUT
    # there is a rub. The win object is not really accesable from non Gtk system.
    
    # Because I had this genious idea to use already created Gtk.Window and just
    # add a bunch stuff to it in order to have a kind of global dictionary thing.
    
    def __init__(self, project):
        
        self.project = project

def previous(win):
    win.previous = {}
    for i in win.current:
        if type(win.current[i]) == list or type(win.current[i]) is dict:
            win.previous[i] = win.current[i].copy()
        else:
            win.previous[i] = win.current[i]
    
    
def run(project):
    
    
    win = make_win(project)
    
    # Setting up the global variables. (kinda)
    win.animations = {}
    win.previous   = {}
    win.current    = {}
    win.images     = {}
    win.imageload  = 0
    win.text       = {}
    win.textactive = ""
    win.scroll     = {}
    win.FPS        = 0
    win.url        = "story_editor"
    win.cur        = ""  # This will be used to get precicelly what asset / scene / shot we are in
    win.update     = {"versions":{}}
    win.project    = project
    win.out_dots  = {}
    win.assets    = {}
    win.szone     = [[100,100],[100,100]] # Square drawn if selected more then one node.
    win.surround  = {  # And this is the list of the squares. Because it's not
        "frame":0,     # as easy to do. See UI / UI_math / rectangle_surround()
        "rects":[]     # for details of this implementation.
        }
    win.calllayer = False
    win.layercashe = {} # Here I gonna store layers that are inactive to speed up stuff
    win.checklists = {}
    win.blink = False  # Cursor blinking thing. 
    win.renders = {} # List of current active renders.
    win.undo_history = []
    win.undo_index = 0
    win.multiuser = {
        "server":False,     # Whether we are connected to the server. And the server ID
        "userid":"",        # The id of current user in the server
        "last_request": "", # The last request send to the server. ( for stopping bloat )
        "curs":{},          # The information about various items on other users machines.
        "request":[["story"]],       # Requests done in UI space
        "users":{},         # List of users information Names, IPs etc.
        "messages":[],      # List of messages
        "unread":0   ,      # Amount of unread messages
        "terminal":[],      # The outputs from the server
        "asset_list_check":False,    # Whether the initial update happened when connecting to the server
        "story_check":False, # Whether the first story check was done.
        "analytics_check":False
        }
    
    if pm_project.is_legacy(project):
        win.story        = story.get_legacy(project)
        win.analytics    = analytics.get_legacy(project)
    else:
        win.story        = story.load(project)
        win.analytics    = analytics.load(project)
    
    # Cashed tables
    win.color    = UI_color.get_table()
    win.settings = settings.load_all()
    
    # Default values
    win.current["frame"]      = 0
    win.current["testing"]    = False
    win.current["LMB"]        = False
    win.current["MMB"]        = False
    win.current["RMB"]        = False
    win.current["keys"]       = []
    win.current["key_letter"] = ""
    win.current["scroll"]     = [0,0]
    win.current["project"]    = ""
    win.current["tool"]       = "selection"
    win.current["draw_dot"]   = "end"
    win.current["calls"]      = {}   # Calls. See sutdio/studio_dialogs.py
    win.current["script_find"] = [0,0]
    win.current["camera_arrived"] = False
    
    if "pointers" not in win.story:
        win.story["pointers"] = {} # List of text pointers per scene
    
    new_date_format = "%Y/%m/%d"
    today = datetime.datetime.strftime(datetime.datetime.today(), new_date_format)
    win.current["date"] = today # Don't even ask. I'm litteraly tired already.
    
    previous(win)
    
    # Version of the software
    win.version = 0.0
    try:
        vfile = open("settings/update.data")
        vfile = vfile.read()
        vfile = vfile.split("\n")
        
        for line in vfile:
            if line.startswith("VERSION "):
                win.version = float(line.replace("VERSION ", ""))
                break
    except:
        win.version = 0.0
        
    # FPS
    win.sFPS = datetime.datetime.now()
    
        
    
    cls()
    
    
    # The title thing in the top
    
    print("\033[1;33m\n "+win.analytics["name"]+"")
    print("\033[1;33m "+win.analytics["director"]+"")
    print("\033[1;33m "+win.analytics["status"]+" \n")
    progress_bar(win.analytics["fraction"])
    print()
    
    
    while True:
        
        # making sure Tab is doing autocomlete to the right functions

        pm_console.commands = commands1.copy()
        
        command = input("\033[1;35m : \033[1;m")
        
        ##############
        
        if command == "exit":
            cls()
            exit()
    
        ###### HELP ######
        elif command == "help":
            
            print("\033[1;32m"+talk.text("sc_help")+"\n")
        
        ##### ASSETS LIST ####
        
        elif command == "assets":
            for asset in network_multiuser.list_all_assets(win):
                print("\033[1;35m "+asset)
        
        ##### ASSET ACCESS #####
        
        elif command == "asset":
            
            pm_console.commands = pm_project.get_list()
            
            n = input("\033[1;33m : ")
            
            if os.path.exists(win.project+"/dev"+n) and n.count("/") == 2:
                
                win.cur = n
                
                t, cur, name = n.split("/")
                
                print("\033[1;33m\n "+talk.text(cur)+": "+name)
                progress_bar(story.get_asset_data(win, n)["fraction"])
                print()
                
                
            else:
                print("\033[1;31m"+talk.text("failed"))
        
        #### SCENES LIST ####
            
        elif command == "scenes":
            for scene in win.story["scenes"]:
                print("\033[1;35m "+scene)
        
        #### SCENES MAIN CHAIN LIST ####
        
        elif command == "scenes_main_chain":
            lastarrow = 'start'
            for i in win.story["arrows"]:
                if lastarrow == "end":
                    break
                for arrow in win.story["arrows"]:
                    if arrow[0] == lastarrow:
                        lastarrow = arrow[1]
                        if arrow[1] != "end":
                            print("\033[1;35m "+arrow[1][1])
        
        ##### READ SCENE TEXT #####
        
        elif command == "scene":
            
            pm_console.commands = list(win.story["scenes"].keys())
            
            n = input("\033[1;33m : ")
            
            
            
            if n in win.story["scenes"]:
                win.cur = "/"+n
                
                
                
                # I want to have the full scene written to the terminal at this
                # point. Good that most terminals already support tiling. I don't
                # need to care about that. So let's do that.
                
                scene = win.story["scenes"][n]["shots"]
                
                buf = "\033[1;0m"
                lines = 0
                
                for block in scene:
                        
                        
                        # For just text parts.
                        if block[0] == "text_block":
                            style = "\033[1;40m"
                        else:
                            
                            # If It's a shot. I want the shot color marking
                            
                            shotis = block[1]
                            
                            rcolors = {
                                "shot_1":"\033[1;41m",
                                "shot_2":"\033[1;43m",
                                "shot_3":"\033[1;46m",
                                "shot_4":"\033[1;44m",
                                "shot_5":"\033[1;42m"
                                }
                        
                            # Getting the color. It's not always works.
                            
                            if "shot_colors" not in win.story:
                                win.story["shot_colors"] = {}
                            
                            surl = "/"+n+"/"+shotis
                            
                            if surl not in win.story["shot_colors"]:
                             
                                win.story["shot_colors"][surl] = list(rcolors.keys())[len(win.story["shot_colors"]) % len(rcolors)]
                            
                            style = rcolors[win.story["shot_colors"][surl]]
                            
                        for text in block[-1]:
                        
                            # For just regular parts we have our regular text
                            
                            if text[0] == "text" or text[0] == "link":
                                
                                for line in re.split("(\n)",text[-1]):
                                    
                                    if line == "\n":
                                        
                                        while buf: 
                                            print(buf[:w])
                                            buf = buf[w:] 
                                            lines = lines + 1
                                            if lines + 8 > h:
                                                input("... "+talk.text("press_to_continue")+" ...")
                                                lines = 0
                                            
                                        buf = "\033[1;0m"
                                    
                                    else:
                                        
                                        if text[0] == "text":
                                            buf = buf + style + line + "\033[1;0m"
                                        else:
                                            buf = buf + "\033[1;45m" + line + "\033[1;0m"
                
                            elif text[0] == "frase":
                                
                                while buf: 
                                    print(buf[:w])
                                    buf = buf[w:] 
                                    lines = lines + 1
                                    if lines + 8 > h:
                                        input("... "+talk.text("press_to_continue")+" ...")
                                        lines = 0
                                buf = "\033[1;0m"
                                
                                if text[1][0] == "text":
                                    print(" "*int(w/2-len(text[1][-1])/2)+"\033[1;40m"+text[1][-1])
                                else:
                                    print(" "*int(w/2-len(text[1][-1])/2)+"\033[1;45m"+text[1][-1]+"\033[1;40m")
                                    
                                
                                for line in re.split("(\n)",text[-1]):
                                    if line == "\n":
                                        print(line)
                                    
                                    else:
                                        while line:
                                            print(" "*int(w/3)+style+line[:int(w/3)])
                                            line = line[int(w/3):]
                                            lines = lines + 1
                                            if lines + 8 > h:
                                                input("... "+talk.text("press_to_continue")+" ...")
                                                lines = 0
                
                while buf: 
                    print(buf[:w])
                    buf = buf[w:] 
                    lines = lines + 1
                    if lines + 8 > h:
                        input("... "+talk.text("press_to_continue")+" ...")
                        lines = 0
                 
                print()
                print("\033[1;33m\n "+n)
                progress_bar(win.story["scenes"][n]["fraction"])
                print()
                        
            else:
                print("\033[1;31m"+talk.text("failed"))
            
        
        ### FILES ###
        
        elif command == "files":
            
            prefix = "/rnd"
            for i in ["/chr", "/veh", "/obj","/loc"]:
                if win.cur.startswith(i):
                    prefix = "/dev"
            
            for i in network_multiuser.get_give_folder_list(win.project, prefix+win.cur):
                print("\033[1;35m "+i[0])
        
        elif command == "file":
            n = input("\033[1;33m : ")
            oscalls.Open(win.project+n)
        
        ### EVAL ###
        
        elif command == "eval":
            n = input("\033[1;33m : ")
            try:
                print("\033[1;33m"+str(eval(n)))
            except Exception as e:
                print("\033[1;31m"+talk.text("failed")+" : "+str(e))
        
        
        #### NOT IMPLEMENTED YET ####
        
        elif command in pm_console.commands:
            print("\033[1;31m"+talk.text("failed")+" : Not Implemented Yet")
        
            
        ## FAIL ##
        
        elif command != "":
            print("\033[1;31m"+talk.text("failed"))
    
    
    
def progress_bar(f):

    # This function will print out a progress bar similar to
    
    # [ ############################.................................. ]
    
    bw = w-6
    pw = int(round(bw*f))
    lw = bw - pw
    
    print(" [ "+"#"*pw+"."*lw+" ] ")