"""
PoseSaveState for All engines (Implemented in SceneSaveState as "Pose Library")
Based on PoseConsole for HS StudioNeo (Implemented in SceneConsole as "Pose Library") (by @chickenmanX)
v4.0
Plugin for management of pose library

2.0
- changed PoseConsoleUIData to direct use folders
- fixed bug with tx names
- moved folders to sss/fposes, sss/mposes
- change logic to use classes
- add faces save/load
2.1
- fix bug: empty Tags during save will lead to Base tag, not error
- X buttons for text fields during save
2.2
- Fix bug with no MFaces tab
3.0
- Support save: FStatus, MStatus, Left hand, Right hand
3.1
- sorting in pose group
- replaced everywhere for grp in console.lib.Keys: to for grp in sorted(console.lib.Keys):
4.0
- saving in PNG files
4.1
- PNGFileSupported lib
4.2
- Clip lib support vnanime clip v2
4.3
- Adapt to new toolbar style
"""
from vngameengine import HSNeoOCIFolder, HSNeoOCI
from vnactor import *
from Studio import OICharInfo
from UnityEngine import GUI, GUILayout, GUIStyle, GUIUtility, Screen, Rect, Vector3, Vector2, Input, KeyCode
from UnityEngine import Event, EventType, WaitForSeconds, GameObject
from System import String, Array

from System import Single, Byte
from json import encoder
import json
from array import array
#import extplugins
#[116,153 except 122,123]
#Instance of pose console
_pc = None

# :::::::::: JSON Derulo ::::::::::::
encoder.FLOAT_REPR = lambda o: format(o, '.3f')
from libjsoncoder import *

import extplugins
plXxpe = extplugins.AIPE()

# loading pngFileSupported library

pngFileSupported = False
try:
    import clr
    clr.AddReference('PNGFileSupport')
    import PngFileSupport
    pngFileSupported = True
except Exception, e:
    print("VNGE: can't load PNGFileSupport lib")

# :::::::::: Main console ::::::::::::
def start(game):
    toggle_pose_console()

class PoseConsoleUIData():
    def __init__(self, basefold = None, groupose_flag = False):
        self.toolbarInt = 0
        self.basefold = basefold

        # --- Load screen --- 
        self.ldscrollPos = Vector2(0,0)
        self.ldtagscrollpos = Vector2(0,0)
        self.ldgrpscrollpos = Vector2(0,0)

        self.ldsearchstr = ""
        self.ldbyTag = False
        self.ldbyGrp = False

        self.ldTags = []
        self.ldTagsBckup = []
        self.ldTagTgl = []
        self.ldGroup = ""

        # --- Save screen ---
        self.svscrollPos = Vector2(0,0)
        self.svtagscrollpos = Vector2(0,0)
        self.svgrpscrollpos = Vector2(0,0)
        self.svsearchstr = ""
        self.svtagstr = ""
        self.svgrpstr = ""
        self.svTagTgl = []

        # --- Replace screen --- 
        self.rep_scrollPos = Vector2(0,0)
        self.rep_tagscrollpos = Vector2(0,0)
        self.rep_grpscrollpos = Vector2(0,0)
        self.rep_searchstr = ""
        self.rep_tagstr = ""
        self.rep_grpstr = ""
        self.rep_TagTgl = []

        self.loaded_pose = None # pose key from load scren
        self.rep_do_init = False
        self.rep_do = False

        # --- Lib --- 
        self.taglib = []
        self.lib = {"None":{},}
        self.y_offset = 0

        # --- Pose fetch ---
        self.isFileInited = False # do it later
        self.textureWatermark = None


        # --- Color data ---
        self.nortgcol = "#f9f9f9"
        self.sptgcol = "#42d4f4"



    def initFromFiles(self):
        # --- Pose fetch ---
        self.isFileInited = True

        self.getAllPoses()
        self.getAllTags()
        self.getTagIndex()

        # also getting watermark
        from UnityEngine import Texture2D
        self.textureWatermark = Texture2D(1, 1)
        try:
            from vngameengine import FilePNG2Texture2D
            import os.path

            basewmpath = os.path.dirname(__file__)+"/posesavestate_wm"
            advwmpath = os.path.dirname(__file__)+"/posesavestate_wm_"+self.basefold.replace("/","_")
            if os.path.exists(advwmpath+".png"):
                self.textureWatermark = FilePNG2Texture2D(advwmpath+".png")
            else:
                self.textureWatermark = FilePNG2Texture2D(basewmpath+".png")
        except Exception, e:
            print("Can't find watermark for")

    def getAllPoses(self):
        import os

        script_dir = os.path.dirname(__file__) #<-- absolute dir the script is in




        basefolder_path = os.path.join(script_dir, self.basefold)
        itemlist = os.listdir(basefolder_path)

        #poselib = {}
        #print itemlist
        ext = ".txt"
        ext2 = ".png"
        for item in itemlist:
            if os.path.isdir(basefolder_path+item):
                if not item in self.lib.Keys:
                    self.lib[item] = {}
                sub_fld_path = os.path.join(basefolder_path,(item+"/"))
                filelist = os.listdir(sub_fld_path)
                for file in filelist:
                    if file.endswith(ext) or file.endswith(ext2):
                        #posename = file.strip('.txt')
                        posename = file[0:-4]
                        file_path = sub_fld_path+file

                        dat = self.getPoseDataFromFile(file_path)

                        # if self.basefold == "sss/propfk/":
                        #     print(file_path,dat)

                        if dat != None:
                            self.lib[item][posename] = dat

            elif item.endswith(ext) or item.endswith(ext2):
                posename = item[0:-4]
                file_path = os.path.join(basefolder_path, item)

                dat = self.getPoseDataFromFile(file_path)
                if dat != None:
                    self.lib["None"][posename] = dat



    def getPoseDataFromFile(self,file_path):
        from vngameengine import vnge_game

        if file_path.endswith(".txt"):
            f = open(file_path)
            res = json.loads(f.read(), object_hook = sceneDecoder)
            f.close()

            if "thumb" in res.keys():
                from vngameengine import BytesPNG2Texture2D
                from vnactor import str64_to_bytearray
                res["tex2d"] = BytesPNG2Texture2D(str64_to_bytearray(res["thumb"]))

            return res

        if file_path.endswith(".png"):
            try:
                from vngameengine import vnge_game

                from System.IO import File, FileStream, FileMode, FileAccess
                from System.IO import MemoryStream, BinaryWriter, BinaryReader

                with FileStream(file_path, FileMode.Open, FileAccess.Read) as inp:
                    with BinaryReader(inp) as binaryReader:
                        thumb = PngFileSupport.LoadPngBytes(binaryReader)
                        key = binaryReader.ReadString()
                        if key != "vnge_posesavestate":
                            vnge_game.logger_log_message(file_path+" is incorrect PoseSaveState PNG file")
                            return None
                        else:
                            checkfolder = binaryReader.ReadString()
                            if checkfolder != self.basefold:
                                vnge_game.logger_log_message(file_path+" is other PoseSaveState PNG file: it's from "+checkfolder+", while placed in "+self.basefold)
                                return None
                            else:
                                jsonstr = binaryReader.ReadString()
                                res = json.loads(jsonstr, object_hook = sceneDecoder)
                                from vngameengine import BytesPNG2Texture2D
                                res["tex2d"] = BytesPNG2Texture2D(thumb)
                                return res
            except Exception, e:
                vnge_game.logger_log_message(file_path+" can't be loaded as PoseSaveState PNG file")
                return None

        return None

    def getAllTags(self):
        #taglib = []
        for grp in self.lib.values():
            for pose in grp.Keys:
                if not grp[pose]["tags"] == [""]:
                    tags = grp[pose]["tags"]
                    self.taglib = addItems(tags, self.taglib)
        # Something Heels/flats on top
        #ntaglib = ["Heels","Flats"]
        #ntaglib = ["Heels", "Flats"]
        ntaglib = ["Base", "Sexy"]
        #ntaglib = []
        for tg in self.taglib:
            if not tg.lower() == "base" and not tg.lower() == "sexy" :
                ntaglib.append(tg)

        self.taglib = ntaglib
        #return self.taglib


    def getTagIndex(self):
        self.ldTagTgl = []
        self.svTagTgl = []
        self.rep_TagTgl = []

        for i in range (0,len(self.taglib)):
            self.ldTagTgl.append(False)
            self.svTagTgl.append(False)
            self.rep_TagTgl.append(False)

    def getRepTagIndex(self):
        self.rep_TagTgl = []
        for i in range (0,len(self.taglib)):
            self.rep_TagTgl.append(False)


    # base function to override
    def savePoseData(self, name, tags, group, offset_flag = False, rep_loaded = False):
        return None

    #Save Pose
    def savePose(self, name, tags, group, offset_flag = False, rep_loaded = False):

        data = self.savePoseData(name, tags, group, offset_flag , rep_loaded)

        if data == None:
            return None

        import os



        tags = tags.replace(" ","")

        # avoid bugs if str is empty
        if tags == "":
            tags = "Base,"

        if tags[-1] == ",":
            tags = tags[0:-1]
        tags = tags.split(",")

        #dict = {"pose" : pose, "tags" : tags, "group" : group}
        dict = {"pose" : data, "tags" : tags}


        from vngameengine import vnge_game

        from vnactor import bytearray_to_str64
        thumb = None
        try:
            #dict["thumb"] =  bytearray_to_str64(vnge_game.makePngScreenshot(160,90))
            thumb = vnge_game.makePngScreenshot(320,180)
            from vngameengine import WatermarkTexture, BytesPNG2Texture2D, Texture2D2BytesPNG
            thumb_tex = BytesPNG2Texture2D(thumb)
            thumb_wat_tex = WatermarkTexture(thumb_tex,self.textureWatermark,0,thumb_tex.height - self.textureWatermark.height)
            thumb = Texture2D2BytesPNG(thumb_wat_tex)
        except Exception, e:
            print("Error: Can't make thumbnail:", str(e))


        script_dir = os.path.dirname(__file__) #<-- absolute dir the script is in


        folder_path = os.path.join(script_dir,self.basefold)

        #Group (make folder)
        if not group == "":
            folder_path = os.path.join(folder_path,(group + "/"))
            if not os.path.exists(folder_path):
                os.makedirs(folder_path)

        try: # trying make PNG file - option 1
            if thumb == None:
                a = 6/0 # move to Exception

            if not pngFileSupported:
                vnge_game.logger_log_message("Can't find PNGFileSupport.dll - fallback to TXT file.")
                a = 6/0 # move to Exception

            #import PngFile
            from System.IO import File, FileStream, FileMode, FileAccess
            from System.IO import MemoryStream, BinaryWriter, BinaryReader

            file_path = os.path.join(folder_path, (str(name)+".png"))
            jsonstr = json.dumps(dict, cls = SceneEncoder)

            # If replace
            if rep_loaded == True:
                #if not str(self.loaded_pose[0]) == str(name):
                old_file_path = folder_path + str(self.loaded_pose[0]) + ".txt"
                abs_old_file_path = os.path.join(script_dir, old_file_path)
                if os.path.exists(abs_old_file_path) and abs_old_file_path != file_path:
                    os.rename(abs_old_file_path,file_path)

                old_file_path = folder_path + str(self.loaded_pose[0]) + ".png"
                abs_old_file_path = os.path.join(script_dir, old_file_path)
                if os.path.exists(abs_old_file_path) and abs_old_file_path != file_path:
                    os.rename(abs_old_file_path,file_path)


            with FileStream(file_path, FileMode.Create, FileAccess.Write) as output:
                with BinaryWriter(output) as binaryWriter:
                    binaryWriter.Write(thumb)
                    binaryWriter.Write("vnge_posesavestate")
                    binaryWriter.Write(self.basefold)
                    binaryWriter.Write(jsonstr)

            vnge_game.logger_log_message("Pose saved to PNG file!")

        except Exception, e:
            # fallback to old one, TXT - option 2
            #vnge_game.
            vnge_game.logger_log_message("Can't save pose to PNG - fallback to TXT file. Details in Console")

            import traceback
            traceback.print_exc()

            file_path = os.path.join(folder_path, (str(name)+".txt"))

            # If replace
            if rep_loaded == True:
                if not str(self.loaded_pose[0]) == str(name):
                    old_file_path = folder_path + str(self.loaded_pose[0]) + ".txt"
                    abs_old_file_path = os.path.join(script_dir, old_file_path)
                    if os.path.exists(abs_old_file_path) and abs_old_file_path != file_path:
                        os.rename(abs_old_file_path,file_path)

                    old_file_path = folder_path + str(self.loaded_pose[0]) + ".png"
                    abs_old_file_path = os.path.join(script_dir, old_file_path)
                    if os.path.exists(abs_old_file_path) and abs_old_file_path != file_path:
                        os.rename(abs_old_file_path,file_path)

            if thumb != None:
                dict["thumb"] =  bytearray_to_str64(thumb)

            f=open(file_path,"w")
            f.write(json.dumps(dict, cls = SceneEncoder))#, indent = 4, separators = (","," : ")))
            f.close()


        #Add pose to PoseLib
        dict_upd = self.getPoseDataFromFile(file_path)
        if rep_loaded == True:
            loaded_name = self.loaded_pose[0]
            loaded_grp = self.loaded_pose[1]
            self.lib[loaded_grp].pop(loaded_name)
        if group == "":
            self.lib["None"][name] = dict_upd
        elif group not in self.lib.Keys:
            self.lib[group] = {}
            self.lib[group][name] = dict_upd
        else:
            self.lib[group][name] = dict_upd
        self.getAllTags()
        self.getTagIndex()

    def checkTags(self, grp, name):
        if (set(list(map(lambda x: x.lower(),self.ldTags))) <= set(list(map(lambda x: x.lower(),self.lib[grp][name]["tags"])))):
            return True
        else:
            return False

    def prepReplace(self, pose_name, grp_name):
        self.loaded_pose = (pose_name, grp_name)
        self.rep_do_init = True

    def replaceInit(self):
        if self.rep_do_init == True:
            pose_name = self.loaded_pose[0]
            grp_name = self.loaded_pose[1]
            if isinstance(self.loaded_pose,tuple):
                self.rep_searchstr = pose_name
                if grp_name == "None":
                    self.rep_grpstr = ""
                else:
                    self.rep_grpstr = grp_name

                self.getRepTagIndex()
                tags = self.lib[grp_name][pose_name]["tags"]
                if len(tags) > 0:
                    for tag in tags:
                        for i in range(0,len(self.taglib)):
                            if tag.lower() == self.taglib[i].lower():
                                self.rep_TagTgl[i] = True
                            #else:
                            #self.rep_TagTgl[i] = False
                self.rep_do = True
                self.rep_do_init = False

    def applyState(self, state):
        return applyStateNormal(state)

    # additional button
    def isAddButton(self):
        return False

    def addButtonText(self):
        return "No text"

    def addButtonRun(self):
        pass

