import os, time
from xml.dom import minidom
import c4d
from ssp_utils_c4d_version import *
from ssp_ids import *
from ssp_utils_pref import *
from ssp_dialog_ask_session_name import *


def GetScenesContainer(idxSession, idBc):
    bc = None

    if idxSession == -1:
        bc = GetPrefsContainer(idBc)

    else:
        bcSessions = GetSessionsContainer()
        numSessions = bcSessions.GetInt32(BCSESSIONS_NUM_SESSIONS, 0)

        if idxSession >= 0 and idxSession < numSessions:
            idBaseNewSession = idxSession * BCSESSIONS_SESSION_OFFSET
            bc = bcSessions.GetContainer(idBaseNewSession + idBc)

    return bc


def GetScenes(idxSession=-1):
    return GetScenesContainer(idxSession, BCID_BC_SCENES)

def SetScenes(bc):
    SetPrefsContainer(BCID_BC_SCENES, bc)


def GetScenesFavorite(idxSession=-1):
    return GetScenesContainer(idxSession, BCID_BC_SCENES_FAVORITES)

def SetScenesFavorite(bc):
    SetPrefsContainer(BCID_BC_SCENES_FAVORITES, bc)


def GetScenesReopen(idxSession=-1):
    return GetScenesContainer(idxSession, BCID_BC_SCENES_REOPEN)

def SetScenesReopen(bc):
    SetPrefsContainer(BCID_BC_SCENES_REOPEN, bc)


def GetScenesNames(idxSession=-1):
    return GetScenesContainer(idxSession, BCID_BC_SCENES_NAMES)

def SetScenesNames(bc):
    SetPrefsContainer(BCID_BC_SCENES_NAMES, bc)


def GetScenesIsSaved(idxSession=-1):
    return GetScenesContainer(idxSession, BCID_BC_SCENES_IS_SAVED)

def SetScenesIsSaved(bc):
    SetPrefsContainer(BCID_BC_SCENES_IS_SAVED, bc)


def GetScenesIsActive(idxSession=-1):
    return GetScenesContainer(idxSession, BCID_BC_SCENES_IS_ACTIVE)

def SetScenesIsActive(bc):
    SetPrefsContainer(BCID_BC_SCENES_IS_ACTIVE, bc)


def GetSessionsContainer():
    return GetPrefsContainer(BCID_BC_SESSIONS)

def SetSessionsContainer(bc):
    SetPrefsContainer(BCID_BC_SESSIONS, bc)


def PrintSceneData():
    bcScenes = GetScenes()
    bcScenesNames = GetScenesNames()
    bcScenesFavorites = GetScenesFavorite()
    bcScenesReopen = GetScenesReopen()
    bcScenesIsSaved = GetScenesIsSaved()
    bcScenesIsActive = GetScenesIsActive()

    for idDoc, pathDocFull in bcScenes:
        print('{0}: Favorite: {1}, Reopen: {2}, Saved: {3}, Active: {4}'.format(bcScenesNames[idDoc], bcScenesFavorites[idDoc], bcScenesReopen[idDoc], bcScenesIsSaved[idDoc], bcScenesIsActive[idDoc]))
        print('    {0}'.format(pathDocFull))


def DocNameAndFullPath(pathDoc, nameDoc):
    if pathDoc[:9] == 'preset://':
        pathDocFull = pathDoc + '/' + nameDoc

    else:
        pathDocFull = os.path.join(pathDoc, nameDoc)

    return pathDocFull


def GetDocumentPathFull(doc):
    pathDoc = doc.GetDocumentPath()
    nameDoc = doc.GetDocumentName()
    pathDocFull = DocNameAndFullPath(pathDoc, nameDoc)
    docCheckDuplicate = c4d.documents.GetFirstDocument()
    idxDocFromSameFile = 0

    while docCheckDuplicate is not None:
        if docCheckDuplicate == doc:
            break

        pathDocCheckDuplicate = docCheckDuplicate.GetDocumentPath()
        nameDocCheckDuplicate = docCheckDuplicate.GetDocumentName()
        pathDocFullDuplicate = DocNameAndFullPath(pathDocCheckDuplicate, nameDocCheckDuplicate)

        if pathDocFullDuplicate == pathDocFull:
            idxDocFromSameFile += 1

        docCheckDuplicate = docCheckDuplicate.GetNext()

    idDoc = MyHash(pathDocFull + '_' + str(idxDocFromSameFile))
    isSaved = False

    if len(pathDoc) > 0:
        isSaved = True

    return pathDocFull, idDoc, nameDoc, isSaved


