#!/usr/bin/env python
#
# state.py - Functions for saving/restoring the state of *FSLeyes*.
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
"""This module provides two functions, :func:`getState` and :func:`setState`.
These functions may be used to get/set the state of *FSLeyes*.
"""


import logging

import fsleyes.actions.showcommandline  as showcommandline
import fsleyes.actions.applycommandline as applycommandline
import fsleyes.views.canvaspanel        as canvaspanel
import fsleyes.layouts                  as layouts


log = logging.getLogger(__name__)


SEP = '\n------\n'
"""String used to separate different parts of the state string. """


CLISEP = '\t'
"""String used to separate different command line arguments, within the state
string.
"""


def getState(frame):
    """Generate a string which describes the current state of FSLeyes.

    The string contains:

      - A layout specification string, as generated by the
        :func:`.layouts.serialiseLayout` function.

      - A set of command line arguments describing the overlays that are
        loaded, generated by the :func:`.genCommandLineArgs` function.

      - A set of command line arguments for each :class:`.CanvasPanel`,
        describing the panel settings, and any panel-specific overlay
        settings.

    :arg frame: The :class:`.FSLeyesFrame`
    :returns:   A string describing FSLeyes.
    """

    displayCtx  = frame.displayCtx
    overlayList = frame.overlayList

    layout = layouts.serialiseLayout(frame)
    cli    = [showcommandline.genCommandLineArgs(overlayList, displayCtx)]

    for i, panel in enumerate(frame.viewPanels):
        if not isinstance(panel, canvaspanel.CanvasPanel):
            continue

        argv = showcommandline.genCommandLineArgs(
            overlayList,
            panel.displayCtx,
            panel)
        cli.append(argv)

    cli   = [[a.strip('"') for a in argv[1:]] for argv in cli]
    cli   = [CLISEP.join(c) for c in cli]
    state = SEP.join([layout] + cli)

    return state


def setState(frame, state):
    """Set the state of FSLeyes from the given ``state`` string.

    .. warning:: This function will remove all view panels, and remove all
                 overlays, before loading the new state.

    :arg frame: The :class:`.FSLeyesFrame`
    :arg state: A FSLeyes state string, generated by :func:`getState`.
    """

    displayCtx  = frame.displayCtx
    overlayList = frame.overlayList

    bits   = state.split(SEP)
    layout = bits[0]
    cli    = bits[1:]
    cli    = [c.split(CLISEP) for c in cli]

    # First clear the current state
    frame.removeAllViewPanels()
    overlayList.clear()

    # Then load all new overlays
    applycommandline.applyCommandLineArgs(
        overlayList,
        displayCtx,
        cli[0],
        blocking=True)

    # After overlays have been loaded,
    # apply the new layout, and apply
    # view-specific overlay arguments.
    layouts.applyLayout(frame, 'state', layout)

    panels = [p for p in frame.viewPanels
              if isinstance(p, canvaspanel.CanvasPanel)]
    for i, panel in enumerate(panels, 1):
        applycommandline.applyCommandLineArgs(
            overlayList,
            panel.displayCtx,
            cli[i],
            panel,
            loadOverlays=False)
