# THIS FILE IS A PART OF VCStudio
# PYTHON 3

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

# This file here will act like simple set of functions for the developer of the
# software. But infect will be a little more complex behimith. To explain the 
# idea we need to look a little bit deeper into how this program functions and
# draws UI peaces. 

# Basically every Layer py file is a set of instuction of how to draw a specific
# UI on to the screen. Those function return the finished canvas. An image
# basically. That the compositing layer (studio_gtk.py or pm_gtk.py ) combine
# into a bigger picture.

# There is a blur effect added to undernith layers if the top layer is drawn. 
# I do this by checking the win.url string. Each layer has they own urls. 
# Some are composited at all times. Some only if their url is the url. But all
# get blurred if it's not their url.

# Unfortunatly I can't make a function that will return a value. Because it means
# to stop the drawing of the UI. And I need the UI to get to next frame in order
# to draw the function's UI. 

# Let's say I want to add a link to an image to the story-editor. I click on the
# add button. Next what I want to see is a searcher dialog appear. As soon as I
# have selected the image I want to link, then the new link appears in the story
# editor space which is automatically moving. Untill I place it.

# For this I need to set up some kind of variable. And as soon as this variable
# is not None. For example. We are doing the rest of the operation. 


# Step 0 : User Clicks the add button. And a funtion is called.
# Step 1 : This function creates a dictionary with a variable NONE and a callable
# Step 2 : win.url changes to the Layer which is the searcher.
# Step 3 : User selects the images, or a file that he or she wanted to select.
# Step 4 : This filename is being written into the variable that used to be NONE.
# Step 5 : As soon as this variable is not NONE the callable is called.
# Step 6 : This callable is the one that does the setup work. 

# Of course it would defeat the purpose if the callable always standard. It shold
# be one of the inputs to the dialogue function. 

# Function template function_name(win, operation_name, callable):

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

import os
import time
import threading

# GTK module ( Graphical interface
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import GLib
from gi.repository import Gdk
import cairo

# Own modules
from settings import settings
from settings import talk
from project_manager import pm_project

from studio import analytics
from studio import studio_nodes

#UI modules
from UI import UI_elements
from UI import UI_color

###################################################   ########################
                                                  #   #                      #
from studio  import studio_file_selectLayer       #   #   These modules he-  #
from studio  import studio_asset_selectLayer      #   #   re. Are the modu-  #
from studio  import studio_shot_linkLayer         #   #   les that are ac-   #
from studio  import studio_asset_configureLayer   #   #   tual UI of dialo-  #
from studio  import studio_renderLayer            #   #   gs that I was ta-  #
from studio  import studio_vseLayer               #   #   lking about at     #
from UI      import UI_helpDialog                 #   #   the top.           #
from network import http_client                   #   #                      #
                                                  #   #                      #
###################################################   ########################

#      ^
#      |

# Who does that?

def file_select(win, name, call, force=False, IMAGE=True, BLEND=False, VIDEO=True,
    FILE=False, CHR=True, VEH=True, LOC=True, OBJ=True, RND=False, FOLDER=False,
    SEARCH=""):


    # Forcing reload of the fileswin.current["AllFiles"] = []
                                
    try:        
        del win.current["AllFiles"] 
    except:
        pass
    
    # This function will select files for any kind of stuff. It will search
    # through the files of the project. Similar to image searcher in the old
    # organizer. 
    if name not in win.current["calls"]:
        win.current["calls"][name] = {
            "var" :None,   # This is the variable that we are waiting for
            "call":call,   # This is what it's going to run when it's done
            "url" :"file_select",
            "back":win.url,# This is where it's going to come back when it's done
            "draw":studio_file_selectLayer.layer
            }
    
    # Now let's make a container to save those setting between frames
    
    if force or "file_selector" not in win.current:
        
        win.current["file_selector"] = {
            "image"  :IMAGE,
            "blender":BLEND,
            "video"  :VIDEO,
            "file"   :FILE,
            "chr"    :CHR,
            "veh"    :VEH,
            "loc"    :LOC,
            "obj"    :OBJ,
            "vse"    :RND,
            "folder" :FOLDER
            }
    
    # Search text
    
    win.text["file_select_search"] = {
        "text"  :SEARCH,  # Actuall text you are editing.
        "cursor":[len(str(SEARCH)),len(str(SEARCH))], # Cursor
        "insert":False, # Whether the insert mode is on
        "scroll":"file_select_search_scroll" # If multiline. The pointer for the scroll value.
        }
     
    # Let's activate the text so you could type immediatly 
    win.textactive = "file_select_search"
    
    # Let's clear the LMB just in case
    win.previous["LMB"] = False
    