def SessionStore(name, bcSessions=None):
    if bcSessions is None:
        bcSessions = GetSessionsContainer()

    numSessions = bcSessions.GetInt32(BCSESSIONS_NUM_SESSIONS, 0)
    idBaseNewSession = numSessions * BCSESSIONS_SESSION_OFFSET

    bcScenes = GetScenes()
    bcSessions.SetContainer(idBaseNewSession + BCID_BC_SCENES, bcScenes)

    bcScenesNames = GetScenesNames()
    bcSessions.SetContainer(idBaseNewSession + BCID_BC_SCENES_NAMES, bcScenesNames)

    bcScenesFavorites = GetScenesFavorite()
    bcSessions.SetContainer(idBaseNewSession + BCID_BC_SCENES_FAVORITES, bcScenesFavorites)

    bcScenesReopen = GetScenesReopen()
    bcSessions.SetContainer(idBaseNewSession + BCID_BC_SCENES_REOPEN, bcScenesReopen)

    bcScenesIsSaved = GetScenesIsSaved()
    bcSessions.SetContainer(idBaseNewSession + BCID_BC_SCENES_IS_SAVED, bcScenesIsSaved)

    bcScenesIsActive = GetScenesIsActive()
    bcSessions.SetContainer(idBaseNewSession + BCID_BC_SCENES_IS_ACTIVE, bcScenesIsActive)

    bcSessions.SetString(idBaseNewSession + BCID_STRING_SESSION_NAME, name)
    bcSessions.SetInt32(BCSESSIONS_NUM_SESSIONS, numSessions + 1)


def SessionGetSessions():
    bcSessions = GetSessionsContainer()
    numSessions = bcSessions.GetInt32(BCSESSIONS_NUM_SESSIONS, 0)
    sessions = []

    for idxSession in range(numSessions):
        idBaseSession = idxSession * BCSESSIONS_SESSION_OFFSET
        nameSession = bcSessions.GetString(idBaseSession + BCID_STRING_SESSION_NAME, 'ERROR')

        sessions.append(nameSession)

    return sessions


def SessionOpenStoredSession(idxSession):
    bcSessions = GetSessionsContainer()
    numSessions = bcSessions.GetInt32(BCSESSIONS_NUM_SESSIONS, 0)

    if idxSession < 0 or idxSession >= numSessions:
        return

    idBaseNewSession = idxSession * BCSESSIONS_SESSION_OFFSET

    bcScenes = bcSessions.GetContainer(idBaseNewSession + BCID_BC_SCENES)
    bcScenesIsSaved = bcSessions.GetContainer(idBaseNewSession + BCID_BC_SCENES_IS_SAVED)
    bcScenesIsActive = bcSessions.GetContainer(idBaseNewSession + BCID_BC_SCENES_IS_ACTIVE)

    docActive = None

    for idDoc, pathDocFull in bcScenes:
        if not bcScenesIsSaved[idDoc]:
            continue

        doc = c4d.documents.LoadDocument(pathDocFull, c4d.SCENEFILTER_OBJECTS | c4d.SCENEFILTER_MATERIALS)
        if doc is None:
            print('{0} ERROR: Failed to load document: {1}'.format(PLUGIN_NAME, pathDocFull))
            continue

        c4d.documents.InsertBaseDocument(doc)

        if bcScenesIsActive[idDoc]:
            docActive = doc

    if docActive is not None:
        c4d.documents.SetActiveDocument(docActive)