class UIDataPoses(PoseConsoleUIData):
    def savePoseData(self, name, tags, group, offset_flag = False, rep_loaded = False):
        char = get_selected_objs(_pc.game)
        if not char == None:
            char = char[0]
            state = char.export_full_status()

            pose = {}
            poseKeys = ["kinematic", "anim", "anim_spd", "anim_ptn", "anim_lp", "ik_active",
                        "ik_set", "fk_active", "face_to", "rotate_to", "hands"]
            if state["face_to"] == 4:
                poseKeys.append("face_to_full")

            # --- Creating dictionary ---
            for key in poseKeys:
                if key in state:
                    pose[key] = state[key]

            if offset_flag == True:
                pose["y_offset"] = state["move_to"][1]
                # Y offset backup
                if char.sex == 1:
                    self.y_offset = state["move_to"][1]

            # Exclude head fk nodes
            pose["fk_set"] = excludeFK(state["fk_set"])

            return pose

        return None


class UIDataFPoses(UIDataPoses):
    def __init__(self):
        PoseConsoleUIData.__init__(self, "sss/fposes/")

class UIDataMPoses(UIDataPoses):
    def __init__(self):
        PoseConsoleUIData.__init__(self, "sss/mposes/")

class UIDataPropFK(PoseConsoleUIData):
    def __init__(self):
        PoseConsoleUIData.__init__(self, "sss/propfk/")

    def savePoseData(self, name, tags, group, offset_flag = False, rep_loaded = False):
        props = get_selected_props(_pc.game)
        if not props == None:
            prop = props[0]
            state = prop.export_full_status()

            pose = {}
            poseKeys = ["fk_set", "ik_set"]

            # --- Creating dictionary ---
            for key in poseKeys:
                if key in state:
                    pose[key] = state[key]

            return pose

        return None

    def applyState(self, state):
        applyStateNormalProp(state)

class UIDataFaces(PoseConsoleUIData):
    def savePoseData(self, name, tags, group, offset_flag = False, rep_loaded = False):
        char = get_selected_objs(_pc.game)
        if not char == None:
            char = char[0]
            state = char.export_full_status()

            pose = {}
            poseKeys = ["eyes", "eyes_blink", "eyes_open", "face_red", "look_at_pos", "look_at_ptn",
                        "mouth", "mouth_open", "tear"]
            if _pc.game.isCharaStudio:
                poseKeys.append("eyebrow")

            # --- Creating dictionary ---
            for key in poseKeys:
                if key in state:
                    pose[key] = state[key]
            return pose

        return None

class UIDataFFaces(UIDataFaces):
    def __init__(self):
        PoseConsoleUIData.__init__(self, "sss/ffaces/")

class UIDataMFaces(UIDataFaces):
    def __init__(self):
        PoseConsoleUIData.__init__(self, "sss/mfaces/")

class UIDataStatus(PoseConsoleUIData):
    def savePoseData(self, name, tags, group, offset_flag = False, rep_loaded = False):
        char = get_selected_objs(_pc.game)
        if not char == None:
            char = char[0]
            state = char.export_full_status()

            del state["visible"]
            del state["rotate_to"]
            del state["move_to"]
            del state["scale_to"]
            return state

        return None



    def applyState(self, state):
        return applyStateNormalDiffOpt(state)

class UIDataFStatus(UIDataStatus):
    def __init__(self):
        PoseConsoleUIData.__init__(self, "sss/fstatus/")

class UIDataMStatus(UIDataStatus):
    def __init__(self):
        PoseConsoleUIData.__init__(self, "sss/mstatus/")

# class UIDataPropStatus(UIDataStatus):
#     def __init__(self):
#         PoseConsoleUIData.__init__(self, "sss/propstatus/")


