# THIS FILE IS A PART OF VCStudio
# PYTHON 3

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

#UI modules
from UI import UI_elements
from UI import UI_color

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

def layer(win, call):
    
    ##########################################################################
    
    # This file will do the asset configuration for linking assets into anima-
    # tion files. The ways it's going to be performed is following:
    
    # 0. User creates the asset. The /dev/ folder for the asset is created.
    # 1. User finished the asset and the checklists is now 100%.
    # 2. User Clicks on a configure button which launches this UI.
    # 3. User choses the main blendfile. It is copied to the /ast/ folder.
    # 4. User choses the collection and the rig with in the file. and it's
    #    saved into autolink.data
    # 5. User creates a shot in the script editor. And creates a blend-file.
    # 6. Use presses the link button on the blend file. And it loads the assets
    #    mentioned in the script. 
    # 7. User presses the okay button and a script is running inside blender
    #    that will read autolink.data files. And open /ast/ blend files. From
    #    which it will loaded the right collection and make library override or
    #    proxy to the rig. Both specified here by the user.
    
    # See:
    #     studio/studio_shot_linkLayer.py
    #     studio/bpy_do_linking.py
    #     studio/studio_assetLayer.py
    
    # The way this file going to work will be like a step by step wizzard.
    
    # This file will be able to be openned from studio_shot_linkLayer dialog so
    # there will be 3 different UIs in this file.
    
    # 0. If checklist is not yet 100%. There will be a message to finish the
    #    asset first.
    # 1. When the checklist is 100%. There will UI to select / copy /ast/file
    # 2. When that's done. The program going to launch a script to read data
    #    from the newly created /ast/ file. And will present the user with 
    #    selection of collections and objects from the collections. So to
    #    what to link and what to proxy.
    
    ##########################################################################
    
    
    # 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, 
        win.current["w"]/2-250,
        100,
        500,
        win.current["h"]-200,
        10)
    
    # 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,
        win.current["w"]/2-250,
        win.current["h"]-140, 
        40,
        40,
        10,
        do,
        "question")
    
    
    # Exit button
    def do():
        win.current["calls"][call]["var"] = False 
        
        
    UI_elements.roundrect(layer, win, 
        win.current["w"]/2+210,
        win.current["h"]-140,
        40,
        40,
        10,
        button=do,
        icon="cancel",
        tip=talk.text("cancel"))
    
      
    # Okay so before we going to clip everything. Let's make a little widget.
    # this will be similar to the thing on top of shots. With the little round
    # icons. And a some kind of progress bar with fat points. But this one
    # will have only 3 points. 
    
    # Let's simplify the process a little bit
    
    x = win.current["w"]/2-250
    y = 100
    width = 500
    height = win.current["h"]-200
    
    # Okay. let's draw the icons.
    
    threeicons = {
        "edit_mode":False,
        "blender":False,
        "link_configure":False                  
        }
    
    for numb, icon in enumerate(threeicons):
        UI_elements.image(layer, win,"settings/themes/"\
            +win.settings["Theme"]+"/icons/"+icon+".png",
            x+(width/4)*numb+(width/8)+40,
            y+20, 
            40,
            40)
    
    # Before we can do progress bar and or progress dots we need to check
    # a few things about the asset.
    
    # First is whether it's done.
    threeicons["edit_mode"] = story.get_asset_data(win, win.current["asset_configure"]["asset"])["fraction"] == 1
    # Then whether the ast exists.
    threeicons["blender"] = os.path.exists(win.project+"/ast"+win.current["asset_configure"]["asset"]+".blend")
    # Then whether the autolink.data exists.
    threeicons["link_configure"] = os.path.exists(win.project+"/dev"+win.current["asset_configure"]["asset"]+"/autolink.data")
    
    # Now let's manually make the fraction.
    fraction = 0.0
    if threeicons["edit_mode"]:
        fraction = 0.33
    if threeicons["blender"]:
        fraction = 0.66
    if threeicons["link_configure"]:
        fraction = 1
    
    UI_color.set(layer, win, "progress_background")
    UI_elements.roundrect(layer, win,
        x+20,
        y+80, 
        width-40,
        0,
        5)

    UI_color.set(layer, win, "progress_active")
    UI_elements.roundrect(layer, win,
        x+20,
        y+80, 
        (width-40)*fraction,
        0,
        5)
   
    # And the 3 dots
   
    for numb, icon in enumerate(threeicons):
        
        UI_color.set(layer, win, "progress_background")
        if threeicons[icon]: # If this folder has any files.
            UI_color.set(layer, win, "progress_active")
        UI_elements.roundrect(layer, win,
            x+(width/4)*numb+(width/8)+50,
            y+75, 
            0,
            0,
            10)
    
    # Now let's do 3 UIs. 
    
    
    ################## STEP 1: MAKE ASSET ######################
    
    if not threeicons["edit_mode"]:
        
        fraction = story.get_asset_data(win, win.current["asset_configure"]["asset"])["fraction"]
        
        UI_elements.text(layer, win, "asset_configuration_step",
            x,
            y+150,
            width,
            30,
            10,
            fill=False,
            centered=True,
            editable=False)
        win.text["asset_configuration_step"]["text"] = talk.text("asset_configuration_step_1")
        
        UI_elements.text(layer, win, "asset_configuration_step1",
            x,
            y+200,
            width,
            30,
            10,
            fill=False,
            centered=True,
            editable=False)
        win.text["asset_configuration_step1"]["text"] = str(int(round(fraction*100)))+"%"
        
        UI_color.set(layer, win, "progress_background")
        UI_elements.roundrect(layer, win,
            x+20,
            y+250, 
            width-40,
            0,
            5)

        UI_color.set(layer, win, "progress_active")
        UI_elements.roundrect(layer, win,
            x+20,
            y+250, 
            (width-40)*fraction,
            0,
            5)
    
    ####################### STEP 2 : COPY BLEND-FILE TO AST ####################
    
    
    
    
    # Setting up the scroll
    if "asset_configure" not in win.scroll:
        win.scroll["asset_configure"] = 0
    
    current_Y = 310 # The max scroll value
    
    if threeicons["edit_mode"] and not threeicons["blender"]:  
        
        UI_elements.text(layer, win, "asset_configuration_step",
            x,
            y+150,
            width,
            30,
            10,
            fill=False,
            centered=True,
            editable=False)
        win.text["asset_configuration_step"]["text"] = talk.text("asset_configuration_step_2")
        
        # So if the file is selected I want to have an apply button.
        
        if win.current["asset_configure"]["blend_to_copy"]:
            
            UI_color.set(layer, win, "text_normal")
            layer.set_font_size(20)
            layer.move_to(x+40,
                    y+height-20)
            layer.show_text(win.current["asset_configure"]["blend_to_copy"])
            
            def do():
                copy_from = win.project+"/dev"+win.current["asset_configure"]["asset"]+"/"+win.current["asset_configure"]["blend_to_copy"]
                copy_to = win.project+"/ast"+win.current["asset_configure"]["asset"]+".blend"
                
                newname = copy_to[copy_to.rfind("/")+1:]
                copy_to = copy_to[:copy_to.rfind("/")]
                
                oscalls.copy_file(
                    win,
                    copy_from,
                    copy_to,
                    newname)
                
            UI_elements.roundrect(layer, win, 
                win.current["w"]/2+170,
                win.current["h"]-140,
                40,
                40,
                10,
                button=do,
                icon="ok",
                tip=talk.text("checked"))
        
        
        
        # Here I want to draw a whole window with blend file selection and stuff.
        # so here we go.
        
        # Clipping everything
        UI_elements.roundrect(layer, win, 
            win.current["w"]/2-250,
            300,
            500,
            win.current["h"]-460,
            10,
            fill=False)
        layer.clip()
        
        clip = [
            win.current["w"]/2-250,
            300,
            500,
            win.current["h"]-460]
        
        # Background
        #UI_color.set(layer, win, "dark_overdrop")
        #layer.rectangle(x, y,width,height)
        #layer.fill()
        
        # Now we draw all the blend files of the file. I know it's redundant  but
        # I want to be able to configure an asset from the linking window.
        
        tileX = x+70
        
        for filename in sorted(os.listdir(win.project+"/dev"+win.current["asset_configure"]["asset"])):
            
            if filename.endswith(".blend"):
            
                if int(current_Y + win.scroll["asset_configure"]) in range(0-200, height):
                            
                    # Making the layer
                    node2surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 170, 200)
                    node2 = cairo.Context(node2surface)
                    node2.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
                    
                    
                    UI_elements.roundrect(node2, win, 
                        0,
                        0,
                        170,
                        200,
                        10,
                        fill=False)
                    
                    node2.clip()
                    
                    # Background
                    UI_color.set(node2, win, "dark_overdrop")
                    node2.rectangle(0,0,170, 200)
                    node2.fill()
                    
                    # Banner
                    UI_color.set(node2, win, "node_blendfile") 
                    node2.rectangle(0,0,170, 20)
                    node2.fill()
                    
                    # Outputting the layer
                    layer.set_source_surface(node2surface, 
                            tileX-10,
                            current_Y + win.scroll["asset_configure"] )
                    layer.paint()
                    
                    UI_elements.image(layer, win, win.project+"/dev"+win.current["asset_configure"]["asset"]+"/"+filename, 
                        tileX,
                        current_Y + win.scroll["asset_configure"] + 30, 
                        150,
                        150)
                    
                    UI_color.set(layer, win, "text_normal")
                    layer.set_font_size(12)
                    layer.move_to(tileX,
                            current_Y + win.scroll["asset_configure"]+15)
                    layer.show_text(filename[filename.rfind("/")+1:][:22])
                    
                    # If selected
                    layer.set_line_width(4)
                    if win.current["asset_configure"]["blend_to_copy"] == filename:
                        UI_color.set(layer, win, "progress_background")
                        UI_elements.roundrect(layer, win, 
                            tileX-10,
                            current_Y + win.scroll["asset_configure"],
                            170,
                            200,
                            10,
                            fill=False)
                        layer.stroke()
                        
                    # Button to activate it
                    def do():
                        win.current["asset_configure"]["blend_to_copy"] = filename
                        
                    
                        
                    UI_elements.roundrect(layer, win, 
                        tileX-10,
                        current_Y + win.scroll["asset_configure"],
                        170,
                        200,
                        10,
                        button=do,
                        tip=filename,
                        fill=False,
                        clip=clip)
                    
                    layer.stroke()
                    layer.set_line_width(2) 
                    
                tileX += 200
                    
                if tileX > 1000:
                    tileX = x+70
                    current_Y += 230
    
    ####################### STEP 3 : CONFIGURE AUTOLINK.DATA ####################
    
    if threeicons["edit_mode"] and threeicons["blender"]: 
        
        UI_elements.text(layer, win, "asset_configuration_step",
            x,
            y+150,
            width,
            30,
            10,
            fill=False,
            centered=True,
            editable=False)
        win.text["asset_configuration_step"]["text"] = talk.text("asset_configuration_step_3")
        
        if win.current["asset_configure"]["apply"]:
            
            def do():
                # Here I'm going to actually write stuff to the file. It's not hard.
                
                autolink = open(win.project+"/dev"+win.current["asset_configure"]["asset"]+"/autolink.data", "w")
                
                cols = win.current["asset_configure"]["collections"]
                for col in cols:
                    
                    # If the collection is selected we write it.
                    
                    if cols[col]["selected"]:
                        autolink.write("Link : "+col+"\n")
                        
                        # Also we need to then look throught the collection to
                        # see if there are any proxy objects. Aramtures...
                        
                        objs = cols[col]["objects"]
                        
                        for obj in objs:
                            
                            # Same thing if it's selected. Then write it to file.
                            
                            if objs[obj]["selected"]:
                                autolink.write("Proxy : "+obj+"\n")
                autolink.close()
                
                # And a history entry real quick
                history.record(win, "/dev"+win.current["asset_configure"]["asset"]+"/autolink.data", "[Updated]")
                
                # And we need to quit the window. So...
                win.current["calls"][call]["var"] = False 
                
            UI_elements.roundrect(layer, win, 
                win.current["w"]/2+170,
                win.current["h"]-140,
                40,
                40,
                10,
                button=do,
                icon="ok",
                tip=talk.text("checked"))
        
        
        # For this step I can't just copy stuff from assed layer and pretend that everything
        # is good. Because this part requires a whole new script to write and test.
        
        # See:
        #     studio/bpy_get_blend_content.py
        
        # Now let's actually run this script quickly. Basically we need to get data out of
        # the asset blend file. But of course not on every frame. It's a bit too much. So
        # here is how we do it.
        
        if not win.current["asset_configure"]["collections"]:
            
            # If in the current data the data about the file still doesn't exists we load
            # it.
            
            blenderpath = oscalls.get_current_blender(win)
            assetblend = win.project+"/ast"+win.current["asset_configure"]["asset"]+".blend"
            
            checkframes = Popen([blenderpath, "-b", assetblend , "-P",
                 os.getcwd()+"/studio/bpy_get_blend_content.py"],stdout=PIPE, universal_newlines=True)
            checkframes.wait()
            checkstring = checkframes.stdout.read()
            
            # Let's also see if the file autolink.data already there. Meaning I can get 
            # data that is already saved there. 
            
            linkcols = []
            linkobjs = []
            
            if threeicons["link_configure"]:
                autolink = open(win.project+"/dev"+win.current["asset_configure"]["asset"]+"/autolink.data")
                autolink = autolink.read()
                autolink = autolink.split("\n")
                
                for line in autolink:
                    if line.startswith("Link : "):
                        linkcols.append(line[7:])
                    
                    elif line.startswith("Proxy : "):
                        linkobjs.append(line[8:])            
            else:
                # If there is no file. I want to start the applying process already:
                win.current["asset_configure"]["apply"] = True
            
            # Now let's parse this crazy stuff that we've got from the blender script.
            
            for line in checkstring.split("\n"):
                if line.startswith(">>> "):
                    line = line[4:]
                    if "<==" in line:
                        col = line[:line.find(" <==")]
                        obj = line[line.find(" <==")+5:].split(" <== ")
                        
                    else:
                        col = line
                        obj = False
                    
                    
                    selected = False
                    if col in win.current["asset_configure"]["asset"] and not threeicons["link_configure"]:
                        selected = True
                    elif col in linkcols:
                        selected = True
                        
                    # So we found a collection. Let's write it in
                    if col not in win.current["asset_configure"]["collections"]:
                        win.current["asset_configure"]["collections"][col] = {
                            "selected":selected,
                            "objects":{}
                            }
                    
                    # We also got the object. Let's put it inside the collection.
                    # But first. If it's an armature we want it to be selected. 
                    if obj:
                        selected = False
                        if "Armature" in obj[1] and not threeicons["link_configure"]:
                            selected = True
                        elif obj[0] in linkobjs:
                            selected = True
                        
                        win.current["asset_configure"]["collections"][col]["objects"][obj[0]] = {
                            "selected":selected,
                            "type":obj[1]
                            }
                    
        # Now let's draw the findings to the screen. But first we need
        # buttons to see in what catergory are we.
        
        buttons = ["collection", "rig"]
        
        
        
        for num, button in enumerate(buttons):
            
            if win.current["asset_configure"]["step3_button"] == button:
        
                UI_color.set(layer, win, "progress_time")
                UI_elements.roundrect(layer, win,
                    x+10+(40*num),
                    y+200, 
                    40,
                    40,
                    10)
            
            def do():
                win.current["asset_configure"]["step3_button"] = button
                
            UI_elements.roundrect(layer, win,
                x+10+(40*num),
                y+200, 
                40,
                40,
                10,
                do,
                button)
        
        
        # Now we can clip the bastard
        
        UI_elements.roundrect(layer, win, 
            win.current["w"]/2-250,
            350,
            500,
            win.current["h"]-510,
            10,
            fill=False)
        layer.clip()
        
        clip = [
            win.current["w"]/2-250,
            350,
            500,
            win.current["h"]-510]
        
        # Background
        #UI_color.set(layer, win, "dark_overdrop")
        #layer.rectangle(x, y,width,height)
        #layer.fill()
        
        # Let's start by drawing the collections first since it's the first thing
        # that the user will be doing. Is selecting the collections. 
        
        current_Y = current_Y - 50
        
        if win.current["asset_configure"]["step3_button"] == "collection":
            
            for collection in win.current["asset_configure"]["collections"]:
                
                # We are going to draw a little collection icon. And put a text
                # with it's name.
                
                UI_elements.image(layer, win, 
                    "settings/themes/"+win.settings["Theme"]+"/icons/collection.png",
                    x+60, y+current_Y+win.scroll["asset_configure"], 40, 40)
                
                UI_color.set(layer, win, "text_normal")
                layer.set_font_size(20)
                layer.move_to(x+120,
                        y+current_Y + win.scroll["asset_configure"]+30)
                layer.show_text(collection)
                
                # Now let's make a checkbox button beside each collection. 
                # Mimicing the Blender UI so to speak. 
                
                icon = "unchecked"
                if win.current["asset_configure"]["collections"][collection]["selected"]:
                    icon = "checked"
                
                def do():
                    win.current["asset_configure"]["collections"][collection]["selected"]\
                    = not win.current["asset_configure"]["collections"][collection]["selected"]
                    win.current["asset_configure"]["apply"] = True
                    
                UI_elements.roundrect(layer, win,
                    x+10,
                    y+current_Y + win.scroll["asset_configure"], 
                    40,
                    40,
                    10,
                    do,
                    icon)
                
                
                current_Y = current_Y + 50
        
        else:
            
            # If we are not doing the collection but instead we are selecting the
            # rigs. We need to draw different stuff.
            
            for collection in win.current["asset_configure"]["collections"]:
                
                # But we want to draw only objects that are in selected colllections
                # so here what we do.
                
                if win.current["asset_configure"]["collections"][collection]["selected"]:
                
                    for obj in win.current["asset_configure"]["collections"][collection]["objects"]:
                        
                        name = obj
                        obj = win.current["asset_configure"]["collections"][collection]["objects"][obj]
                        
                        # Now first thing is we need to find an icon to represent
                        # this object.
                        
                        icon = "obj"
                        if "Mesh" in obj["type"]:
                            icon = "mesh"
                        elif "Armature" in obj["type"]:
                            icon = "rig"
                        elif "Camera" in obj["type"]:
                            icon = "shot"
                        
                        UI_elements.image(layer, win, 
                            "settings/themes/"+win.settings["Theme"]+"/icons/"+icon+".png",
                            x+60, y+current_Y+win.scroll["asset_configure"], 40, 40)
                        
                        UI_color.set(layer, win, "text_normal")
                        layer.set_font_size(20)
                        layer.move_to(x+120,
                                y+current_Y + win.scroll["asset_configure"]+30)
                        layer.show_text(name)
                        
                        icon = "link"
                        if obj["selected"]:
                            icon = "override"
                        
                        def do():
                            obj["selected"]\
                            = not obj["selected"]
                            win.current["asset_configure"]["apply"] = True
                        
                        UI_elements.roundrect(layer, win,
                            x+10,
                            y+current_Y + win.scroll["asset_configure"], 
                            40,
                            40,
                            10,
                            do,
                            icon)
                        
                        
                        current_Y = current_Y + 50
        
    current_Y = current_Y - 300
    
    ###########################
        
    UI_elements.scroll_area(layer, win, "asset_configure", 
        x,
        y+300,
        width,
        height-400,
        current_Y,
        bar=True,
        mmb=True,
        url="asset_configure"
    )
    
    
    return surface