def SessionGetName(idxSession):
    bcSessions = GetSessionsContainer()
    numSessions = bcSessions.GetInt32(BCSESSIONS_NUM_SESSIONS, 0)

    if idxSession < 0 or idxSession >= numSessions:
        return

    idBaseNewSession = idxSession * BCSESSIONS_SESSION_OFFSET

    return bcSessions.GetString(idBaseNewSession + BCID_STRING_SESSION_NAME)


def AskSessionName(idxSession, nameDefault=None, titleAddition='Add Session'):
    title = '{0} - {1}...'.format(PLUGIN_NAME, titleAddition)

    if nameDefault is None:
        nameDefault = 'Session {0}'.format(idxSession)

    dlgInput = DialogAskSessionName(title, nameDefault)
    dlgInput.Open(c4d.DLG_TYPE_MODAL)

    result, nameSession = dlgInput.GetResult()
    if not result or nameSession is None or len(nameSession) <= 0:
        return False, ''

    return True, nameSession


def SessionToXML(bcSessions, idxSession, xmlDoc, xmlNodeSessions):
    idBaseSession = idxSession * BCSESSIONS_SESSION_OFFSET

    nameSession = bcSessions.GetString(idBaseSession + BCID_STRING_SESSION_NAME, 'SESSION WITHOUT NAME')

    xmlNodeSession = xmlDoc.createElement('Session')

    xmlNodeSession.setAttribute('name', nameSession)

    xmlNodeSessions.appendChild(xmlNodeSession)

    bcScenesIsSaved = bcSessions.GetContainerInstance(idBaseSession + BCID_BC_SCENES_IS_SAVED)

    bcScenes = bcSessions.GetContainerInstance(idBaseSession + BCID_BC_SCENES)
    bcScenesNames = bcSessions.GetContainerInstance(idBaseSession + BCID_BC_SCENES_NAMES)
    bcScenesReopen = bcSessions.GetContainerInstance(idBaseSession + BCID_BC_SCENES_REOPEN)
    bcScenesIsActive = bcSessions.GetContainerInstance(idBaseSession + BCID_BC_SCENES_IS_ACTIVE)
    bcScenesFavorites = bcSessions.GetContainerInstance(idBaseSession + BCID_BC_SCENES_FAVORITES)

    for idDoc, isSaved in bcScenesIsSaved:
        if not isSaved:
            continue

        pathDoc = bcScenes.GetString(idDoc)
        nameScene = bcScenesNames.GetString(idDoc)
        isFavorite = str(bcScenesFavorites.GetBool(idDoc))
        reopen = str(bcScenesReopen.GetBool(idDoc))
        isActive = str(bcScenesIsActive.GetBool(idDoc))

        xmlNodeScene = xmlDoc.createElement('Project')

        xmlNodeScene.setAttribute('path', pathDoc)
        xmlNodeScene.setAttribute('name', nameScene)
        xmlNodeScene.setAttribute('reopen', reopen)
        xmlNodeScene.setAttribute('active', isActive)
        xmlNodeScene.setAttribute('favorite', isFavorite)

        xmlNodeSession.appendChild(xmlNodeScene)