class UIDataHands(PoseConsoleUIData):
    def savePoseData(self, name, tags, group, offset_flag = False, rep_loaded = False):
        char = get_selected_objs(_pc.game)
        if not char == None:
            char = char[0]
            state = char.export_full_status()

            pose = {}
            poseKeys = ["kinematic", "hands", "fk_set", "fk_active", "ik_active", "ik_set"]

            # --- Creating dictionary ---
            for key in poseKeys:
                if key in state:
                    pose[key] = state[key]
            return pose

        return None

    def applyState(self, state):
        global _pc
        char = get_selected_objs(_pc.game)
        if not char == None:
            char = char[0]
            self.applyStateChar(char,state)
            return True
        return None

    def applyStateChar(self, char, state):
        global _pc
        kin = char.get_kinematic()
        if kin == 2 or kin == 3:
            # ok
            self.applyStateChar2(char,state)
        else:
            _pc.show_blocking_message_time_pc("Load works only if char in FK or FK&IK state")

    def applyStateChar2(self, char, state):
        pass

class UIDataLHand(UIDataHands):
    def __init__(self):
        PoseConsoleUIData.__init__(self, "sss/lhand/")
    # def applyState(self, state):
    #     applyStateLHand(state)

    def applyStateChar2(self, char, state):
        do_exist = False

        lhand_keys = [i for i in range(37,52)]
        #if lhand_keys <= state["fk_set"].keys():
        lhand_fk = {}
        for i in lhand_keys:
            if i in state["fk_set"].keys():
                lhand_fk[i] = state["fk_set"][i]
                do_exist = True
        if do_exist == True:
            char.set_FK_active(group = 5, active = 1)
            char.import_fk_bone_info(lhand_fk)

class UIDataRHand(UIDataHands):
    def __init__(self):
        PoseConsoleUIData.__init__(self, "sss/rhand/")
    # def applyState(self, state):
    #     applyStateRHand(state)

    def applyStateChar2(self, char, state):
        do_exist = False

        rhand_keys = [i for i in range(22,37)]
        #if rhand_keys <= state["fk_set"].keys():
        rhand_fk = {}
        for i in rhand_keys:
            if i in state["fk_set"].keys():
                rhand_fk[i] = state["fk_set"][i]
                do_exist = True
        if do_exist == True:
            char.set_FK_active(group = 4, active = 1)
            char.import_fk_bone_info(rhand_fk)

class UIAnimeChar(PoseConsoleUIData):
    def __init__(self):
        PoseConsoleUIData.__init__(self, "sss/vnachar/")
        self.postfix = "_lib"

    def savePoseData(self, name, tags, group, offset_flag = False, rep_loaded = False):
        import vnanime

        char = get_selected_objs(_pc.game)
        if not char == None:
            char = char[0]

            # trying to find necessary clip
            resClip = None
            for clip in _pc.game.gdata.kfaSortedClips:
                """:type clip: vnanime.KeyFrameClip"""
                if clip.isPlaying: # must be playing

                    actKeys = [tgt for tgt in clip.keyframes.Keys if clip.game.scenedata.actors.has_key(tgt)]
                    proKeys = [tgt for tgt in clip.keyframes.Keys if clip.game.scenedata.props.has_key(tgt)]

                    if len(actKeys) == 1 and len(proKeys) == 0:
                        if _pc.game.scenedata.actors[actKeys[0]].objctrl == char.objctrl:
                            resClip = clip
                            break


            if resClip == None:
                _pc.show_blocking_message_time_pc("Can't find playing VNAnime clip to save\nClip must be:\n- playing\n- contains animation for ONLY ONE char (clip targeting several items/chars can't be saved!)\n- this char must be selected")
                return None

            if resClip.version == 1:
                return resClip.exportSettingForScene()
            elif resClip.version == 2:
                return resClip.exportSetting()
            else:
                _pc.show_blocking_message_time_pc("Unsupported VNAnime clip version")
                return None
        else:
            _pc.show_blocking_message_time_pc("Char must be selected")
            return None

        return None

    def applyState(self, state):
        import unity_util


        global _pc
        char = get_selected_objs(_pc.game)
        if not char == None:
            char = char[0]
            #self.applyStateChar(char,state)
            #_pc.show_blocking_message_time_pc("Not implemented yet")

            actors = _pc.game.scenef_get_all_actors()
            select_actor_key = None
            for actor_key in actors.Keys:
                if actors[actor_key].objctrl == char.objctrl:
                    select_actor_key = actor_key
                    break

            if select_actor_key != None:
                import vnanime


                target_clip_name = select_actor_key+self.postfix

                # add process
                ctrl, alt, shift = unity_util.metakey_state()
                if ctrl:
                    target_clip_name += "2"
                if alt:
                    target_clip_name += "3"

                print "VNAnime char, target charID={0}, new clip name={1}".format(select_actor_key, target_clip_name)

                if target_clip_name in _pc.game.gdata.kfaManagedClips:
                    vnanime.kfa_remove(_pc.game, target_clip_name)

                if isinstance(state, dict):
                    clipScript = state
                    cver = 2
                elif isinstance(state, str):
                    import ast
                    clipScript = ast.literal_eval(state)
                    cver = 1
                else:
                    _pc.show_blocking_message_time_pc("Unknown clip save data format")
                    return None

                #print clipScript

                # processing
                if cver == 1:
                    clipScript["setting"]["autorun"] = True
                    clipScript["setting"]["name"] = target_clip_name

                    actOldName = list(clipScript["actors"].keys())[0]
                    frames = clipScript["actors"][actOldName]
                    clipScript["actors"].pop(actOldName)
                    clipScript["actors"][select_actor_key] = frames

                    vnanime.kfa_import(_pc.game, clipScript)
                elif cver == 2:
                    from vnanime2 import KeyFrameClip2
                    #clipScript["autorun"] = True
                    clipScript["name"] = target_clip_name

                    actOldName = list(clipScript["keyframes"].keys())[0]
                    frames = clipScript["keyframes"][actOldName]
                    frames["targetId"] = select_actor_key
                    clipScript["keyframes"].pop(actOldName)
                    clipScript["keyframes"][select_actor_key] = frames
                    
                    clip = KeyFrameClip2.createFromSetting(_pc.game, clipScript)
                    vnanime.kfa_register(_pc.game, clip)

                vnanime.kfa_play(_pc.game, target_clip_name)

                return True



            else:
                _pc.show_blocking_message_time_pc("Char must be trackable (has ID). Add it to Tracking")
                return None

        else:
            _pc.show_blocking_message_time_pc("Char must be selected")
            return None

        return None

        # additional button
    def isAddButton(self):
        return True

    def addButtonText(self):
        return "To Clip Manager"

    def addButtonRun(self):
        global _pc
        _pc.game._sup_toggle_vnframe_console()

class UIAnimeProp(UIAnimeChar):
    def __init__(self):
        PoseConsoleUIData.__init__(self, "sss/propvnanime/")
        self.postfix = "_libi"

    def savePoseData(self, name, tags, group, offset_flag = False, rep_loaded = False):

        char = get_selected_props(_pc.game)
        if not char == None:
            char = char[0]

            # trying to find necessary clip
            resClip = None
            for clip in _pc.game.gdata.kfaSortedClips:
                """:type clip: vnanime.KeyFrameClip"""
                if clip.isPlaying: # must be playing

                    actKeys = [tgt for tgt in clip.keyframes.Keys if clip.game.scenedata.actors.has_key(tgt)]
                    proKeys = [tgt for tgt in clip.keyframes.Keys if clip.game.scenedata.props.has_key(tgt)]

                    if len(actKeys) == 0 and len(proKeys) == 1:
                        if _pc.game.scenedata.props[proKeys[0]].objctrl == char.objctrl:
                            resClip = clip
                            break


            if resClip == None:
                _pc.show_blocking_message_time_pc("Can't find playing VNAnime clip to save\nClip must be:\n- playing\n- contains animation for ONLY ONE Studio prop (item) (clip targeting several items/chars can't be saved!)\n- this Studio item must be selected")
                return None

            if resClip.version == 1:
                return resClip.exportSettingForScene()
            elif resClip.version == 2:
                return resClip.exportSetting()
            else:
                _pc.show_blocking_message_time_pc("Unsupported VNAnime clip version")
                return None
        else:
            _pc.show_blocking_message_time_pc("Item must be selected")
            return None

        return None

    def applyState(self, state):
        import unity_util


        global _pc
        char = get_selected_props(_pc.game)
        if not char == None:
            char = char[0]
            #self.applyStateChar(char,state)
            #_pc.show_blocking_message_time_pc("Not implemented yet")

            actors = _pc.game.scenef_get_all_props()
            select_actor_key = None
            for actor_key in actors.Keys:
                if actors[actor_key].objctrl == char.objctrl:
                    select_actor_key = actor_key
                    break

            if select_actor_key != None:
                import vnanime


                target_clip_name = select_actor_key+self.postfix

                # add process
                ctrl, alt, shift = unity_util.metakey_state()
                if ctrl:
                    target_clip_name += "2"
                if alt:
                    target_clip_name += "3"

                print "VNAnime item, targ itemID={0}, new clip name={1}".format(select_actor_key, target_clip_name)

                if target_clip_name in _pc.game.gdata.kfaManagedClips:
                    vnanime.kfa_remove(_pc.game, target_clip_name)

                if isinstance(state, dict):
                    clipScript = state
                    cver = 2
                elif isinstance(state, str):
                    import ast
                    clipScript = ast.literal_eval(state)
                    cver = 1
                else:
                    _pc.show_blocking_message_time_pc("Unknown clip save data format")
                    return None

                #print clipScript

                # processing
                if cver == 1:
                    clipScript["setting"]["autorun"] = True
                    clipScript["setting"]["name"] = target_clip_name

                    actOldName = list(clipScript["props"].keys())[0]
                    frames = clipScript["props"][actOldName]
                    clipScript["props"].pop(actOldName)
                    clipScript["props"][select_actor_key] = frames

                    vnanime.kfa_import(_pc.game, clipScript)
                elif cver == 2:
                    from vnanime2 import KeyFrameClip2
                    #clipScript["autorun"] = True
                    clipScript["name"] = target_clip_name

                    actOldName = list(clipScript["keyframes"].keys())[0]
                    frames = clipScript["keyframes"][actOldName]
                    frames["targetId"] = select_actor_key
                    clipScript["keyframes"].pop(actOldName)
                    clipScript["keyframes"][select_actor_key] = frames
                    
                    clip = KeyFrameClip2.createFromSetting(_pc.game, clipScript)
                    vnanime.kfa_register(_pc.game, clip)

                vnanime.kfa_play(_pc.game, target_clip_name)
                return True



            else:
                _pc.show_blocking_message_time_pc("Item must be trackable (has ID). Add it to Tracking")
                return None

        else:
            _pc.show_blocking_message_time_pc("Item must be selected")
            return None

        return None