def asset_select(win, name, call, force=False, cur="chr", SEARCH=""):
    
    # This function will be an asset selector. The idea it to be something
    # in between itemselector and assets in the same time. 
    
    # If you remember
    # in the Blender-Organizer there were tabs on the top bar. If you click
    # on Characters let's say, you would get a full screen selector to enter
    # a given character.
    
    # But for linking and such you would get a small window with only names.
    # But with a search dialog. 
    
    # Well this dialog will be some kind a merge of both of them. Having both
    # a very good cell-based preview type list and search. And could be used
    # not only to enter the asset, but also for linking and such.
    
    if name not in win.current["calls"]:
        win.current["calls"][name] = {
            "var" :None,   # This is the variable that we are waiting for
            "call":call,   # This is what it's going to run when it's done
            "url" :"asset_select",
            "back":win.url,# This is where it's going to come back when it's done
            "draw":studio_asset_selectLayer.layer
            }
    
    # Now let's make a container to save those setting between frames
    
    if force or "asset_cur" not in win.current:
        
        win.current["asset_cur"] = cur
    
    # Search text
    
    win.text["asset_select_search"] = {
        "text"  :SEARCH,  # Actuall text you are editing.
        "cursor":[len(str(SEARCH)),len(str(SEARCH))], # Cursor
        "insert":False, # Whether the insert mode is on
        "scroll":"asset_select_search_scroll" # If multiline. The pointer for the scroll value.
        }
     
    # Let's activate the text so you could type immediatly 
    win.textactive = "asset_select_search"
    
    # Wiping the history of the assets. See studio/studio_asset_selectLayer.py
    win.assets = {}
    
    # Let's clear the LMB just in case
    win.previous["LMB"] = False

def asset_link(win, name, call, filename, force=False):
    
    # This function will configure the linking of the assets into animation files
    # it's in theory a quite simple operation, but requires nesting of dialogs.
    # which is untested by the time I'm writting this comment.
    
    if name not in win.current["calls"]:
        win.current["calls"][name] = {
            "var" :None,   # This is the variable that we are waiting for
            "call":call,   # This is what it's going to run when it's done
            "url" :"asset_link",
            "back":win.url,# This is where it's going to come back when it's done
            "draw":studio_shot_linkLayer.layer
            }
    
    # let's prepare the data for this operation
    
    if force or "linking_asset_data" not in win.current\
    or win.current["linking_asset_data"]["linking_to"] != filename:
        win.current["linking_asset_data"] = {
            "linking_to":filename,
            "assets":[],
            "read":False,
            "selected":"",
            "mode":"link",
            "fraction":0,
            "process":False
            }
    if win.current["linking_asset_data"]["fraction"]:
        win.current["linking_asset_data"]["assets"] = []
        win.current["linking_asset_data"]["fraction"] = 0
    
    # Wiping the history of the assets. See studio/studio_asset_selectLayer.py
    win.assets = {}
    
    # Let's clear the LMB just in case
    win.previous["LMB"] = False
    
def asset_configure(win, name, call, asset, force=False):
    
    # This function going to configure assets. More deatailed explanation is
    # in the file: studio/studio_asset_configureLayer.py
    
    if name not in win.current["calls"]:
        win.current["calls"][name] = {
            "var" :None,   # This is the variable that we are waiting for
            "call":call,   # This is what it's going to run when it's done
            "url" :"asset_configure",
            "back":win.url,# This is where it's going to come back when it's done
            "draw":studio_asset_configureLayer.layer
            }
    
    # let's prepare the data for this operation
    
    if force or "asset_configure" not in win.current\
    or win.current["asset_configure"]["asset"] != asset:
        win.current["asset_configure"] = {
            "asset":asset,
            "blend_to_copy":"",
            "collections":{},
            "step3_button":"collection",
            "apply":False
            }
    
    
    # Wiping the history of the assets. See studio/studio_asset_selectLayer.py
    win.assets = {}
    
    # Let's clear the LMB just in case
    win.previous["LMB"] = False
    