def ExportSessions(bcSessions, idxSession=-1):
    versionMajorC4D = c4d.GetC4DVersion() // 1000

    numSessions = bcSessions.GetInt32(BCSESSIONS_NUM_SESSIONS, 0)

    if idxSession == -1:
        tNow = time.localtime()

        nameSessionXML = 'C4D_R{0}_Sessions_{1}{2:02}{3:02}_{4:02}{5:02}.xml'.format(versionMajorC4D, tNow.tm_year, tNow.tm_mon, tNow.tm_mday, tNow.tm_hour, tNow.tm_min)

    else:
        if idxSession >= numSessions:
            return

        idBaseSession = idxSession * BCSESSIONS_SESSION_OFFSET

        nameSessionXML = bcSessions.GetString(idBaseSession + BCID_STRING_SESSION_NAME, 'ERROR') + '.xml'

    titleDlgSave = 'Save Session(s) as...'

    if versionMajorC4D >= 18:
        pathSessionsXML = c4d.storage.SaveDialog(type=c4d.FILESELECTTYPE_ANYTHING,  title=titleDlgSave, force_suffix='xml', def_file=nameSessionXML)

    else:
        pathSessionsXML = c4d.storage.SaveDialog(type=c4d.FILESELECTTYPE_ANYTHING,  title=titleDlgSave, force_suffix='xml')

    if pathSessionsXML is None or len(pathSessionsXML) <= 2:
        return

    xmlDoc = minidom.Document()

    xmlNodeSessions = xmlDoc.createElement('Sessions')

    xmlDoc.appendChild(xmlNodeSessions)

    if idxSession == -1:
        rngSessions = range(numSessions)

    else:
        rngSessions = range(idxSession, idxSession+1)

    for idx in rngSessions:
        SessionToXML(bcSessions, idx, xmlDoc, xmlNodeSessions)

    with open(pathSessionsXML, 'w') as fp:
        success = xmlDoc.writexml(fp, addindent='\t', newl='\n')


def GetSessionIdx(bcSessions, nameSession):
    numSessions = bcSessions.GetInt32(BCSESSIONS_NUM_SESSIONS, 0)

    for idxSession in range(numSessions):
        idBaseSession = idxSession * BCSESSIONS_SESSION_OFFSET

        nameSessionTest = bcSessions.GetString(idBaseSession + BCID_STRING_SESSION_NAME, 'ERROR')

        if nameSession == nameSessionTest:
            return idxSession

    return None


def SessionStoreEmpty(bcSessions, name):
    numSessions = bcSessions.GetInt32(BCSESSIONS_NUM_SESSIONS, 0)

    idBaseNewSession = numSessions * BCSESSIONS_SESSION_OFFSET

    bcSessions.SetContainer(idBaseNewSession + BCID_BC_SCENES, c4d.BaseContainer())
    bcSessions.SetContainer(idBaseNewSession + BCID_BC_SCENES_NAMES, c4d.BaseContainer())
    bcSessions.SetContainer(idBaseNewSession + BCID_BC_SCENES_FAVORITES, c4d.BaseContainer())
    bcSessions.SetContainer(idBaseNewSession + BCID_BC_SCENES_REOPEN, c4d.BaseContainer())
    bcSessions.SetContainer(idBaseNewSession + BCID_BC_SCENES_IS_SAVED, c4d.BaseContainer())
    bcSessions.SetContainer(idBaseNewSession + BCID_BC_SCENES_IS_ACTIVE, c4d.BaseContainer())

    bcSessions.SetString(idBaseNewSession + BCID_STRING_SESSION_NAME, name)

    bcSessions.SetInt32(BCSESSIONS_NUM_SESSIONS, numSessions + 1)