class UIAnimeCharPose(UIAnimeChar):
    def __init__(self):
        PoseConsoleUIData.__init__(self, "sss/vnacharpose/")
        self.postfix = "_libp"

    def savePoseData(self, name, tags, group, offset_flag = False, rep_loaded = False):
        resClipStr = UIAnimeChar.savePoseData(self,name,tags,group,offset_flag,rep_loaded)
        if resClipStr == None:
            # call already show error
            return None

        global _pc

        resPose = _pc.fconsole.savePoseData(name,tags,group,offset_flag,rep_loaded)
        if resPose == None:
            # call already show error
            return None

        return {'pose': resPose, 'clip': resClipStr}

    def applyState(self, state):
        res = UIAnimeChar.applyState(self,state['clip'])

        if res != None:
            global _pc
            return _pc.fconsole.applyState(state['pose'])

        return res

class UIAnimeXXPE(PoseConsoleUIData):
    def __init__(self):
        PoseConsoleUIData.__init__(self, "sss/xxpelib/")

    def savePoseData(self, name, tags, group, offset_flag = False, rep_loaded = False):
        global _pc
        char = get_selected_objs(_pc.game)
        if not char == None:
            char = char[0]

            # trying to find necessary clip
            if plXxpe.isDetected:
                blshapesxml = plXxpe.GetBlendShapesXML(char.objctrl)
                resFace = _pc.ffaces.savePoseData(name,tags,group,offset_flag,rep_loaded)


                return {"face":resFace,"xxpexml":blshapesxml}
            else:
                _pc.show_blocking_message_time_pc("XXPE (KKPE, HSPE etc.) plugin not detected")
                return None


        else:
            _pc.show_blocking_message_time_pc("Char must be selected")
            return None

        return None

    def applyState(self, state):
        import unity_util


        global _pc
        char = get_selected_objs(_pc.game)
        if not char == None:
            char = char[0]
            #self.applyStateChar(char,state)
            #_pc.show_blocking_message_time_pc("Not implemented yet")

            if plXxpe.isDetected:
                #plXxpe.SetBlendShapesXML(char.objctrl, state)
                resFace = _pc.ffaces.applyState(state['face'])

                plXxpe.SetBlendShapesXML(char.objctrl, state['xxpexml'])

                return True
            else:
                _pc.show_blocking_message_time_pc("XXPE (KKPE, HSPE etc.) plugin not detected")
                return None


        else:
            _pc.show_blocking_message_time_pc("Char must be selected")
            return None

        return None

        # additional button


class PoseConsole():
    def __init__(self,game):
        # --- Some constants/strings ---
        self._normalwidth = 500
        self._normalheight = 350
        #self.drag_rect = Rect(0, 0, 10000, 50)
        self.options = Array[String](("Load screen","Save screen","Replace"))
        self.hoptions = Array[String](("Load screen","Save screen"))

        # --- Basic settings ---
        self.game = game
        self.originalwindowwidth = 0
        self.originalwindowheight = 0
        self.originalWindowCallback = None
        self.guiOnShow = False
        self.windowwidth = self._normalwidth
        self.windowheight = self._normalheight
        self.windowindex = 0

        # --- Colors ---
        self.col_grp = "#f442dc"
        self.col_pmatch = "#f9f9f9" #"#42f4f4"
        self.col_match = "#f4424e"
        self.col_loaded = self.col_match

        # --- Init UI data ---
        #self.fconsole = PoseConsoleUIData(basefold="sss/fposes/")
        #self.mconsole = PoseConsoleUIData(basefold="sss/mposes/")
        self.fconsole = UIDataFPoses()
        self.mconsole = UIDataMPoses()

        self.ffaces = UIDataFFaces()
        self.mfaces = UIDataMFaces()

        self.fstatus = UIDataFStatus()
        self.mstatus = UIDataMStatus()

        self.lhand = UIDataLHand()
        self.rhand = UIDataRHand()

        self.animechar = UIAnimeChar()
        self.animecharpose = UIAnimeCharPose()

        self.animeitem = UIAnimeProp()
        self.itemfk = UIDataPropFK()

        self.xxpelib = UIAnimeXXPE()

        # blocking message
        self.funcLockedText = "..."
        self.isFuncLocked = False

        self.skin = None

    # Blocking message functions
    def show_blocking_message(self, text="..."):
        self.funcLockedText = text
        self.isFuncLocked = True

    def hide_blocking_message(self, game=None):
        self.isFuncLocked = False

    def show_blocking_message_time_pc(self, text="...", duration=3):
        self.show_blocking_message(text)
        self.game.set_timer(duration, self.hide_blocking_message)

    #self.hconsole = HandConsoleUIData()

    # --- Additional modifiers ---
    #self.fk_exc = self.init_fkexclude()

    # def init_fkexclude(self):
    #     a = []
    #     for i in range(116,154):
    #         if not i == 122 and not i == 123:
    #             a.append(i)
    #     return (a)

# lib must be list      
def addItems(items, lib):
    for item in items:
        if item.lower() not in list(map(lambda x:x.lower(),lib)):
            lib.append(item)
    return lib

def init_from_sc(game):
    global _pc
    if _pc == None:
        _pc = PoseConsole(game)
    return _pc

def toggle_pose_console(p1="", p2=""):
    from vngameengine import tlbBtn_setColor,tlbBtn_VNGEPoseLib,tlbBtn_UpdateBtnColor,vnge_game
    from UnityEngine import Color
    game = vnge_game
    global _pc
    if _pc == None:
        _pc = PoseConsole(game)

    if newWndId == None:
        poseConsoleGUIStart(game)
        tlbBtn_UpdateBtnColor(tlbBtn_VNGEPoseLib,True)
    else:
        game.get_extra_window(newWndId).visible = not game.get_extra_window(newWndId).visible
        tlbBtn_UpdateBtnColor(tlbBtn_VNGEPoseLib, game.get_extra_window(newWndId).visible)

            # if _pc.guiOnShow:
    #     poseConsoleGUIClose()
    # else:
    #     poseConsoleGUIStart(game)

newWndId = None

def poseConsoleGUIStart(game):
    global newWndId
    if newWndId == None:
        #_pc.game_skin_saved = game.skin

        from skin_customwindow import SkinCustomWindow
        skin = SkinCustomWindow()
        skin.funcSetup = poseConsoleSkinSetup
        skin.funcWindowGUI = poseConsoleSkinWindowGUI
        _pc.skin = skin
        #game.skin_set(skin)
        newWndId = game.new_extra_window_skin(skin)

        _pc.guiOnShow = True




def poseConsoleSkinSetup(game):
    setWindowName(_pc.windowindex)
    #setWindowName(_pc.windowindex)
    game.windowName = "FPoses Library"

    from UnityEngine import GUI, Screen, Rect
    game.wwidth = _pc.windowwidth
    game.wheight = _pc.windowheight
    # #game.windowRect = Rect (Screen.width / 2 - game.wwidth / 2, Screen.height - game.wheight - 10, game.wwidth, game.wheight)

    x = get_ini_value_def_int("WindowX", Screen.width / 2 - game.wwidth * 1.5)
    y = get_ini_value_def_int("WindowY", Screen.height - game.wheight - 500)
    w = get_ini_value_def_int("WindowWidth", game.wwidth + 50)
    h = get_ini_value_def_int("WindowHeight", game.wheight + 400)

    # game.windowRect = Rect(Screen.width / 2 - game.wwidth * 1.5, Screen.height - game.wheight - 500,
    #                        game.wwidth + 50, game.wheight + 400)

    game.windowRect = Rect(x,y,w,h)

    #game.windowCallback = GUI.WindowFunction(scriptHelperWindowGUI)
    game.windowStyle = game.windowStyleDefault

def poseConsoleSkinWindowGUI(game,windowid):
    poseConsoleWindowFunc(windowid)

def poseConsoleGUIClose():
    global _pc

    global newWndId
    if newWndId != None:
        _pc.guiOnShow = False
        _pc.game.windowName = ""

    #_pc.game.skin_set(_pc.game_skin_saved)


# def setWindowName(index):
#     global _pc
#     names = {
#         0 : "FPoses",
#         1 : "MPoses",
#         2 : "FFaces",
#         3 : "MFaces"
#     }
#
#     if index in names.Keys:
#         _pc.windowindex = index
#         _pc.game.windowName = names[index]
#     else:
#         print "Invalid index:", index

