# THIS FILE IS A PART OF VCStudio
# PYTHON 3



import os
from subprocess import *

# 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 oscalls
from settings import talk
from settings import fileformats
from project_manager import pm_project

#UI modules
from UI import UI_elements
from UI import UI_color

# story
from studio import story
from studio import analytics
from studio import history
from studio import studio_dialogs
from studio import history

def link_from_script(win):
    
    #########################################################################
    
    # This file is here because there are multiple places in the window where
    # I want to link assets based on what's written in the text of the script.
    
    # So this file will basically parse the text and add the assets it finds
    # linked to the link list.
    
    #########################################################################
    
    print("Reading from the scene")
    
    # Fist we need to know what scene and shot are we.
    
    if win.cur.count("/") > 1:
        tmp = win.cur.replace("/","",1).split("/")
        scene, shotis  = tmp[0], tmp[1]
    else:
        scene = win.cur[win.cur.rfind("/")+1:]
        shotis  = ""
    
    print(scene, shotis)
    
    # Now let's read through the scene.
    
    for shot in win.story["scenes"][scene]["shots"]:
        
        
        # Ignore the non shots.
        if shot[0] != "shot_block":
            continue
        
        # Ingore all other shots.
        if shot[1] != shotis:
            continue
        
        # Let's read the shot
        for asset in shot[-1]:
            # Ignore text
            if asset[0] == "text":
                continue
            
            # It's it's a staight up link. Just add it.
            if asset[0] == "link" and "/dev"+asset[1] not in win.current["linking_asset_data"]["assets"]:
                win.current["linking_asset_data"]["assets"].append("/dev"+asset[1])
            
            # It's a link in a frase. 
            if asset[0] == "frase" and asset[1][0] == "link" and "/dev"+asset[1][1] not in win.current["linking_asset_data"]["assets"]:
                win.current["linking_asset_data"]["assets"].append("/dev"+asset[1][1])
            
        