def AddSessionFromXML(xmlNodeSession, bcSessions):
    nameSession = xmlNodeSession.getAttribute('name')

    if GetSessionIdx(bcSessions, nameSession) is not None:
        sMsg = 'A Session "{0}" already exists.\n\n'.format(nameSession)
        sMsg += 'Merge imported session?\n\n'
        sMsg += 'Yes: Merge imported session into existing session\n'
        sMsg += 'No:  Create a new session\n'
        sMsg += 'Cancel: Abort'
        result = c4d.gui.MessageDialog(sMsg, c4d.GEMB_YESNOCANCEL | c4d.GEMB_ICONQUESTION)
        if result == c4d.GEMB_R_CANCEL:
            return

        elif result == c4d.GEMB_R_NO:
            cnt = 0

            nameTest = nameSession

            while GetSessionIdx(bcSessions, nameTest) is not None:
                cnt += 1
                nameTest = '{0}_{1:02}'.format(nameSession, cnt)

            nameSession = nameTest

    idxSession = GetSessionIdx(bcSessions, nameSession)

    merge = True

    if idxSession is None:
        idxSession = bcSessions.GetInt32(BCSESSIONS_NUM_SESSIONS, 0)

        SessionStoreEmpty(bcSessions, nameSession)

        merge = False

    xmlNodesProject = xmlNodeSession.getElementsByTagName('Project')

    if xmlNodesProject is None or len(xmlNodesProject) <= 0:
        return

    idBaseSession = idxSession * BCSESSIONS_SESSION_OFFSET

    nameSessionTarget = bcSessions.GetString(idBaseSession + BCID_STRING_SESSION_NAME, 'ERROR')

    bcScenes = bcSessions.GetContainerInstance(idBaseSession + BCID_BC_SCENES)
    bcScenesNames = bcSessions.GetContainerInstance(idBaseSession + BCID_BC_SCENES_NAMES)
    bcScenesReopen = bcSessions.GetContainerInstance(idBaseSession + BCID_BC_SCENES_REOPEN)
    bcScenesIsActive = bcSessions.GetContainerInstance(idBaseSession + BCID_BC_SCENES_IS_ACTIVE)
    bcScenesFavorites = bcSessions.GetContainerInstance(idBaseSession + BCID_BC_SCENES_FAVORITES)
    bcScenesIsSaved = bcSessions.GetContainerInstance(idBaseSession + BCID_BC_SCENES_IS_SAVED)

    for xmlNodeProject in xmlNodesProject:
        pathDoc = xmlNodeProject.getAttribute('path')

        idDoc = MyHash(pathDoc + '_0')

        if bcScenes.FindIndex(idDoc)['index'] != -1:
            continue

        found = False

        for idDocTest, pathDocTest in bcScenes:
            if pathDocTest == pathDoc:
                found = True
                break

        if found:
            continue

        idDoc = MyHash(pathDoc + '_0')

        nameDoc = xmlNodeProject.getAttribute('name')
        reopen = xmlNodeProject.getAttribute('reopen') == 'True'
        isActive = not merge and xmlNodeProject.getAttribute('active') == 'True' # on merge, there already is an active project
        isFavorite = xmlNodeProject.getAttribute('favorite') == 'True'

        bcScenes.SetString(idDoc, pathDoc)
        bcScenesNames.SetString(idDoc, nameDoc)
        bcScenesReopen.SetBool(idDoc, reopen)
        bcScenesIsActive.SetBool(idDoc, isActive)
        bcScenesFavorites.SetBool(idDoc, isFavorite)
        bcScenesIsSaved.SetBool(idDoc, True)


def ImportSessions(bcSessions):
    pathSessionsXML = c4d.storage.LoadDialog(type=c4d.FILESELECTTYPE_ANYTHING,  title='Import Session(s)...', flags=c4d.FILESELECT_LOAD, force_suffix='xml')

    if pathSessionsXML is None or len(pathSessionsXML) <= 2:
        return

    if not os.path.exists(pathSessionsXML):
        return

    with open(pathSessionsXML) as fp:
        xmlDoc = minidom.parseString(fp.read())

    xmlNodesSession = xmlDoc.getElementsByTagName('Session')

    if xmlNodesSession is None or len(xmlNodesSession) <= 0:
        return

    for xmlNodeSession in xmlNodesSession:
         AddSessionFromXML(xmlNodeSession, bcSessions)