def setWindowName(index,windowName=None):
    _pc.windowindex = index
    #print(windowName,_pc.skin,_pc.skin.windowName)
    if windowName != None:
        if _pc.skin != None:
            _pc.skin.controller.windowName = windowName+" Library"

def poseConsoleWindowFunc(windowid):
    global _pc
    #options = Array[String](("Load screen","Save screen","Replace"))
    try:
        poseConsoleUIFuncs()
    except Exception as e:
        import traceback
        print "PoseConsoleWindowGUI Exception:"
        traceback.print_exc()
        poseConsoleGUIClose()
        _pc.game.show_blocking_message_time("Pose console error: "+str(e))

def poseRenderButtons():
    GUILayout.BeginVertical()
    if GUILayout.Button("FPoses"):
        setWindowName(0,"FPoses")
    if GUILayout.Button("MPoses"):
        setWindowName(1,"MPoses")
    if GUILayout.Button("VNAnimeChar&Pose"):
        setWindowName(9,"VNAnimeChar&Pose")
    if GUILayout.Button("XXPE Faces&Shapes"):
        setWindowName(12,"XXPE Faces&Shapes")
    GUILayout.EndVertical()

    GUILayout.BeginVertical()
    if GUILayout.Button("FFaces"):
        setWindowName(2,"FFaces")
    if GUILayout.Button("MFaces"):
        setWindowName(3,"MFaces")
    if GUILayout.Button("VNAnimeChar"):
        setWindowName(8,"VNAnimeChar")
    GUILayout.EndVertical()

    GUILayout.BeginVertical()
    if GUILayout.Button("FStatus"):
        setWindowName(4,"FStatus")
    if GUILayout.Button("MStatus"):
        setWindowName(5,"MStatus")
    if GUILayout.Button("VNAnimeItem"):
        setWindowName(11,"VNAnimeItem")

    GUILayout.EndVertical()

    GUILayout.BeginVertical()
    if GUILayout.Button("Left hand"):
        setWindowName(6,"Left hand")
    if GUILayout.Button("Right hand"):
        setWindowName(7,"Right hand")
    if GUILayout.Button("Item FK"):
        setWindowName(10,"Item FK")

    GUILayout.EndVertical()

def poseConsoleUIFuncs():
    global _pc


    # global msg
    if _pc.isFuncLocked == True:
        GUILayout.BeginVertical()
        GUILayout.Space(10)
        GUILayout.BeginHorizontal()
        GUILayout.Space(10)
        GUILayout.Label("<size=20>"+_pc.funcLockedText+"</size>")
        # GUILayout.Label(_sc.funcLockedText)
        GUILayout.Space(10)
        GUILayout.EndHorizontal()
        GUILayout.Space(10)
        GUILayout.EndVertical()
        return

    options = _pc.options
    hoptions = _pc.hoptions

    GUILayout.BeginVertical()
    if _pc.windowindex == 0: #FPoses
        _pc.fconsole.toolbarInt = GUILayout.Toolbar(_pc.fconsole.toolbarInt,options)
        if _pc.fconsole.toolbarInt == 0: #Load
            _pc.fconsole = poseConsoleLoadWindow(_pc.fconsole)
        elif _pc.fconsole.toolbarInt == 1: #Save
            _pc.fconsole = poseConsoleSaveWindow(_pc.fconsole)
        elif _pc.fconsole.toolbarInt == 2: #Replace
            _pc.fconsole = poseConsoleReplaceWindow(_pc.fconsole)

        GUILayout.BeginHorizontal()
        poseRenderButtons()
        #if GUILayout.Button("Close window",GUILayout.Width(120)):
        #poseConsoleGUIClose()
        #toggle_pose_console()
        # elif GUILayout.Button("Hands"):
        #     setWindowName(2)
        GUILayout.EndHorizontal()


    elif _pc.windowindex == 1: #MPoses
        _pc.mconsole.toolbarInt = GUILayout.Toolbar(_pc.mconsole.toolbarInt,options)
        if _pc.mconsole.toolbarInt == 0: #Load
            _pc.mconsole = poseConsoleLoadWindow(_pc.mconsole)
        elif _pc.mconsole.toolbarInt == 1: #Save
            _pc.mconsole = poseConsoleSaveWindow(_pc.mconsole)
        elif _pc.mconsole.toolbarInt == 2: #Replace
            _pc.mconsole = poseConsoleReplaceWindow(_pc.mconsole)

        GUILayout.BeginHorizontal()
        poseRenderButtons()
        # elif GUILayout.Button("Hands"):
        #     setWindowName(2)
        #if GUILayout.Button("Close window",GUILayout.Width(120)):
        #GUILayout.Label("Go to SceneConsole tab and close...")
        #poseConsoleGUIClose()
        GUILayout.EndHorizontal()

    elif _pc.windowindex == 2:  # FFaces
        _pc.ffaces.toolbarInt = GUILayout.Toolbar(_pc.ffaces.toolbarInt, options)
        if _pc.ffaces.toolbarInt == 0:  # Load
            _pc.ffaces = poseConsoleLoadWindow(_pc.ffaces)
        elif _pc.ffaces.toolbarInt == 1:  # Save
            _pc.ffaces = poseConsoleSaveWindow(_pc.ffaces)
        elif _pc.ffaces.toolbarInt == 2:  # Replace
            _pc.ffaces = poseConsoleReplaceWindow(_pc.ffaces)

        GUILayout.BeginHorizontal()
        poseRenderButtons()
        GUILayout.EndHorizontal()

    elif _pc.windowindex == 3:  # MFaces
        _pc.mfaces.toolbarInt = GUILayout.Toolbar(_pc.mfaces.toolbarInt, options)
        if _pc.mfaces.toolbarInt == 0:  # Load
            _pc.mfaces = poseConsoleLoadWindow(_pc.mfaces)
        elif _pc.mfaces.toolbarInt == 1:  # Save
            _pc.mfaces = poseConsoleSaveWindow(_pc.mfaces)
        elif _pc.mfaces.toolbarInt == 2:  # Replace
            _pc.mfaces = poseConsoleReplaceWindow(_pc.mfaces)

        GUILayout.BeginHorizontal()
        poseRenderButtons()
        GUILayout.EndHorizontal()

    elif _pc.windowindex == 4:  # FStatus
        _pc.fstatus.toolbarInt = GUILayout.Toolbar(_pc.fstatus.toolbarInt, options)
        if _pc.fstatus.toolbarInt == 0:  # Load
            _pc.fstatus = poseConsoleLoadWindow(_pc.fstatus)
        elif _pc.fstatus.toolbarInt == 1:  # Save
            _pc.fstatus = poseConsoleSaveWindow(_pc.fstatus)
        elif _pc.fstatus.toolbarInt == 2:  # Replace
            _pc.fstatus = poseConsoleReplaceWindow(_pc.fstatus)

        GUILayout.BeginHorizontal()
        poseRenderButtons()
        GUILayout.EndHorizontal()

    elif _pc.windowindex == 5:  # MStatus
        _pc.mstatus.toolbarInt = GUILayout.Toolbar(_pc.mstatus.toolbarInt, options)
        if _pc.mstatus.toolbarInt == 0:  # Load
            _pc.mstatus = poseConsoleLoadWindow(_pc.mstatus)
        elif _pc.mstatus.toolbarInt == 1:  # Save
            _pc.mstatus = poseConsoleSaveWindow(_pc.mstatus)
        elif _pc.mstatus.toolbarInt == 2:  # Replace
            _pc.mstatus = poseConsoleReplaceWindow(_pc.mstatus)

        GUILayout.BeginHorizontal()
        poseRenderButtons()
        GUILayout.EndHorizontal()

    elif _pc.windowindex == 6:  # LHand
        _pc.lhand.toolbarInt = GUILayout.Toolbar(_pc.lhand.toolbarInt, options)
        if _pc.lhand.toolbarInt == 0:  # Load
            _pc.lhand = poseConsoleLoadWindow(_pc.lhand)
        elif _pc.lhand.toolbarInt == 1:  # Save
            _pc.lhand = poseConsoleSaveWindow(_pc.lhand)
        elif _pc.lhand.toolbarInt == 2:  # Replace
            _pc.lhand = poseConsoleReplaceWindow(_pc.lhand)

        GUILayout.BeginHorizontal()
        poseRenderButtons()
        GUILayout.EndHorizontal()

    elif _pc.windowindex == 7:  # RHand
        _pc.rhand.toolbarInt = GUILayout.Toolbar(_pc.rhand.toolbarInt, options)
        if _pc.rhand.toolbarInt == 0:  # Load
            _pc.rhand = poseConsoleLoadWindow(_pc.rhand)
        elif _pc.rhand.toolbarInt == 1:  # Save
            _pc.rhand = poseConsoleSaveWindow(_pc.rhand)
        elif _pc.rhand.toolbarInt == 2:  # Replace
            _pc.rhand = poseConsoleReplaceWindow(_pc.rhand)

        GUILayout.BeginHorizontal()
        poseRenderButtons()
        GUILayout.EndHorizontal()

    elif _pc.windowindex == 8:  # VNAnimeChar
        _pc.animechar.toolbarInt = GUILayout.Toolbar(_pc.animechar.toolbarInt, options)
        if _pc.animechar.toolbarInt == 0:  # Load
            _pc.animechar = poseConsoleLoadWindow(_pc.animechar)
        elif _pc.animechar.toolbarInt == 1:  # Save
            _pc.animechar = poseConsoleSaveWindow(_pc.animechar)
        elif _pc.animechar.toolbarInt == 2:  # Replace
            _pc.animechar = poseConsoleReplaceWindow(_pc.animechar)

        GUILayout.BeginHorizontal()
        poseRenderButtons()
        GUILayout.EndHorizontal()

    elif _pc.windowindex == 9:  # VNAnimeChar and Pose
        _pc.animecharpose.toolbarInt = GUILayout.Toolbar(_pc.animecharpose.toolbarInt, options)
        if _pc.animecharpose.toolbarInt == 0:  # Load
            _pc.animecharpose = poseConsoleLoadWindow(_pc.animecharpose)
        elif _pc.animecharpose.toolbarInt == 1:  # Save
            _pc.animecharpose = poseConsoleSaveWindow(_pc.animecharpose)
        elif _pc.animecharpose.toolbarInt == 2:  # Replace
            _pc.animecharpose = poseConsoleReplaceWindow(_pc.animecharpose)

        GUILayout.BeginHorizontal()
        poseRenderButtons()
        GUILayout.EndHorizontal()

    elif _pc.windowindex == 10:  # Item FK
        _pc.itemfk.toolbarInt = GUILayout.Toolbar(_pc.itemfk.toolbarInt, options)
        if _pc.itemfk.toolbarInt == 0:  # Load
            _pc.itemfk = poseConsoleLoadWindow(_pc.itemfk)
        elif _pc.itemfk.toolbarInt == 1:  # Save
            _pc.itemfk = poseConsoleSaveWindow(_pc.itemfk)
        elif _pc.itemfk.toolbarInt == 2:  # Replace
            _pc.itemfk = poseConsoleReplaceWindow(_pc.itemfk)

        GUILayout.BeginHorizontal()
        poseRenderButtons()
        GUILayout.EndHorizontal()

    elif _pc.windowindex == 11:  # VNAnime Item
        _pc.animeitem.toolbarInt = GUILayout.Toolbar(_pc.animeitem.toolbarInt, options)
        if _pc.animeitem.toolbarInt == 0:  # Load
            _pc.animeitem = poseConsoleLoadWindow(_pc.animeitem)
        elif _pc.animeitem.toolbarInt == 1:  # Save
            _pc.animeitem = poseConsoleSaveWindow(_pc.animeitem)
        elif _pc.animeitem.toolbarInt == 2:  # Replace
            _pc.animeitem = poseConsoleReplaceWindow(_pc.animeitem)

        GUILayout.BeginHorizontal()
        poseRenderButtons()
        GUILayout.EndHorizontal()

    elif _pc.windowindex == 12:  # XXPE Lib
        _pc.xxpelib.toolbarInt = GUILayout.Toolbar(_pc.xxpelib.toolbarInt, options)
        if _pc.xxpelib.toolbarInt == 0:  # Load
            _pc.xxpelib = poseConsoleLoadWindow(_pc.xxpelib)
        elif _pc.xxpelib.toolbarInt == 1:  # Save
            _pc.xxpelib = poseConsoleSaveWindow(_pc.xxpelib)
        elif _pc.xxpelib.toolbarInt == 2:  # Replace
            _pc.xxpelib = poseConsoleReplaceWindow(_pc.xxpelib)

        GUILayout.BeginHorizontal()
        poseRenderButtons()
        GUILayout.EndHorizontal()

    GUILayout.EndVertical()