def render(win, name, call, filename="", force=False):
    
    # This function going to launch a window that shows all current renders and
    # confuge them. 
    
    if name not in win.current["calls"]:
        win.current["calls"][name] = {
            "var" :None,   # This is the variable that we are waiting for
            "call":call,   # This is what it's going to run when it's done
            "url" :"render",
            "back":win.url,# This is where it's going to come back when it's done
            "draw":studio_renderLayer.layer
            }
    
    # let's prepare the data for this operation
    
    if force or "renders_window" not in win.current\
    or win.current["renders_window"]["filename"] != filename:
        win.current["renders_window"] = {
            "filename":filename
            }
    
    
    # Wiping the history of the assets. See studio/studio_asset_selectLayer.py
    win.assets = {}
    
    # Let's clear the LMB just in case
    win.previous["LMB"] = False

def vse(win, name, call, filename="", force=False):
    
    # This function going to select vse blend files. 
    
    if name not in win.current["calls"]:
        win.current["calls"][name] = {
            "var" :None,   # This is the variable that we are waiting for
            "call":call,   # This is what it's going to run when it's done
            "url" :"vse",
            "back":win.url,# This is where it's going to come back when it's done
            "draw":studio_vseLayer.layer
            }
    
    # Let's clear the LMB just in case
    win.previous["LMB"] = False
    
def help(win, name, call, filename="", force=False, SEARCH=""):
    
    # This function going to select vse blend files. 
    
    if name not in win.current["calls"]:
        win.current["calls"][name] = {
            "var" :None,   # This is the variable that we are waiting for
            "call":call,   # This is what it's going to run when it's done
            "url" :"help",
            "back":win.url,# This is where it's going to come back when it's done
            "draw":UI_helpDialog.layer
            }
    
    # Let's clear the LMB just in case
    win.previous["LMB"] = False
    
    win.text["in_help"] = {
        "text"  :SEARCH,  # Actuall text you are editing.
        "cursor":[len(str(SEARCH)),len(str(SEARCH))], # Cursor
        "insert":False, # Whether the insert mode is on
        "scroll":"in_help_search_scroll" # If multiline. The pointer for the scroll value.
        }

    
def http_client_dialog(win, name, call, function, args=""):
    
    # This function is going to be the UI for http-client. 
    
    if name not in win.current["calls"]:
        win.current["calls"][name] = {
            "var" :None,   # This is the variable that we are waiting for
            "call":call,   # This is what it's going to run when it's done
            "url" :"http-server",
            "back":win.url,# This is where it's going to come back when it's done
            "draw":http_client.layer
            }
    
    # Let's clear the LMB just in case
    win.previous["LMB"] = False

    
    # Some variables to pass so the function.
    win.current["http-server"] = {
        "args"    :args,      # arguments to the function
        "progress":0,         # progress of that function
        "fileprog":0,         # progress for a file download
        "call"    :name,      # The call to stop the process
        "message" :"",        # message about the progress
        "started" :time.time()# current time ( to calculate progress completion )
    }

    # Let's now run the function 
    function_run = threading.Thread(target=function, args=(win,))
    function_run.setDaemon(True)
    function_run.start()

def http_client_update_prompt(win, name, call):
    
    # This function is going to be the UI for http-client. 
    
    if name not in win.current["calls"]:
        win.current["calls"][name] = {
            "var" :None,   # This is the variable that we are waiting for
            "call":call,   # This is what it's going to run when it's done
            "url" :"http-server-prompt",
            "back":win.url,# This is where it's going to come back when it's done
            "draw":http_client.prompt_layer
            }
    
    # Let's clear the LMB just in case
    win.previous["LMB"] = False