def CreateDefaultRenderData(doc, xres, yres, doInsert=True):
    rd = doc.GetFirstRenderData()

    while rd is not None:
        if rd.GetName() == NAME_THUMB_RENDERDATA:
            break

        rd = rd.GetNext()

    if rd is None:
        rd = c4d.documents.RenderData()

        if rd is None:
            print('{0} ERROR: Failed to create render settings'.format(PLUGIN_NAME))
            return None

        rd.SetName(NAME_THUMB_RENDERDATA)

        if doInsert:
            doc.InsertRenderDataLast(rd)

    vp = rd.GetFirstVideoPost()

    while vp is not None:
        if vp.GetType() == c4d.RDATA_RENDERENGINE_PREVIEWHARDWARE:
            break

        vp = vp.GetNext()

    if vp is None:
        vp = c4d.BaseList2D(c4d.RDATA_RENDERENGINE_PREVIEWHARDWARE)

        if vp is None:
            print('{0} ERROR: Failed to create Preview Hardware Render VideoPost'.format(PLUGIN_NAME))
            return None

        rd.InsertVideoPostLast(vp)

    vp[c4d.VP_PREVIEWHARDWARE_ENHANCEDOPENGL] = True
    vp[c4d.VP_PREVIEWHARDWARE_TRANSPARENCY] = True
    vp[c4d.VP_PREVIEWHARDWARE_SHADOW] = True
    vp[c4d.VP_PREVIEWHARDWARE_POSTEFFECT] = True
    vp[c4d.VP_PREVIEWHARDWARE_NOISE] = True

    if c4d.GetC4DVersion() >= 18000:
        vp[c4d.VP_PREVIEWHARDWARE_TESSELLATION] = False
        vp[c4d.VP_PREVIEWHARDWARE_SSAO] = True
        vp[c4d.VP_PREVIEWHARDWARE_REFLECTIONS] = True

    if c4d.GetC4DVersion() >= 19000:
        vp[c4d.VP_PREVIEWHARDWARE_DEPTHOFFIELD] = True

    vp[c4d.VP_PREVIEWHARDWARE_ANTIALIASING] = 8

    if GetPrefThumbFilter() and c4d.GetC4DVersion() >= 22000:
        vp[c4d.VP_PREVIEWHARDWARE_DISPLAYFILTER_MULTIAXIS] = False
        vp[c4d.VP_PREVIEWHARDWARE_DISPLAYFILTER_OBJECTHANDLES] = False
        vp[c4d.VP_PREVIEWHARDWARE_DISPLAYFILTER_WORLDAXIS] = False
        vp[c4d.VP_PREVIEWHARDWARE_DISPLAYFILTER_HUD] = False
        vp[c4d.VP_PREVIEWHARDWARE_DISPLAYFILTER_BASEGRID] = False
        vp[c4d.VP_PREVIEWHARDWARE_DISPLAYFILTER_GRID] = False
        vp[c4d.VP_PREVIEWHARDWARE_DISPLAYFILTER_HANDLES] = False
        vp[c4d.VP_PREVIEWHARDWARE_DISPLAYFILTER_HORIZON] = False

    rd[c4d.RDATA_RENDERENGINE] = c4d.RDATA_RENDERENGINE_PREVIEWHARDWARE
    rd[c4d.RDATA_XRES] = xres
    rd[c4d.RDATA_YRES] = yres

    return rd


def GetSSPRenderData(doc, xresDefault, yresDefault):
    rd = doc.GetFirstRenderData()

    while rd is not None:
        if rd.GetName() == NAME_THUMB_RENDERDATA:
            break

        rd = rd.GetNext()

    if rd is None:
        rd = CreateDefaultRenderData(doc, xresDefault, yresDefault, False)

    return rd


def StoreViewportFilter(bd):
    bc = c4d.BaseContainer()

    bc[c4d.BASEDRAW_DISPLAYFILTER_MULTIAXIS] = bd[c4d.BASEDRAW_DISPLAYFILTER_MULTIAXIS]
    bc[c4d.BASEDRAW_DISPLAYFILTER_OBJECTHANDLES] = bd[c4d.BASEDRAW_DISPLAYFILTER_OBJECTHANDLES]
    bc[c4d.BASEDRAW_DISPLAYFILTER_OBJECTHIGHLIGHTING] = bd[c4d.BASEDRAW_DISPLAYFILTER_OBJECTHIGHLIGHTING]
    bc[c4d.BASEDRAW_DISPLAYFILTER_WORLDAXIS] = bd[c4d.BASEDRAW_DISPLAYFILTER_WORLDAXIS]
    bc[c4d.BASEDRAW_DISPLAYFILTER_HUD] = bd[c4d.BASEDRAW_DISPLAYFILTER_HUD]
    bc[c4d.BASEDRAW_DISPLAYFILTER_BASEGRID] = bd[c4d.BASEDRAW_DISPLAYFILTER_BASEGRID]
    bc[c4d.BASEDRAW_DISPLAYFILTER_GRID] = bd[c4d.BASEDRAW_DISPLAYFILTER_GRID]
    bc[c4d.BASEDRAW_DISPLAYFILTER_HANDLES] = bd[c4d.BASEDRAW_DISPLAYFILTER_HANDLES]

    return bc