def consoleRenderOneButton(console,name,grp,grp_name):
    global _pc
    if "tex2d" in console.lib[grp][name].keys():
        GUILayout.BeginHorizontal()
        txt = name
        if grp_name != "":
            txt = "%s\n<color=%s><b>%s</b></color>"%(name,_pc.col_grp,grp_name)
        if GUILayout.Button(txt,GUILayout.Height(90)):
            console.applyState(console.lib[grp][name]["pose"])
            console.prepReplace(name,grp) #Replace prep

        opts = (GUILayout.Width(160),GUILayout.Height(90))# will be applied as GUILayoutOption[], auto-converted
        if GUILayout.Button(console.lib[grp][name]["tex2d"],GUIStyle("label"),opts):
            console.applyState(console.lib[grp][name]["pose"])
            console.prepReplace(name,grp) #Replace prep
        GUILayout.EndHorizontal()

    else:
        if GUILayout.Button("%s  <color=%s><b>%s</b></color>"%(name,_pc.col_grp,grp_name)):
            console.applyState(console.lib[grp][name]["pose"])
            console.prepReplace(name,grp) #Replace prep

def poseConsoleLoadWindow(console):
    global _pc

    if not console.isFileInited: # later init
        console.initFromFiles()

    #if _pc.windowindex == 0:
    if isinstance(console.loaded_pose,tuple):
        GUILayout.Label("Search by:                                    <color=#ffbb99>(Last loaded: %s)</color>"%(console.loaded_pose[0]))
    else:
        GUILayout.Label("Search by:")
    GUILayout.BeginHorizontal()
    console.ldsearchstr = GUILayout.TextField(console.ldsearchstr,GUILayout.Width(330))

    console.ldbyTag = GUILayout.Toggle(console.ldbyTag,"Tag:",GUILayout.Width(80))
    console.ldbyGrp = GUILayout.Toggle(console.ldbyGrp,"Group:"+console.ldGroup,GUILayout.Width(120))
    GUILayout.EndHorizontal()

    GUILayout.BeginHorizontal()

    console.ldscrollPos = GUILayout.BeginScrollView(console.ldscrollPos,GUILayout.Width(350)) #,GUILayout.Width(250),GUILayout.Height(300))
    if console.ldGroup == "":
        for grp in sorted(console.lib.Keys):
            if grp == "None":
                grp_name = ""
            else:
                grp_name = grp
            for name in sorted(console.lib[grp]):
                if name.lower().startswith(console.ldsearchstr.lower()) and console.checkTags(grp, name):
                    consoleRenderOneButton(console,name,grp,grp_name)
                elif console.ldsearchstr == "" and console.checkTags(grp, name):
                    consoleRenderOneButton(console,name,grp,grp_name)
    else:
        grp = console.ldGroup
        if grp == "None":
            grp_name = ""
        else:
            grp_name = grp
        for name in sorted(console.lib[grp]):
            if name.lower().startswith(console.ldsearchstr.lower()) and console.checkTags(grp, name):
                consoleRenderOneButton(console,name,grp,grp_name)
            elif console.ldsearchstr == "" and console.checkTags(grp, name):
                consoleRenderOneButton(console,name,grp,grp_name)
    GUILayout.EndScrollView()


    GUILayout.BeginVertical()

    # If "Groups" toggle is on
    if console.ldbyGrp == True:

        console.ldgrpscrollpos = GUILayout.BeginScrollView(console.ldgrpscrollpos)
        if GUILayout.Button("None"):
            console.ldGroup = "None"
        for grp in sorted(console.lib.Keys):
            if not grp == "None":
                if GUILayout.Button(grp):
                    console.ldGroup = grp
        GUILayout.EndScrollView()
    elif console.ldbyGrp == False:
        console.ldGroup = ""

    # If "Tags" toggle is on
    if console.ldbyTag == True:
        if console.ldbyGrp == True:
            GUILayout.Space(20)
        console.ldTags = console.ldTagsBckup
        console.ldtagscrollpos = GUILayout.BeginScrollView(console.ldtagscrollpos)
        for i in range (0,len(console.taglib)):
            if i == 0 or i == 1: col = console.sptgcol
            else: col = console.nortgcol
            console.ldTagTgl[i] = GUILayout.Toggle(console.ldTagTgl[i],"<color=%s>%s</color>"%(col,console.taglib[i]))

            if (console.ldTagTgl[i] == True) and console.ldTags.count(console.taglib[i]) == 0:
                console.ldTags.append(console.taglib[i])
            elif (console.ldTagTgl[i] == False) and console.ldTags.count(console.taglib[i]) == 1:
                console.ldTags.remove(console.taglib[i])
        GUILayout.EndScrollView()
        console.ldTagsBckup = console.ldTags
    elif console.ldbyTag == False:
        console.ldTags = []

    GUILayout.EndVertical()
    GUILayout.EndHorizontal()
    #if GUILayout.Button("Save"):
    #savePose(console.ldsearchstr)

    return console

