import os
import c4d
from ssp_utils_c4d_version import *
from ssp_utils_dialog import *
from ssp_ids import *
from ssp_utils_pref import *
from ssp_utils import *


def CommandManageSessions(fromPrefs=True):
    dlgManageSessions = DialogManageSessions()

    dlgManageSessions.Open(c4d.DLG_TYPE_MODAL_RESIZEABLE)

    result = dlgManageSessions.GetResult()
    if not result:
        return False

    c4d.SpecialEventAdd(PLUGIN_ID_COREMESSAGE, p1=SUBID_COREMESSAGE_CHANGE_SESSIONS)

    # TODO Andreas: awkward way of updating the pref page (the content of session combo to be precise). Find correct way!
    #               I had expected to make data dirty and have an EventAdd(), but failed on this route...
    if fromPrefs:
        c4d.PrefsLib_OpenDialog(c4d.PREFS_PRI_PLUGINS)
        c4d.EventAdd()
        c4d.PrefsLib_OpenDialog(PLUGIN_ID_PREFS)

    c4d.EventAdd()

    return True


####################################################################################################
# Class DialogManageSessions #######################################################################
####################################################################################################
class DialogManageSessions(c4d.gui.GeDialog):
    ID_COMBO_SESSIONS             =  1000
    ID_BUTTON_SESSION_DELETE      =  1001
    ID_GROUP_SESSIONS             =  1002
    ID_BUTTON_CURRENT_SCENES_ADD  =  1003
    ID_BUTTON_SESSION_ADD_NEW     =  1004
    ID_BUTTON_SESSION_RENAME      =  1005
    ID_BUTTON_IMPORT_SESSIONS     =  1006
    ID_BUTTON_EXPORT_SESSION      =  1007
    ID_BUTTON_EXPORT_ALL_SESSIONS =  1008

    ID_BUTTON_SCENE_ADD           =  2000

    ID_TEXT_SCENE_NAME_BASE       = 10000
    ID_TEXT_SCENE_PATH_BASE       = 20000
    ID_CHECKBOX_SCENE_ACTIVE_BASE = 30000
    ID_BUTTON_SCENE_DELETE_BASE   = 40000

    _idxCurrentSession = -1
    _scenes = None
    _bcSessions = None
    _changeSessions = False
    _changeScenes = False
    _result = False


    def __init__(self):
        self._idxCurrentSession = -1
        self._scenes = None
        self._changeSessions = False
        self._changeScenes = False
        self._result = False

        self._bcSessions = GetSessionsContainer().GetClone(flags=COPY_FLAGS_NONE)

        c4d.gui.GeDialog.__init__(self)


    def BuildScenesList(self):
        self._scenes = []

        if self._idxCurrentSession == -1:
            return

        idBaseSession = self._idxCurrentSession * BCSESSIONS_SESSION_OFFSET

        bcScenes = self._bcSessions.GetContainer(idBaseSession + BCID_BC_SCENES)
        bcScenesNames = self._bcSessions.GetContainer(idBaseSession + BCID_BC_SCENES_NAMES)
        bcScenesIsActive = self._bcSessions.GetContainer(idBaseSession + BCID_BC_SCENES_IS_ACTIVE)
        bcScenesIsSaved = self._bcSessions.GetContainer(idBaseSession + BCID_BC_SCENES_IS_SAVED)
        bcScenesFavorites = self._bcSessions.GetContainer(idBaseSession + BCID_BC_SCENES_FAVORITES)
        bcScenesReopen = self._bcSessions.GetContainer(idBaseSession + BCID_BC_SCENES_REOPEN)

        for idDoc, pathDocFull in bcScenes:
            isSaved = bcScenesIsSaved.GetBool(idDoc)
            if not isSaved:
                continue

            nameDoc = bcScenesNames.GetString(idDoc)
            isActive = bcScenesIsActive.GetBool(idDoc)
            reopen = bcScenesReopen.GetBool(idDoc)
            favorite = bcScenesFavorites.GetBool(idDoc)

            self._scenes.append([pathDocFull, nameDoc, isActive, reopen, favorite, idDoc])


    def StoreScenesList(self):
        idBaseSession = self._idxCurrentSession * BCSESSIONS_SESSION_OFFSET

        bcScenes = self._bcSessions.GetContainerInstance(idBaseSession + BCID_BC_SCENES)
        bcScenes.FlushAll()

        bcScenesNames = self._bcSessions.GetContainerInstance(idBaseSession + BCID_BC_SCENES_NAMES)
        bcScenesNames.FlushAll()

        bcScenesIsActive = self._bcSessions.GetContainerInstance(idBaseSession + BCID_BC_SCENES_IS_ACTIVE)
        bcScenesIsActive.FlushAll()

        bcScenesIsSaved = self._bcSessions.GetContainerInstance(idBaseSession + BCID_BC_SCENES_IS_SAVED)
        bcScenesIsSaved.FlushAll()

        bcScenesFavorites = self._bcSessions.GetContainerInstance(idBaseSession + BCID_BC_SCENES_FAVORITES)
        bcScenesFavorites.FlushAll()

        bcScenesReopen = self._bcSessions.GetContainerInstance(idBaseSession + BCID_BC_SCENES_REOPEN)
        bcScenesReopen.FlushAll()

        for idxDoc, scene in enumerate(self._scenes):
            idxDocFromSameFile = 0

            for sceneCheckForDuplicate in self._scenes:
                if sceneCheckForDuplicate is scene:
                    break

                if scene[0] == sceneCheckForDuplicate[0]:
                    idxDocFromSameFile += 1

            idDoc = MyHash(scene[0] + '_' + str(idxDocFromSameFile))

            bcScenes.SetString(idDoc, scene[0])
            bcScenesNames.SetString(idDoc, scene[1])
            bcScenesIsActive.SetBool(idDoc, scene[2])
            bcScenesIsSaved.SetBool(idDoc, True)
            bcScenesReopen.SetBool(idDoc, scene[3])
            bcScenesFavorites.SetBool(idDoc, scene[4])


    def UpdateDialogGroupCurrentSession(self):
        self.LayoutFlushGroup(self.ID_GROUP_SESSIONS)

        if self._idxCurrentSession == -1 or self.GetNumberOfSessions() <= 0:
            CreateLayoutAddGroupBar(self, 'No Session Selected')

            self.LayoutChanged(self.ID_GROUP_SESSIONS)
            return

        if self._scenes is None or len(self._scenes) <= 0:
            CreateLayoutAddGroupBar(self, 'No Scenes in Session {0}'.format(self.GetSessionNames()[self._idxCurrentSession]))

            self.LayoutChanged(self.ID_GROUP_SESSIONS)
            return

        CreateLayoutAddGroupBar(self, 'Projects in Session {0}'.format(self.GetSessionNames()[self._idxCurrentSession]))

        if self.GroupBegin(0, c4d.BFH_SCALEFIT | c4d.BFV_TOP, cols=4): # headers
            self.GroupBorderSpace(10, 5, 10, 0)

            self.AddStaticText(0, c4d.BFH_LEFT, name='Scene', initw=300, borderstyle=c4d.BORDER_WITH_TITLE_BOLD)
            self.AddStaticText(0, c4d.BFH_SCALEFIT, name='Path', initw=400, borderstyle=c4d.BORDER_WITH_TITLE_BOLD)
            self.AddStaticText(0, c4d.BFH_LEFT, name='Active', initw=50, borderstyle=c4d.BORDER_WITH_TITLE_BOLD)
            self.AddStaticText(0, c4d.BFH_RIGHT, name='', initw=25) # Remove buttons

        self.GroupEnd() # headers

        if self.GroupBegin(0, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, cols=4): # scenes
            self.GroupBorderNoTitle(c4d.BORDER_GROUP_TOP)
            self.GroupBorderSpace(10, 6, 10, 10)
            self.GroupSpace(5, 5)

            for idxDoc, scene in enumerate(self._scenes):
                pathDocFull = scene[0]
                nameDoc = scene[1]
                isActive = scene[2]
                reopen = scene[3]
                favorite = scene[4]

                self.AddStaticText(self.ID_TEXT_SCENE_NAME_BASE + idxDoc, c4d.BFH_LEFT, initw=300, name=nameDoc, borderstyle=c4d.BORDER_WITH_TITLE_BOLD)
                self.AddStaticText(self.ID_TEXT_SCENE_PATH_BASE + idxDoc, c4d.BFH_SCALEFIT, initw=400, name=pathDocFull)
                self.AddCheckbox(self.ID_CHECKBOX_SCENE_ACTIVE_BASE + idxDoc, c4d.BFH_RIGHT, initw=50, inith=0, name='')
                self.SetBool(self.ID_CHECKBOX_SCENE_ACTIVE_BASE + idxDoc, isActive)
                CreateLayoutAddBitmapButton(self, self.ID_BUTTON_SCENE_DELETE_BASE + idxDoc, c4d.RESOURCEIMAGE_CLEARSELECTION, tooltip='Remove Project from Session', toggle=False, flags=c4d.BFH_RIGHT, w=25, h=0)

        self.GroupEnd() # scenes

        self.LayoutChanged(self.ID_GROUP_SESSIONS)


    def CreateLayout(self):
        self.SetTitle('{0} - Manage Sessions'.format(PLUGIN_NAME))

        if self.GroupBegin(0, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, cols=1): # Dialog main group
            self.GroupBorderSpace(7, 5, 7, 3)

            if self.GroupBegin(0, c4d.BFH_SCALEFIT | c4d.BFV_TOP, cols=5): # session selection
                self.AddStaticText(0, c4d.BFH_LEFT, name='Session:')
                self.AddComboBox(self.ID_COMBO_SESSIONS, c4d.BFH_SCALEFIT, initw=200)
                self.AddButton(self.ID_BUTTON_SESSION_ADD_NEW, c4d.BFH_RIGHT | c4d.BFV_TOP, initw=117, inith=0, name='New...')
                self.AddButton(self.ID_BUTTON_SESSION_RENAME, c4d.BFH_RIGHT | c4d.BFV_TOP, initw=117, inith=0, name='Rename')
                self.AddButton(self.ID_BUTTON_SESSION_DELETE, c4d.BFH_RIGHT | c4d.BFV_TOP, initw=117, inith=0, name='Delete')

                self.AddStaticText(0, c4d.BFH_LEFT, name='') # dummy
                if self.GroupBegin(0, c4d.BFH_SCALEFIT, cols=3): # im-/export buttons
                    self.AddButton(self.ID_BUTTON_IMPORT_SESSIONS, c4d.BFH_SCALEFIT, initw=160, inith=0, name='Import Session...')
                    self.AddButton(self.ID_BUTTON_EXPORT_SESSION, c4d.BFH_SCALEFIT, initw=160, inith=0, name='Export Session...')
                    self.AddButton(self.ID_BUTTON_EXPORT_ALL_SESSIONS, c4d.BFH_SCALEFIT, initw=160, inith=0, name='Export All Sessions...')

                self.GroupEnd() # im-/export buttons
                self.AddStaticText(0, c4d.BFH_RIGHT, name='') # dummy
                self.AddStaticText(0, c4d.BFH_RIGHT, name='') # dummy
                self.AddStaticText(0, c4d.BFH_RIGHT, name='') # dummy

            self.GroupEnd() # session selection

            if self.GroupBegin(self.ID_GROUP_SESSIONS, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, cols=1):
                self.GroupBorderSpace(0, 15, 0, 0)
                ## filled in UpdateDialogGroupCurrentSession()

            self.GroupEnd()  # ID_GROUP_SESSIONS

            if self.GroupBegin(0, c4d.BFH_SCALEFIT | c4d.BFV_BOTTOM, cols=5): # Dialog finish
                self.GroupBorderSpace(0, 10, 0, 0)

                self.AddButton(self.ID_BUTTON_SCENE_ADD, c4d.BFH_LEFT | c4d.BFV_TOP, initw=180, inith=16, name='Add File to Session...')
                self.AddButton(self.ID_BUTTON_CURRENT_SCENES_ADD, c4d.BFH_LEFT | c4d.BFV_TOP, initw=250, inith=16, name='Add Current Projects to Session')
                self.AddStaticText(0, c4d.BFH_SCALEFIT, name='')
                self.AddButton(c4d.DLG_OK, c4d.BFH_RIGHT | c4d.BFV_BOTTOM, initw=117, inith=16, name='Ok')
                self.AddButton(c4d.DLG_CANCEL, c4d.BFH_RIGHT | c4d.BFV_BOTTOM, initw=117, inith=16, name='Cancel')

            self.GroupEnd() # Dialog finish

        self.GroupEnd() # Dialog main group

        return True


    def GetNumberOfSessions(self):
        return self._bcSessions.GetInt32(BCSESSIONS_NUM_SESSIONS, 0)


    def GetSessionNames(self): # TODO Andreas: almost duplicate from main dialog
        numSessions = self._bcSessions.GetInt32(BCSESSIONS_NUM_SESSIONS, 0)
        sessions = []

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

            sessions.append(nameSession)

        return sessions


    def SessionStoreEmpty(self, name):
        SessionStoreEmpty(self._bcSessions, name)


    def SessionDelete(self):
        numSessions = self._bcSessions.GetInt32(BCSESSIONS_NUM_SESSIONS, 0)
        if numSessions <= 0:
            return

        for idxSession in range(self._idxCurrentSession + 1, numSessions):
            idBaseSessionPrev = (idxSession - 1) * BCSESSIONS_SESSION_OFFSET
            idBaseSessionNext = idxSession * BCSESSIONS_SESSION_OFFSET

            self._bcSessions.SetContainer(idBaseSessionPrev + BCID_BC_SCENES, self._bcSessions.GetContainer(idBaseSessionNext + BCID_BC_SCENES))
            self._bcSessions.SetContainer(idBaseSessionPrev + BCID_BC_SCENES_NAMES, self._bcSessions.GetContainer(idBaseSessionNext + BCID_BC_SCENES_NAMES))
            self._bcSessions.SetContainer(idBaseSessionPrev + BCID_BC_SCENES_FAVORITES, self._bcSessions.GetContainer(idBaseSessionNext + BCID_BC_SCENES_FAVORITES))
            self._bcSessions.SetContainer(idBaseSessionPrev + BCID_BC_SCENES_REOPEN, self._bcSessions.GetContainer(idBaseSessionNext + BCID_BC_SCENES_REOPEN))
            self._bcSessions.SetContainer(idBaseSessionPrev + BCID_BC_SCENES_IS_SAVED, self._bcSessions.GetContainer(idBaseSessionNext + BCID_BC_SCENES_IS_SAVED))
            self._bcSessions.SetContainer(idBaseSessionPrev + BCID_BC_SCENES_IS_ACTIVE, self._bcSessions.GetContainer(idBaseSessionNext + BCID_BC_SCENES_IS_ACTIVE))

            self._bcSessions.SetString(idBaseSessionPrev + BCID_STRING_SESSION_NAME, self._bcSessions.GetString(idBaseSessionNext + BCID_STRING_SESSION_NAME))

        idBaseSessionLast = (numSessions - 1) * BCSESSIONS_SESSION_OFFSET

        self._bcSessions.RemoveData(idBaseSessionLast + BCID_BC_SCENES)
        self._bcSessions.RemoveData(idBaseSessionLast + BCID_BC_SCENES_NAMES)
        self._bcSessions.RemoveData(idBaseSessionLast + BCID_BC_SCENES_FAVORITES)
        self._bcSessions.RemoveData(idBaseSessionLast + BCID_BC_SCENES_REOPEN)
        self._bcSessions.RemoveData(idBaseSessionLast + BCID_BC_SCENES_IS_SAVED)
        self._bcSessions.RemoveData(idBaseSessionLast + BCID_BC_SCENES_IS_ACTIVE)
        self._bcSessions.RemoveData(idBaseSessionLast + BCID_STRING_SESSION_NAME)

        self._bcSessions.SetInt32(BCSESSIONS_NUM_SESSIONS, numSessions - 1)


    def FillSessionsCombo(self, idxSelect=0):
        self.FreeChildren(self.ID_COMBO_SESSIONS)

        sessions = self.GetSessionNames()

        for idxSession, nameSession in enumerate(sessions):
            self.AddChild(self.ID_COMBO_SESSIONS, idxSession, nameSession)

        if len(sessions) > 0 and (idxSelect >= 0 or self._idxCurrentSession < 0 or self._idxCurrentSession >= len(sessions)):
            self.SetInt32(self.ID_COMBO_SESSIONS, idxSelect)
            self._idxCurrentSession = idxSelect

        elif len(sessions) <= 0:
            self.AddChild(self.ID_COMBO_SESSIONS, -1, 'No Stored Sessions')
            self.SetInt32(self.ID_COMBO_SESSIONS, -1)
            self._idxCurrentSession = -1


    def InitValues(self, idxSelect=0):
        self.FillSessionsCombo(idxSelect=idxSelect)

        self.BuildScenesList()

        self.UpdateDialogGroupCurrentSession()

        if self._idxCurrentSession != -1:
            self.Enable(self.ID_BUTTON_SESSION_RENAME, True)
            self.Enable(self.ID_BUTTON_SESSION_DELETE, True)
            self.Enable(self.ID_BUTTON_SCENE_ADD, True)
            self.Enable(self.ID_BUTTON_CURRENT_SCENES_ADD, True)

        else:
            self.Enable(self.ID_BUTTON_SESSION_RENAME, False)
            self.Enable(self.ID_BUTTON_SESSION_DELETE, False)
            self.Enable(self.ID_BUTTON_SCENE_ADD, False)
            self.Enable(self.ID_BUTTON_CURRENT_SCENES_ADD, False)

        return True


    def CommandSessionSwitch(self):
        if self._changeScenes:
            result = c4d.gui.MessageDialog('Current session has been changed. Keep changes?', type=c4d.GEMB_YESNO)
            if result == c4d.GEMB_R_YES:
                self.StoreScenesList()
                self._changeSessions = True

        self._changeScenes = False
        self._idxCurrentSession = self.GetInt32(self.ID_COMBO_SESSIONS)

        self.BuildScenesList()

        self.UpdateDialogGroupCurrentSession()


    def CommandSessionDelete(self):
        result = c4d.gui.QuestionDialog('Are you sure you want to delete the entire session?')
        if not result:
            return

        self.SessionDelete()

        self.InitValues(idxSelect=0)

        self._changeSessions = True


    def CommandSessionAddNew(self):
        idxSessionNew = self.GetNumberOfSessions()

        result, nameSession = AskSessionName(idxSessionNew)
        if not result:
            return

        self.SessionStoreEmpty(nameSession)

        self.InitValues(idxSelect=idxSessionNew)

        self._changeSessions = True


    def CommandSessionRename(self):
        numSessions = self._bcSessions.GetInt32(BCSESSIONS_NUM_SESSIONS, 0)
        if numSessions <= 0:
            return

        nameDefault = self.GetSessionNames()[self._idxCurrentSession]

        result, nameSession = AskSessionName(self._idxCurrentSession, nameDefault, titleAddition='Rename Session')
        if not result:
            return

        idBaseSession = self._idxCurrentSession * BCSESSIONS_SESSION_OFFSET

        self._bcSessions.SetString(idBaseSession + BCID_STRING_SESSION_NAME, nameSession)

        self.InitValues(idxSelect=self._idxCurrentSession)

        self._changeSessions = True


    def CommandSceneAdd(self):
        pathDocFull = c4d.storage.LoadDialog(type=c4d.FILESELECTTYPE_SCENES, title='Select Scene File...')
        if pathDocFull is None or len(pathDocFull) <= 0:
            return

        nameDoc = pathDocFull.rsplit(os.sep, 1)[1]

        isActive = False
        reopen = True
        favorite = False

        idxDocFromSameFile = 0 # temporary index, index will be fixed, when scenes get stored into session

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

        self._scenes.append([pathDocFull, nameDoc, isActive, reopen, favorite, idDoc])

        self.UpdateDialogGroupCurrentSession()

        self._changeScenes = True


    def CommandImportSessions(self):
        ImportSessions(self._bcSessions)

        self.InitValues(idxSelect=self._idxCurrentSession)

        self._changeSessions = True


    def CommandExportSession(self):
        ExportSessions(self._bcSessions, self._idxCurrentSession)


    def CommandExportAllSessions(self):
        ExportSessions(self._bcSessions)


    def CommandCurrentScenesAdd(self):
        doc = c4d.documents.GetFirstDocument()
        docActive = c4d.documents.GetActiveDocument()

        dictDocs = {}

        while doc is not None:
            pathDocFull, idDoc, nameDoc, isSaved = GetDocumentPathFull(doc)

            doc = doc.GetNext()

            existsAlready = False

            for pathTest, _, _, _, _, _ in self._scenes:
                if pathTest == pathDocFull:
                    existsAlready = True
                    break

            if existsAlready:
                continue

            if isSaved:
                self._scenes.append([pathDocFull, nameDoc, False, True, False, idDoc])


        self.UpdateDialogGroupCurrentSession()

        self._changeScenes = True


    def CommandSceneDelete(self, idxScene):
        self._scenes.pop(idxScene)

        self.UpdateDialogGroupCurrentSession()

        self._changeScenes = True


    def CommandSceneActive(self, idxSceneActive):
        for idxScene, scene in enumerate(self._scenes):
            scene[2] = idxScene == idxSceneActive
            self.SetBool(self.ID_CHECKBOX_SCENE_ACTIVE_BASE + idxScene, scene[2])

        self._changeScenes = True


    def Command(self, id, msg):
        if id == self.ID_COMBO_SESSIONS:
            self.CommandSessionSwitch()

        elif id == self.ID_BUTTON_SESSION_DELETE:
            self.CommandSessionDelete()

        elif id == self.ID_BUTTON_SESSION_ADD_NEW:
            self.CommandSessionAddNew()

        elif id == self.ID_BUTTON_SESSION_RENAME:
            self.CommandSessionRename()

        elif id == self.ID_BUTTON_IMPORT_SESSIONS:
            self.CommandImportSessions()

        elif id == self.ID_BUTTON_EXPORT_SESSION:
            self.CommandExportSession()

        elif id == self.ID_BUTTON_EXPORT_ALL_SESSIONS:
            self.CommandExportAllSessions()

        elif id == self.ID_BUTTON_SCENE_ADD:
            self.CommandSceneAdd()

        elif id == self.ID_BUTTON_CURRENT_SCENES_ADD:
            self.CommandCurrentScenesAdd()

        elif id >= self.ID_BUTTON_SCENE_DELETE_BASE and id < self.ID_BUTTON_SCENE_DELETE_BASE + 1000:
            idxScene = id - self.ID_BUTTON_SCENE_DELETE_BASE
            self.CommandSceneDelete(idxScene)

        elif id >= self.ID_CHECKBOX_SCENE_ACTIVE_BASE and id < self.ID_CHECKBOX_SCENE_ACTIVE_BASE + 1000:
            idxScene = id - self.ID_CHECKBOX_SCENE_ACTIVE_BASE
            self.CommandSceneActive(idxScene)

        elif id == c4d.DLG_OK:
            if self._changeScenes:
                self.StoreScenesList()
                self._changeSessions = True

            if self._changeSessions:
                SetSessionsContainer(self._bcSessions)

            self._result = True
            self.Close()
            # TODO Andreas: Update main dialog and prefs session combo

        elif id == c4d.DLG_CANCEL:
            if (self._changeSessions or self._changeScenes) and not c4d.gui.QuestionDialog('Cancel Session Manager?\nAll changes will be lost.'):
                return True # cancel cancelled

            self._result = False
            self.Close()

        return True


    def GetResult(self):
        return self._result