def RestoreViewportFilter(bd, bc):
    bd[c4d.BASEDRAW_DISPLAYFILTER_MULTIAXIS] = bc[c4d.BASEDRAW_DISPLAYFILTER_MULTIAXIS]
    bd[c4d.BASEDRAW_DISPLAYFILTER_OBJECTHANDLES] = bc[c4d.BASEDRAW_DISPLAYFILTER_OBJECTHANDLES]
    bd[c4d.BASEDRAW_DISPLAYFILTER_OBJECTHIGHLIGHTING] = bc[c4d.BASEDRAW_DISPLAYFILTER_OBJECTHIGHLIGHTING]
    bd[c4d.BASEDRAW_DISPLAYFILTER_WORLDAXIS] = bc[c4d.BASEDRAW_DISPLAYFILTER_WORLDAXIS]
    bd[c4d.BASEDRAW_DISPLAYFILTER_HUD] = bc[c4d.BASEDRAW_DISPLAYFILTER_HUD]
    bd[c4d.BASEDRAW_DISPLAYFILTER_BASEGRID] = bc[c4d.BASEDRAW_DISPLAYFILTER_BASEGRID]
    bd[c4d.BASEDRAW_DISPLAYFILTER_GRID] = bc[c4d.BASEDRAW_DISPLAYFILTER_GRID]
    bd[c4d.BASEDRAW_DISPLAYFILTER_HANDLES] = bc[c4d.BASEDRAW_DISPLAYFILTER_HANDLES]


def CheckSwitchShortcutIsFree(idxShortcutSwitch):
    idPlugin = PLUGIN_IDS_SWITCH[idxShortcutSwitch]

    idManager = PLUGIN_ID_MANAGER
    if REGISTER_SHORTCUTS_GLOBALLY:
        idManager = 0

    qualifier0 = SWITCH_DEFAULT_QUALIFIER_L0
    key0 = SWITCH_DEFAULT_KEY_L0

    qualifier1 = 0
    key1 = SWITCH_DEFAULT_KEY_SELECT[idxShortcutSwitch]

    for idxShortcut in range(c4d.gui.GetShortcutCount()):
        bcShortcut = c4d.gui.GetShortcut(idxShortcut)


        if idPlugin == bcShortcut[c4d.SHORTCUT_PLUGINID]:
            #sShortCut = SwitchShortcutToString(idxShortcutSwitch)
            #print('{0}: Shortcut {1} is already in use by us'.format(PLUGIN_NAME, sShortCut))

            return False # Already registered, actual keys may have been changed by user

        elif bcShortcut[0] == qualifier0 and bcShortcut[1] == key0 and bcShortcut[10] == qualifier1 and bcShortcut[11] == key1:
            sShortCut = SwitchShortcutToString(idxShortcutSwitch)
            print('{0}: Shortcut {1} is already used for command ID: {2}'.format(PLUGIN_NAME, sShortCut, bcShortcut[c4d.SHORTCUT_PLUGINID]))

            return False

    return True