def poseConsoleSaveWindow(console):
    global _pc

    #if _pc.windowindex == 0:
    GUILayout.Label("Save as:")

    GUILayout.BeginHorizontal()
    GUILayout.Label("Name:",GUILayout.Width(60))
    console.svsearchstr = GUILayout.TextField(console.svsearchstr,GUILayout.Width(230))
    if GUILayout.Button("X", GUILayout.Width(20)):
        console.svsearchstr = ""
    if GUILayout.Button("Save"):
        console.savePose(console.svsearchstr,console.svtagstr,console.svgrpstr)
    GUILayout.EndHorizontal()

    GUILayout.BeginHorizontal()
    GUILayout.Label("with Tags:",GUILayout.Width(60))
    console.svtagstr = GUILayout.TextField(console.svtagstr,GUILayout.Width(230))
    if GUILayout.Button("X", GUILayout.Width(20)):
        console.svtagstr = ""
    if GUILayout.Button("Save w/ y-offset"):
        console.savePose(console.svsearchstr,console.svtagstr,console.svgrpstr,offset_flag = True)
    GUILayout.EndHorizontal()

    GUILayout.BeginHorizontal()
    GUILayout.Label("in Group:",GUILayout.Width(60))
    console.svgrpstr = GUILayout.TextField(console.svgrpstr,GUILayout.Width(230))
    if GUILayout.Button("X", GUILayout.Width(20)):
        console.svgrpstr = ""
    if console.isAddButton():
        if GUILayout.Button(console.addButtonText()):
            console.addButtonRun()

    GUILayout.EndHorizontal()

    GUILayout.BeginHorizontal()

    GUILayout.BeginVertical()
    GUILayout.Label("",GUILayout.Width(80)) #<b>Files:</b>
    console.svscrollPos = GUILayout.BeginScrollView(console.svscrollPos,GUILayout.Width(170)) #,GUILayout.Width(250),GUILayout.Height(300))
    for grp in sorted(console.lib.Keys):
        if grp == "None":
            for name in sorted(console.lib[grp]):
                if console.svsearchstr.lower() == name.lower():
                    GUILayout.Label("<color=%s><b>%s</b></color>"%(_pc.col_match,name))
                elif name.lower().startswith(console.svsearchstr.lower()):
                    GUILayout.Label("<color=%s>%s</color>"%(_pc.col_pmatch,name))
        else:
            for name in sorted(console.lib[grp]):
                if console.svsearchstr.lower() == name.lower():
                    GUILayout.Label("<color=%s><b>%s</b></color> <color=%s><b>(%s)</b></color>"%(_pc.col_match,name,_pc.col_grp,grp))
                elif name.lower().startswith(console.svsearchstr.lower()):
                    GUILayout.Label("<color=%s>%s</color><color=%s>(%s)</color>"%(_pc.col_pmatch,name,_pc.col_grp,grp))
    GUILayout.EndScrollView()
    GUILayout.EndVertical()

    GUILayout.BeginVertical()
    # Tags
    GUILayout.Label("Tags:",GUILayout.Width(120))
    console.svtagscrollpos = GUILayout.BeginScrollView(console.svtagscrollpos)
    for i in range (0,len(console.taglib)):
        if i == 0 or i == 1: col = console.sptgcol
        else: col = console.nortgcol
        console.svTagTgl[i] = GUILayout.Toggle(console.svTagTgl[i],"<color=%s>%s</color>"%(col,console.taglib[i]))
        """
        # Add tag to textfield
        if (console.svTagTgl[i] == True):
            if console.svtagstr == "":
                console.svtagstr = console.taglib[i]
            elif console.taglib[i] not in console.svtagstr:
                console.svtagstr = console.svtagstr + ", " + console.taglib[i]
        # Remove tag from textfield
        elif (", "+console.taglib[i]) in console.svtagstr:
            console.svtagstr = console.svtagstr.replace((", "+console.taglib[i]),"")
        elif (console.taglib[i]+", ") in console.svtagstr:
            console.svtagstr = console.svtagstr.replace((console.taglib[i]+", "),"")  
        elif (","+console.taglib[i]) in console.svtagstr:
            console.svtagstr = console.svtagstr.replace((","+console.taglib[i]),"")    
        elif (console.taglib[i]+",") in console.svtagstr:
            console.svtagstr = console.svtagstr.replace((console.taglib[i]+","),"")
        elif console.taglib[i] == console.svtagstr:
            console.svtagstr = console.svtagstr.replace(console.taglib[i],"")
        """
        # Add tag to textfield
        if (console.svTagTgl[i] == True):
            if console.svtagstr == "":
                console.svtagstr = console.taglib[i] + ", "
            elif console.taglib[i] not in console.svtagstr:
                if console.svtagstr.strip()[-1] == ",":
                    console.svtagstr = console.svtagstr + console.taglib[i] + ", "
                else:
                    console.svtagstr = console.svtagstr + ", " + console.taglib[i] + ", "
        # Remove tag from textfield
        elif (", "+console.taglib[i]+", ") in console.svtagstr:
            console.svtagstr = console.svtagstr.replace((console.taglib[i])+", ","")
        elif (", "+console.taglib[i]+",") in console.svtagstr:
            console.svtagstr = console.svtagstr.replace((console.taglib[i])+",","")
        elif console.svtagstr == console.taglib[i] + ", ":
            console.svtagstr = console.svtagstr.replace(console.taglib[i] + ", ","")
        elif console.svtagstr == console.taglib[i] + ",":
            console.svtagstr = console.svtagstr.replace(console.taglib[i] + ",","")
        elif console.svtagstr == console.taglib[i]:
            console.svtagstr = console.svtagstr.replace(console.taglib[i],"")
        elif len(console.svtagstr) > len(console.taglib[i]) + 2:
            if console.svtagstr[0:len(console.taglib[i])+2] == console.taglib[i] + ", ":
                console.svtagstr = console.svtagstr.replace(console.taglib[i] + ", ","")
            elif console.svtagstr[0:len(console.taglib[i])+1] == console.taglib[i] + ",":
                console.svtagstr = console.svtagstr.replace(console.taglib[i] + ",","")
    GUILayout.EndScrollView()
    if GUILayout.Button("Clear tags"):
        for i in range(0,len(console.svTagTgl)):
            console.svTagTgl[i] = False
        #for tgl in console.svTagTgl:
        #tgl = False
        console.svtagstr = ""
    GUILayout.EndVertical()
    GUILayout.BeginVertical()
    # Groups
    GUILayout.Label("Groups:",GUILayout.Width(130))
    console.svgrpscrollpos = GUILayout.BeginScrollView(console.svgrpscrollpos)
    if GUILayout.Button("None"):
        console.svgrpstr = ""
    for grp in sorted(console.lib.Keys):
        if not grp == "None":
            if GUILayout.Button(grp):
                console.svgrpstr = grp
    GUILayout.EndScrollView()
    GUILayout.EndVertical()

    GUILayout.EndHorizontal()



    return console

def poseConsoleReplaceWindow(console):
    global _pc


    if not console.loaded_pose == None:
        console.replaceInit()

        #if _pc.windowindex == 0:
        GUILayout.Label('Replace last loaded "<color=%s><b>%s</b></color>" with current pose:'%(_pc.col_loaded,console.loaded_pose[0]))

        GUILayout.BeginHorizontal()
        GUILayout.Label("Name:",GUILayout.Width(60))
        console.rep_searchstr = GUILayout.TextField(console.rep_searchstr,GUILayout.Width(220))
        if GUILayout.Button("Replace"):
            console.savePose(console.rep_searchstr,console.rep_tagstr,console.rep_grpstr, rep_loaded = console.rep_do)
        GUILayout.EndHorizontal()

        GUILayout.BeginHorizontal()
        GUILayout.Label("with Tags:",GUILayout.Width(60))
        console.rep_tagstr = GUILayout.TextField(console.rep_tagstr,GUILayout.Width(220))
        if GUILayout.Button("Replace w/ y-offset"):
            console.savePose(console.rep_searchstr,console.rep_tagstr,console.rep_grpstr,offset_flag = True, rep_loaded = console.rep_do)
        GUILayout.EndHorizontal()

        GUILayout.BeginHorizontal()
        GUILayout.Label("in Group:",GUILayout.Width(60))
        console.rep_grpstr = GUILayout.TextField(console.rep_grpstr,GUILayout.Width(220))
        GUILayout.EndHorizontal()

        GUILayout.BeginHorizontal()

        GUILayout.BeginVertical()
        GUILayout.Label("Files:",GUILayout.Width(80))
        console.rep_scrollPos = GUILayout.BeginScrollView(console.rep_scrollPos,GUILayout.Width(120)) #,GUILayout.Width(250),GUILayout.Height(300))
        for grp in sorted(console.lib.Keys):
            if grp == "None":
                for name in sorted(console.lib[grp]):
                    if console.rep_searchstr.lower() == name.lower():
                        GUILayout.Label("<color=%s><b>%s</b></color>"%(_pc.col_match,name))
                    elif name.lower().startswith(console.rep_searchstr.lower()):
                        GUILayout.Label("<color=%s><b>%s</b></color>"%(_pc.col_pmatch,name))
            else:
                for name in sorted(console.lib[grp]):
                    if console.rep_searchstr.lower() == name.lower():
                        GUILayout.Label("<color=%s><b>%s</b></color> <color=%s><b>(%s)</b></color>"%(_pc.col_match,name,_pc.col_grp,grp))
                    elif name.lower().startswith(console.rep_searchstr.lower()):
                        GUILayout.Label("<color=%s><b>%s</b></color><color=%s><b>(%s)</b></color>"%(_pc.col_pmatch,name,_pc.col_grp,grp))
        GUILayout.EndScrollView()
        GUILayout.EndVertical()

        GUILayout.BeginVertical()
        # Tags
        GUILayout.Label("Tags:",GUILayout.Width(120))
        console.rep_tagscrollpos = GUILayout.BeginScrollView(console.rep_tagscrollpos)
        for i in range (0,len(console.taglib)):
            if i == 0 or i == 1: col = console.sptgcol
            else: col = console.nortgcol
            console.rep_TagTgl[i] = GUILayout.Toggle(console.rep_TagTgl[i],"<color=%s>%s</color>"%(col,console.taglib[i]))
            # Add tag to textfield
            if (console.rep_TagTgl[i] == True):
                if console.rep_tagstr == "":
                    console.rep_tagstr = console.taglib[i] + ", "
                elif console.taglib[i] not in console.rep_tagstr:
                    if console.rep_tagstr.strip()[-1] == ",":
                        console.rep_tagstr = console.rep_tagstr + console.taglib[i] + ", "
                    else:
                        console.rep_tagstr = console.rep_tagstr + ", " + console.taglib[i] + ", "
            # Remove tag from textfield
            elif (", "+console.taglib[i]+", ") in console.rep_tagstr:
                console.rep_tagstr = console.rep_tagstr.replace((console.taglib[i])+", ","")
            elif (", "+console.taglib[i]+",") in console.rep_tagstr:
                console.rep_tagstr = console.rep_tagstr.replace((console.taglib[i])+",","")
            elif console.rep_tagstr == console.taglib[i] + ", ":
                console.rep_tagstr = console.rep_tagstr.replace(console.taglib[i] + ", ","")
            elif console.rep_tagstr == console.taglib[i] + ",":
                console.rep_tagstr = console.rep_tagstr.replace(console.taglib[i] + ",","")
            elif console.rep_tagstr == console.taglib[i]:
                console.rep_tagstr = console.rep_tagstr.replace(console.taglib[i],"")
            elif len(console.rep_tagstr) > len(console.taglib[i]) + 2:
                if console.rep_tagstr[0:len(console.taglib[i])+2] == console.taglib[i] + ", ":
                    console.rep_tagstr = console.rep_tagstr.replace(console.taglib[i] + ", ","")
                elif console.rep_tagstr[0:len(console.taglib[i])+1] == console.taglib[i] + ",":
                    console.rep_tagstr = console.rep_tagstr.replace(console.taglib[i] + ",","")
        GUILayout.EndScrollView()
        if GUILayout.Button("Clear tags"):
            for i in range(0,len(console.rep_TagTgl)):
                console.rep_TagTgl[i] = False
            #for tgl in console.rep_TagTgl:
            #tgl = False
            console.rep_tagstr = ""
        GUILayout.EndVertical()
        GUILayout.BeginVertical()
        # Groups
        GUILayout.Label("Groups:",GUILayout.Width(160))
        console.rep_grpscrollpos = GUILayout.BeginScrollView(console.rep_grpscrollpos)
        if GUILayout.Button("None"):
            console.svgrpstr = ""
        for grp in sorted(console.lib.Keys):
            if not grp == "None":
                if GUILayout.Button(grp):
                    console.svgrpstr = grp
        GUILayout.EndScrollView()
        GUILayout.EndVertical()

        GUILayout.EndHorizontal()

    else:
        GUILayout.FlexibleSpace()
        GUILayout.BeginHorizontal()
        GUILayout.FlexibleSpace()
        GUILayout.Label("Load a pose first!")
        GUILayout.FlexibleSpace()
        GUILayout.EndHorizontal()
        GUILayout.FlexibleSpace()


    return console