def layer(win, call):
    
    # Making the layer
    surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, win.current['w'],
                                                      win.current['h'])
    layer = cairo.Context(surface)
    
    
    #text setting
    layer.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
    
    UI_color.set(layer, win, "dark_overdrop")
    layer.rectangle(
        0,
        0,
        win.current["w"],
        win.current["h"],
        )
    layer.fill()
    
    
    
    UI_color.set(layer, win, "node_background")
    UI_elements.roundrect(layer, win, 
        40,
        40,
        win.current["w"]-80,
        win.current["h"]-80,
        10)
    
    
    ##############################################################################

    # This file is configuring and lanunching the linking into blend files. But it's
    # not the only file in the chain of files that is responsible for this operation.

    # For example the linking it self does studio/bpy_do_linking.py that is running
    # inside blender and communicates with this file for the UI side of things. 

    ##############################################################################
    
    # Okay
    if not win.current["linking_asset_data"]["fraction"]:
        def do():
            
            # Before we start let's record the history for it.
            
            history.record(win, win.project+win.current["linking_asset_data"]["linking_to"], "[Linked]")
            
            if not win.current["linking_asset_data"]["process"]:
            
                # So this is an apply button. I know it's a little not in the right
                # order. So please read the rest of the file to see what it does.
                
                # So now when a person clicks okay. We first need to save the 
                # autolink.data.
                
                datafile = open(win.project+"/rnd"+win.cur+"/extra/autolink.data", "w")
                for asset in win.current["linking_asset_data"]["assets"]:
                    datafile.write("Link : "+asset+"\n")
                
                # Also let's write the mode. Because it's important.
                datafile.write("Mode : "+win.current["linking_asset_data"]["mode"]+"\n")
                
                datafile.close()
                
                # Okay... now that we have the file. We can start the process of linking
                # Which will be done using Blender. So let's get blender's url
                
                blenderpath = oscalls.get_current_blender(win)
                
                # Now here is the fun part. We gonna start a background process
                # open there blender and will start linking stuff.
                
                win.current["linking_asset_data"]["process"] = Popen(['stdbuf', '-o0',  blenderpath, \
                "-b", win.project+win.current["linking_asset_data"]["linking_to"], \
                "-P", os.getcwd()+"/studio/bpy_do_linking.py"],\
                stdout=PIPE, universal_newlines=True)
                
                win.current["linking_asset_data"]["fraction"] = 0.01
                
                # Hell of a command isn't it. 
            
        UI_elements.roundrect(layer, win, 
            win.current["w"]-120,
            win.current["h"]-80,
            40,
            40,
            10,
            button=do,
            icon="ok",
            tip=talk.text("checked"),
            url="asset_link")
    
    # Documentation entry
    def do():
        def after(win, var):
           pass
        
        studio_dialogs.help(win, "help", after, SEARCH=talk.text("documentation_link_assets"))
    
    UI_elements.roundrect(layer, win,
        300,
        50, 
        40,
        40,
        10,
        do,
        "question")
    
    # CANCEl
    if not win.current["linking_asset_data"]["process"]:
        def do():
            if not win.current["linking_asset_data"]["process"]:
                win.current["calls"][call]["var"] = False 
                win.assets = {}
            
        UI_elements.roundrect(layer, win, 
            win.current["w"]-80,
            win.current["h"]-80,
            40,
            40,
            10,
            button=do,
            icon="cancel",
            tip=talk.text("cancel"),
            url="asset_link")
        
        # Short cut ESC
        if 65307 in win.current["keys"] and not win.textactive:
            do()    
    
     # Now let's prepare the ground for the next part. 
    
    
    
    # Before we do anything we need to make sure that there is an autolink.data
    # file in the extra folder of the shot. But since this is a system that is
    # designed to be very simple on the user side. There could not even be the
    # extra folder. So...
    
    try:
        os.mkdir(win.project+"/rnd"+win.cur+"/extra")
    except:
        pass
    
    # Next thing will be to see if there is a file called autolink.data. And if
    # yes read from it. We are going to load the data into the memory. 
    
    # So if there is nothing yet loaded let's try loading it from file. Try 
    # because there nothing quarantees that the file exists. If file does not
    # exists we gonna populate it with assets from the shot. As marked in the 
    # scene the user wrote. But it's going to be a separate function since I
    # want to make a button to do it.
    
    if not win.current["linking_asset_data"]["assets"] and not win.current["linking_asset_data"]["read"]:
        
        win.current["linking_asset_data"]["read"] = True
        
        try:
            datafile = open(win.project+"/rnd"+win.cur+"/extra/autolink.data")
            datafile = datafile.read()
            datafile = datafile.split("\n")
            
            for line in datafile:
                if line.startswith("Link : "):
                    asset = line[7:]
                    win.current["linking_asset_data"]["assets"].append(asset)
        except:
            
            # So if it fails to load the file. Probably because it's not created
            # yet. Let's load from the story. What's so bad about it?
            
            link_from_script(win)
    
    # Now keep in mind that to help the script that runs inside blender all
    # assets have /dev/ in their folder. So to reach /ast/ blend file we will
    # need to parse the link. It's not hard just reminding it here.
    
    
    # IK everything is all over the place in the file but...
    # If there is a process. We should be able to see what it does.
    # Draw like a litte progress bar and stuff
    
    if win.current["linking_asset_data"]["process"]:
        
        # Basically during the execution of the linking. I want to read the
        # output and give the user some feedback of what is going on.
        
        currentline = win.current["linking_asset_data"]["process"].stdout.readline()[:-1]
        
        # In the bpy_do_linking.py file there is an instruction to write
        # out a fraction of a current operation into terminal. Which is
        # piped into the VCStudio and I can read it. So we can use it
        # to draw a progress bar.
        
        if currentline.startswith("FRACTION:"):
            try:
                fraction = float(currentline.split(":")[1])
                win.current["linking_asset_data"]["fraction"] = fraction
            except:
                pass
        
        if currentline == "FINISHED":
            win.current["linking_asset_data"]["process"] = False
            win.current["linking_asset_data"]["fraction"] = 1
    
    
    # The prgoress bar:
    if win.current["linking_asset_data"]["fraction"]:
        fraction = win.current["linking_asset_data"]["fraction"]
        
        UI_color.set(layer, win, "progress_background")
        UI_elements.roundrect(layer, win,
            70,
            win.current["h"]-75, 
            (win.current["w"]-220),
            0,
            7)
        
        UI_color.set(layer, win, "progress_active")
        UI_elements.roundrect(layer, win,
            70,
            win.current["h"]-75, 
            (win.current["w"]-220)*fraction,
            0,
            7)
        
    
    # This file will fuel of nightmares. Okay. So while developping it I realzed
    # one little problem. Overrides are kind a still buggy. Tho it's good to 
    # have them for future releases. And most of rigs work just fine.
    
    # The thing that I want to do is to give the user options. Let's say their
    # rig is broken when trying Library- Overrides but it's okay if you do
    # legacy Proxy thing. So why not give the user the option of doing both.
    
    # And also sometimes you just want to link and decide later what you do with
    # your rig.
    
    # So I gonna make 3 icons. 3 modes so to speak. LINK, OVERRIDE, PROXY.
    
    linkoptions = {
        "link":"link_mode_link",
        "override":"link_mode_overrides", # Icon / Mode : Tooltip
        "proxy":"link_mode_proxy"
        }
    
    for num, mode in enumerate(linkoptions):
        
        if win.current["linking_asset_data"]["mode"] == mode:
            
            UI_color.set(layer, win, "progress_time")
            UI_elements.roundrect(layer, win,
                50+(40*num),
                50, 
                40,
                40,
                10)
        
        def do():
            win.current["linking_asset_data"]["mode"] = mode
        
        UI_elements.roundrect(layer, win,
            50+(40*num),
            50, 
            40,
            40,
            10,
            do,
            mode,
            tip=talk.text(linkoptions[mode]))
    
    # Let's add a button that adds assets based on what's written in the script.
    
    def do():
        link_from_script(win)
        
    UI_elements.roundrect(layer, win,
        200,
        50, 
        40,
        40,
        10,
        do,
        "scene_new",
        tip=talk.text("link_add_from_scene"))
    
    
    if not os.path.exists(win.project+win.current["linking_asset_data"]["selected"]+"/autolink.data")\
    or not os.path.exists(win.project+win.current["linking_asset_data"]["selected"].replace("/dev/","/ast/")+".blend"):
    
        def do():
        
            def after(win, var):
                print(var)
            
            studio_dialogs.asset_configure(win, "configuring_asset", after, 
                win.current["linking_asset_data"]["selected"].replace("/dev",""))
        
        UI_elements.roundrect(layer, win, 
            250,
            50,
            40,
            40,
            10,
            button=do,
            icon="link_configure")
    
    
    
    # That's it. Now we are clipping and drawing the assets them selves.

    UI_elements.roundrect(layer, win, 
        50,
        100,
        win.current["w"]-100,
        win.current["h"]-200,
        10,
        fill=False)
    layer.clip()
    
    tileX = 70
    current_Y = 0
    
    if "asset_link" not in win.scroll:
        win.scroll["asset_link"] = 0
    
    #############################
    
    # Let's draw the list of assets that the user chose.
    
    for num, asset in enumerate(win.current["linking_asset_data"]["assets"]):
        
        cur, name = asset.split("/")[2], asset.split("/")[3]
        
        if int(current_Y + win.scroll["asset_link"] + 100) in range(0-100, win.current["h"]):
                    
            # Making the layer
            nodesurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 170, 200)
            node = cairo.Context(nodesurface)
            node.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
            
            
            UI_elements.roundrect(node, win, 
                0,
                0,
                170,
                200,
                10,
                fill=False)
            
            node.clip()
            
            # Background
            UI_color.set(node, win, "dark_overdrop")
            node.rectangle(0,0,170, 200)
            node.fill()
            
            # Banner
            UI_color.set(node, win, "node_asset") 
            
            # Now the banner will be node_asset color if the asset is configured
            # but it could be not configured. Or not even have the asset blend.
            # so we need to quickly check both. And if any of them missing. Make
            # the banner a node_badfile color.
            
            warning = ""
            
            if not os.path.exists(win.project+asset+"/autolink.data")\
            or not os.path.exists(win.project+asset.replace("/dev/","/ast/")+".blend"):
                UI_color.set(node, win, "node_badfile")
                
                warning = "\n"+talk.text("link_asset_not_configured")
                
                # Let's do even cooler. And let's draw a thing arround the asset.
                node.set_line_width(10)
                UI_elements.roundrect(node, win, 
                    0,
                    0,
                    170,
                    200,
                    10,
                    fill=False)
                
                node.stroke()
                node.set_line_width(2)
                
                # Even cooler. Let's put a configuration button right into here
                
                
                
                
                
            node.rectangle(0,0,170, 20)
            node.fill()
            
            # Outputting the layer
            layer.set_source_surface(nodesurface, 
                    tileX-10,
                    current_Y + win.scroll["asset_link"] + 120)
            layer.paint()
            
            
            # Previes image
            
            if os.path.exists(win.project+asset+"/renders/Preview.png"):
                UI_elements.image(layer, win, win.project+asset+"/renders/Preview.png", 
                    tileX,
                    current_Y + win.scroll["asset_link"] + 140, 
                    150,
                    150)
            
            elif os.path.exists(win.project+asset+"/renders/Preview.jpg"):
                UI_elements.image(layer, win, win.project+asset+"/renders/Preview.jpg", 
                    tileX,
                    current_Y + win.scroll["asset_link"] + 140, 
                    150,
                    150)
            else:
                UI_elements.image(layer, win, "settings/themes/"+win.settings["Theme"]+"/icons/"+cur+".png", 
                    tileX+55,
                    current_Y + win.scroll["asset_link"] + 150+55, 
                    150,
                    150)
            
            
            
            UI_color.set(layer, win, "text_normal")
            layer.set_font_size(12)
            layer.move_to(tileX,
                current_Y + win.scroll["asset_link"] + 135)
            layer.show_text(name[:22])   
            
            # Let's make a selection of an asset so you could delete one. Or 
            # do other stuff. Maybe.
            
            if win.current["linking_asset_data"]["selected"] == asset:
            
                layer.set_line_width(4)    
                UI_color.set(layer, win, "progress_background")
                UI_elements.roundrect(layer, win, 
                    tileX-10,
                    current_Y + win.scroll["asset_link"] + 120,
                    170,
                    200,
                    10,
                    fill=False)
                
                layer.stroke()
                layer.set_line_width(2)
                
                # And the delete key.
                
                if 65535 in win.current["keys"]:
                    try:
                        win.current["linking_asset_data"]["assets"].remove(asset)
                    except:
                        pass
                    win.current["keys"] = []
            
            # Button to activate it
            def do():
                win.current["linking_asset_data"]["selected"] = asset
            
            layer.set_line_width(4)    
            UI_elements.roundrect(layer, win, 
                tileX-10,
                current_Y + win.scroll["asset_link"] + 120,
                170,
                200,
                10,
                button=do,
                tip=talk.text(cur)+": "+name+warning,
                fill=False,
                clip=[
                        50,
                        100,
                        win.current["w"]-100,
                        win.current["h"]-200
                        ],
                url="asset_link")
            
            layer.stroke()
            layer.set_line_width(2)
        
        tileX += 200
        
        if tileX > win.current["w"]-220:
            tileX = 70
            
            current_Y += 230
    
    
    # Now here I want to put the add new one button. So you could add assets
    # to the stuff manually.
    
    def do():
        
        # Now this is going to be wild. Because I'm going to run a dialog with
        # in a dialog. And I hope that it's going to work.
        
        def after(win, var):
            
            # Funny that it's actually working.
            # Tho there is a little rub. If you press Cancel there is a bug that
            # makes nothing unusable. so...
            
            try:
                del win.current["calls"]["link_add_asset_select"]
            except:
                pass
            
            
            if var and "/dev"+var not in win.current["linking_asset_data"]["assets"]:
                win.current["linking_asset_data"]["assets"].append("/dev"+var)
            
            # So basically I want to add one only if there is not one already.
            # And then select it. So if the use gets which one is added or
            # whether it was already there.
            
            win.current["linking_asset_data"]["selected"] = "/dev"+var
            
            # And since it could allight with the add button. Let's clear the
            # click
            
            win.current["LMB"] = False
            win.previous["LMB"] = False
        
            
        studio_dialogs.asset_select(win, "link_add_asset_select", after) 
    
    UI_elements.roundrect(layer, win, 
        tileX-10,
        current_Y + win.scroll["asset_link"] + 120,
        170,
        200,
        10,
        button=do,
        url="asset_link")
    
    UI_color.set(layer, win, "progress_background")
    UI_elements.roundrect(layer, win, 
        tileX-10,
        current_Y + win.scroll["asset_link"] + 120,
        170,
        200,
        10,
        fill=False)
    layer.stroke()
    
    UI_elements.image(layer, win, 
        "settings/themes/"+win.settings["Theme"]+"/icons/asset_new.png",
        tileX+55,
        current_Y + win.scroll["asset_link"] + 200,
        40, 40)
    
    #############################
    
    current_Y += 230
    
    UI_elements.scroll_area(layer, win, "asset_link", 
        50,
        100,
        win.current["w"]-100,
        win.current["h"]-200,
        current_Y,
        bar=True,
        mmb=True,
        url="asset_link",
        strenght=130
        )
    
    
    
    return surface