def RegisterSwitchShortcut(idxShortcut):
    if idxShortcut >= len(PLUGIN_IDS_SWITCH):
        return False

    idManager = PLUGIN_ID_MANAGER
    if REGISTER_SHORTCUTS_GLOBALLY:
        idManager = 0

    bcShortcut = c4d.BaseContainer()

    bcShortcut.SetInt32(c4d.SHORTCUT_PLUGINID, PLUGIN_IDS_SWITCH[idxShortcut])
    bcShortcut.SetInt32(c4d.SHORTCUT_ADDRESS, idManager)
    bcShortcut.SetBool(c4d.SHORTCUT_OPTIONMODE, True) # Note: We use option mode for these, so we get passed the actual plugin ID
    bcShortcut.SetInt32(0, SWITCH_DEFAULT_QUALIFIER_L0)
    bcShortcut.SetInt32(1, SWITCH_DEFAULT_KEY_L0)
    bcShortcut.SetInt32(10, 0)
    bcShortcut.SetInt32(11, SWITCH_DEFAULT_KEY_SELECT[idxShortcut])

    result = c4d.gui.AddShortcut(bcShortcut)
    sShortcut = SwitchShortcutToString(idxShortcut)
    if not result:
        print('{0} ERROR: Failed to register Switch Shortcut ({1})'.format(PLUGIN_NAME, sShortcut))

    #else:
    #    print('{0}: Registered Switch Shortcut ({1})'.format(PLUGIN_NAME, sShortcut))

    return result


# For use in cases developer sucked!
def RemoveSwitchShortcut(idxSwitch):
    if idxSwitch >= len(PLUGIN_IDS_SWITCH):
        return ''

    idPlugin = PLUGIN_IDS_SWITCH[idxSwitch]

    idManager = PLUGIN_ID_MANAGER
    if REGISTER_SHORTCUTS_GLOBALLY:
        idManager = 0

    qualifier0 = SWITCH_DEFAULT_QUALIFIER_L0
    key0 = SWITCH_DEFAULT_KEY_L0

    qualifier1 = 0
    key1 = SWITCH_DEFAULT_KEY_SELECT[idxSwitch]

    for idxShortcut in range(c4d.gui.GetShortcutCount()):
        bcShortcut = c4d.gui.GetShortcut(idxShortcut)

        if bcShortcut[c4d.SHORTCUT_PLUGINID] == idPlugin and bcShortcut[c4d.SHORTCUT_ADDRESS] == idManager and \
           bcShortcut[0] == qualifier0 and bcShortcut[1] == key0 and bcShortcut[10] == qualifier1 and bcShortcut[11] == key1:
            result = c4d.gui.RemoveShortcut(idxShortcut)
            print('REMOVED SHORTCUT', result, idxShortcut)


# For use in cases developer sucked really big time!
def RemoveAllC4DTabsShortcuts(idsPlugin=PLUGIN_IDS_SWITCH):
    idxShortcut = 0

    while idxShortcut < c4d.gui.GetShortcutCount():
        bcShortcut = c4d.gui.GetShortcut(idxShortcut)

        if bcShortcut[c4d.SHORTCUT_PLUGINID] in idsPlugin:
            result = c4d.gui.RemoveShortcut(idxShortcut)
            print('REMOVED SHORTCUT', result, idxShortcut)
            continue

        idxShortcut += 1


def SwitchShortcutToString(idxShortcut, short=True):
    if idxShortcut >= len(SWITCH_DEFAULT_KEY_SELECT):
        return ''

    if short:
        sShortcut = ' [{0}]'.format(idxShortcut + 1)

    else:
        qualifier0 = SWITCH_DEFAULT_QUALIFIER_L0
        key0 = SWITCH_DEFAULT_KEY_L0

        qualifier1 = 0
        key1 = SWITCH_DEFAULT_KEY_SELECT[idxShortcut]

        sShortcut = ' [{0}~{1}]'.format(c4d.gui.Shortcut2String(qualifier0, key0), c4d.gui.Shortcut2String(qualifier1, key1))

    return sShortcut


def ShortenName(name, maxVisibleLength=24, fill='...'):
    if len(name) > maxVisibleLength + len(fill):
        lenSegment = maxVisibleLength // 2

        name = name[:lenSegment] + '...' + name[-lenSegment:]

    return name


#def GetAvailableLayouts():
#    layouts = {}
#    pathLayout = os.path.join(c4d.storage.GeGetStartupPath(), 'library', 'layout')
#    for filenameLayout in os.listdir(pathLayout):
#        if filenameLayout[-4:] == '.l4d':
#            path = os.path.join(pathLayout, filenameLayout)
#            layouts[MyHash(path)] = (filenameLayout[:-3], path)
#    return layouts