# Get selection
def get_selected_objs(game):
    mtreeman = game.studio.treeNodeCtrl
    ar = []
    for node in mtreeman.selectNodes:
        ochar = HSNeoOCI.create_from_treenode(node)
        #if 'oiCharInfo' in dir(ochar):
        if "as_actor" in dir(ochar):
            #if isinstance(ochar,OCIChar):
            ar.append(ochar.as_actor)

        """
        if isinstance(ochar,HSNeoOCIChar):
            ar.append(ActorSC(ochar.objctrl))
            #print "actor"
        else:
            ar.append(ochar.objctrl)
            #print "item"
        """

    if len(ar) == 0:
        return None
    return ar

def get_selected_props(game):
    mtreeman = game.studio.treeNodeCtrl
    ar = []
    for node in mtreeman.selectNodes:
        ochar = HSNeoOCI.create_from_treenode(node)
        #if 'oiCharInfo' in dir(ochar):
        if "as_prop" in dir(ochar):
            #if isinstance(ochar,OCIChar):
            ar.append(ochar.as_prop)

        """
        if isinstance(ochar,HSNeoOCIChar):
            ar.append(ActorSC(ochar.objctrl))
            #print "actor"
        else:
            ar.append(ochar.objctrl)
            #print "item"
        """

    if len(ar) == 0:
        return None
    return ar


# def applyState(state):
#     # if is_hsadvneo():
#     #     applyStateHSNeoAdv(state)
#     # else:
#     applyStateCross(state)


def applyStateNormal(state):
    global _pc
    char = get_selected_objs(_pc.game)
    if not char == None:
        char = char[0]
        if "move_to" in state:
            del state["move_to"]
        if "rotate_to" in state:
            del state["rotate_to"]
        if "scale_to" in state:
            del state["scale_to"]

        char.import_status(state)
        return True

    return None

def applyStateNormalProp(state):
    global _pc
    char = get_selected_props(_pc.game)
    if not char == None:
        char = char[0]
        if "move_to" in state:
            del state["move_to"]
        if "rotate_to" in state:
            del state["rotate_to"]
        if "scale_to" in state:
            del state["scale_to"]

        char.import_status(state)
        return True

    return None

def applyStateNormalDiffOpt(state):
    global _pc
    char = get_selected_objs(_pc.game)
    if not char == None:
        char = char[0]
        if "move_to" in state:
            del state["move_to"]
        if "rotate_to" in state:
            del state["rotate_to"]
        if "scale_to" in state:
            del state["scale_to"]

        char.import_status_diff_optimized(state)
        return True

    return None

# --- old functions from SceneConsole to apply hands --

# def applyStateLHand(state):
#     global _pc
#     char = get_selected_objs(_pc.game)
#     if not char == None:
#         char = char[0]
#
#         char.set_kinematic(state["kinematic"])
#         if state["kinematic"] == 0 or state["kinematic"] == 1:
#             cur_lhand = char.get_hand_ptn()
#             new_lhand = (state["hands"][0],cur_lhand[1])
#             char.set_hand_ptn(new_lhand)
#         if state["kinematic"] == 2 or state["kinematic"] == 3:
#             do_exist = False
#             lhand_keys = [i for i in range(37,52)]
#             #if lhand_keys <= state["fk_set"].keys():
#             lhand_fk = {}
#             for i in lhand_keys:
#                 if i in state["fk_set"].keys():
#                     lhand_fk[i] = state["fk_set"][i]
#                     do_exist = True
#             if do_exist == True:
#                 char.set_FK_active(group = 5, active = 1)
#                 char.import_fk_bone_info(lhand_fk)
#
#
# def applyStateRHand(state):
#     global _pc
#     char = get_selected_objs(_pc.game)
#     if not char == None:
#         char = char[0]
#
#         char.set_kinematic(state["kinematic"])
#         if state["kinematic"] == 0 or state["kinematic"] == 1:
#             cur_rhand = char.get_hand_ptn()
#             new_rhand = (state["hands"][1],cur_rhand[0])
#             char.set_hand_ptn(new_rhand)
#         if state["kinematic"] == 2 or state["kinematic"] == 3:
#             do_exist = False
#             rhand_keys = [i for i in range(22,37)]
#             #if rhand_keys <= state["fk_set"].keys():
#             rhand_fk = {}
#             for i in rhand_keys:
#                 if i in state["fk_set"].keys():
#                     rhand_fk[i] = state["fk_set"][i]
#                     do_exist = True
#             if do_exist == True:
#                 char.set_FK_active(group = 4, active = 1)
#                 char.import_fk_bone_info(rhand_fk)

# def applyStateCross(state, apply = None):
#     global _pc
#     char = get_selected_objs(_pc.game)
#     if not char == None:
#         char = char[0]
#         if apply == None:
#             apply = ["pose"]
#
#         if isinstance(apply, list):
#             # print "list"
#             if "move_to" in state:
#                 del state["move_to"]
#             if "rotate_to" in state:
#                 del state["rotate_to"]
#             if "scale_to" in state:
#                 del state["scale_to"]
#
#             char.import_status(state)

def excludeFK(dicFK, exc = None):
    # no correction for now
    return dicFK

    #
    correctedDicFK = {}
    if exc == None:
        global _pc
        exc = _pc.fk_exc
    for tgt in dicFK:
        if int(tgt) not in exc:
            #rot = Vector3(float(dicFK[tgt][0]),float(dicFK[tgt][1]),float(dicFK[tgt][2]))
            correctedDicFK[tgt] = dicFK[tgt]

    return correctedDicFK

def cleanKeys(dct):
    ndct = {}
    for key in dct.keys():
        ndct[int(key)] = dct[key]
    return ndct

# keitaro crossplatform elements
def is_hsadvneo():
    import extplugins
    return extplugins.ExtPlugin.exists("HSStudioNEOAddon")


# config ini values
# ini file

_iniOptions = None

def get_ini_value(elem): # get ini value for cur engine
    global _iniOptions
    if _iniOptions != None:
        # already parsed
        pass
    else:
        # need to parse and cache
        _iniOptions = {}

        import ConfigParser, sys, os.path
        config = ConfigParser.SafeConfigParser()
        config.read(os.path.splitext(__file__)[0] + '_config.ini')

        for k, v in config.items("Options"):
            _iniOptions[k.lower()] = v


    # main code
    #print _iniOptions
    elemlower = elem.lower()
    if elemlower in _iniOptions:
        return _iniOptions[elemlower]

    return None

def get_ini_value_def_int(elem,defint):
    val = get_ini_value(elem)
    if val == None:
        return defint
    else:
        val2 = int(val)
        if val2 == -1:
            return defint
        else:
            return val2

def is_ini_value_true(elem):
    val = get_ini_value(elem)
    if val != None and val != 0 and val != "0":
        return True
    return False