# -*- coding: utf-8 -*-
#  This software and supporting documentation are distributed by
#      Institut Federatif de Recherche 49
#      CEA/NeuroSpin, Batiment 145,
#      91191 Gif-sur-Yvette cedex
#      France
#
# This software is governed by the CeCILL license version 2 under
# French law and abiding by the rules of distribution of free software.
# You can  use, modify and/or redistribute the software under the
# terms of the CeCILL license version 2 as circulated by CEA, CNRS
# and INRIA at the following URL "http://www.cecill.info".
#
# As a counterpart to the access to the source code and  rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty  and the software's author,  the holder of the
# economic rights,  and the successive licensors  have only  limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading,  using,  modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean  that it is complicated to manipulate,  and  that  also
# therefore means  that it is reserved for developers  and  experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and,  more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license version 2 and that you accept its terms.
"""
Several global variables are defined in this module to store **Brainvisa configuration and user options**:
.. py:data:: logFileName
  path of Brainvisa log file where the history of the current session will be saved.
.. py:data:: platform
  linux, windows...
.. py:data:: gui
  false if Brainvisa is in batch mode
.. py:data:: sessionID
.. py:data:: fullVersion
             shortVersion
  Brainvisa version
.. py:data:: userProfile
  if Brainvisa is started with ``-u`` option, the name of the profile stored in this variable is used to create a specific log file for this profile.
.. py:data:: siteOptionFile
  path to a general options file that may be used for all users.
.. py:data:: userOptionFile
  path to user options file.
.. py:data:: logFileName
  path of Brainvisa log file where the history of the current session will be saved.
.. py:data:: runsInfo
  information about the current executions of Brainvisa.
.. py:data:: temporaryDirectory
  directory where temporary files will be written.
.. py:data:: mainPath
  Path of Brainvisa main module.
.. py:data:: sharePath
  Brainvisa share directory
.. py:data:: iconPath
.. py:data:: homeBrainVISADir
  path to Brainvisa home directory (usually *$HOME/.brainvisa*)
.. py:data:: toolboxesDir
  Brainvisa toolboxes directory
.. py:data:: processesPath
  list of paths to Brainvisa processes (outside any toolbox)
.. py:data:: dataPath
  list of DatabaseSettings objects indicating the selected databases.
.. py:data:: typesPath
  list of paths to Brainvisa type files that contain the description of Brainvisa ontology.
.. py:data:: fileSystemOntologiesPath
  list of paths to Brainvisa hierarchy files that contain the rules to organize Brainvisa databases directories.
.. py:data:: debugHierarchyScanning
  stream where debug information about hierarchy rules may be written. Set with ``--debugHierarchy`` option.
.. py:data:: debugParameterLinks
  stream where debug information about parameter links may be written. Set with `--debugLinks` option.
.. py:data:: sharedDatabaseFound
  True if Brainvisa shared database which contain models, templates, referentials, etc, was found.
.. py:data:: mainDocPath
  path to Brainvisa documentation directory
.. py:data:: docPath
  path to Brainvisa documentation directory according to the choosen language.
.. py:data:: brainvisaSysEnv
  :py:class:`soma.env.BrainvisaSystemEnv` - defines system environment variables that have to be passed to external command to restore environment if it have been modified at brainvisa startup
.. py:data:: ignoreValidation
  Do not check vor invalid processes, all are enabled. Set with ``--ignoreValidation``.
.. py:data:: language
  fr or en
.. py:data:: userLevel
  the processes which level is greater than the user level are hidden. Basic = 0, advanced = 1, expert = 2.
.. py:data:: supportEmail
             SMTP_server_name
.. py:data:: textEditor
.. py:data:: HTMLBrowser
.. py:data:: fastStart
  if this mode is enabled, brainvisa starts faster but with less features. Set with ``-f`` or ``-r`` options.
.. py:data:: noToolBox
  if enabled, Brainvisa toolboxes are not loaded. Set with ``--noToolBox``.
.. py:data:: setup
  if enabled, the shared database is updated at startup. Set with ``--setup`` option.
.. py:data:: anatomistExecutable
             anatomistImplementation
.. py:data:: matlabRelease
             matlabExecutable
             matlabOptions
             matlabPath
             matlabStartup
.. py:data:: spmDirectory
.. py:data:: Roptions
             Rexecutable
.. py:data:: profileFileName
  filename where profiling information may be written. Set with ``--profile`` option.
.. py:data:: historyBookDirectory
  path to history_book directory, where processes executions and logs will be saved. Normally it is None so that it is stored in the database of each output data. But in some specific cases (distributed execution of single process) it can be useful to force it.
  May be a list of directories: in that case, history files are duplicated in each of them.
"""
from __future__ import print_function
from __future__ import absolute_import
__docformat__ = 'restructuredtext en'
_defaultTranslateFunction = lambda x: x
import six.moves.builtins
if not hasattr(six.moves.builtins, '_t_'):
    six.moves.builtins._t_ = _defaultTranslateFunction
import sys
import os
import errno
import re
import time
import socket
import tempfile
from soma.wip.application.api import Application
from brainvisa.configuration.api import initializeConfiguration, readConfiguration, DatabaseSettings
from soma.html import htmlEscape
from soma.uuid import Uuid
from soma.minf.api import readMinf, writeMinf
from soma.env import BrainvisaSystemEnv
import brainvisa
import six
import io
exitValue = 0
mainPath = os.path.normpath(
    os.path.join(os.path.dirname(brainvisa.__file__), "..", "..", "brainvisa"))
sys.argv[0] = os.path.normpath(
    os.path.abspath(os.path.join(mainPath, '..', 'bin', 'brainvisa')))
mainPath = os.path.normpath(os.path.abspath(mainPath))
if not os.path.isdir(mainPath):
    raise RuntimeError('Cannot find main BrainVISA directory')
# Change sys.path[0] because Python follow symlinks when it adds
# this directory and we do not want that to be able to make symlinks
# in build tree to source tree and create the *.pyo or *.pyc in build tree.
basePath = os.path.dirname(mainPath)
sys.path[0:0] = [mainPath, os.path.join(basePath, 'python')]
# A bit of cleanup
sys.path = [os.path.normpath(os.path.abspath(p)) for p in sys.path]
_commandLine = " ".join(['"' + x + '"' for x in sys.argv])
def commandLine():
    return _commandLine
platform = findPlatform()
if platform == 'windows':
    pathSeparator = ';'
else:
    pathSeparator = ':'
[docs]def findInPath(file,
               pathlist=os.environ.get('PATH').split(pathSeparator),
               is_dir=False):
    """Returns the directory containing file"""
    for i in pathlist:
        p = os.path.normpath(os.path.abspath(i))
        if p:
            if os.path.isdir(p) and os.path.exists(os.path.join(p, file)):
                if (is_dir and os.path.isdir(os.path.join(p, file))) \
                        
or (not is_dir and not os.path.isdir(os.path.join(p, file))):
                    return p 
def executableWithPath(file,
                       pathlist=os.environ.get('PATH').split(pathSeparator)):
    if os.path.isabs(file) and os.path.exists(file):
        return file
    path = findInPath(file, pathlist)
    return os.path.join(path, file)
try:
    from brainvisa.config import fullVersion, shortVersion
except ImportError:
    f = os.path.join(mainPath, 'VERSION')
    if not os.path.exists(f):
        f = os.path.join(mainPath, '..', 'VERSION')
    f = open(f)
    fullVersion = f.readline()[:-1]
    f.close()
    shortVersion = '.'.join(fullVersion.split('.')[:2])
[docs]def versionNumber():
    """Returns Brainvisa short version X.Y as a float number"""
    global shortVersion
    return float(shortVersion) 
[docs]def versionString():
    """Returns Brainvisa full version 'X.Y.Z'"""
    global fullVersion
    return fullVersion 
[docs]def versionText():
    """Returns the text 'BrainVISA X.Y.Z'"""
    return 'BrainVISA ' + versionString() 
_sharePath = None
[docs]def getSharePath():
    """Returns BrainVISA share directory path."""
    global _sharePath
    if _sharePath is not None:
        return _sharePath
    try:
        from soma.config import BRAINVISA_SHARE
        _sharePath = BRAINVISA_SHARE
    except ImportError:
        path = os.getenv('PATH').split(os.pathsep)
        for p in path:
            if p.endswith('/bin') or p.endswith('\\bin'):
                p = p[:len(p) - 4]
            elif p.endswith( '/bin/commands-links' ) \
                    
or p.endswith('\\bin\\commands-links'):
                p = p[:len(p) - 19]
            p = os.path.join(p, 'share')
            if os.path.isdir(p):
                _sharePath = p
                break
    if not _sharePath or \
        
(not os.path.isdir(os.path.join(_sharePath,
                                        'axon-' + shortVersion))
         and not os.path.isdir(os.path.join(_sharePath,
                                            'brainvisa-' + shortVersion))):
        # empty string rather than None to avoid later re-detection
        _sharePath = ''
        for projectName in ('axon', 'brainvisa'):
            sharePath = os.path.normpath(os.path.join(mainPath, '..', 'share',
                                                      projectName + '-' + shortVersion))
            if os.path.isdir(sharePath):
                _sharePath = os.path.normpath(os.path.join(mainPath, '..',
                                                           'share'))
                break
    return _sharePath 
[docs]def initializeOntologyPaths():
    """
    Initializes the global variables :py:data:`typesPath` and :py:data:`fileSystemOntologiesPath`.
    This function is used when toolboxes are reloaded.
    """
    global typesPath
    global fileSystemOntologiesPath
    global mainPath
    typesPath = [os.path.join(mainPath, 'types')]
    fileSystemOntologiesPath = [os.path.join(mainPath, 'hierarchies')] 
initializeOntologyPaths()
processesPath = [os.path.join(mainPath, 'processes')]
for projectName in ('axon', 'brainvisa'):
    sharePath = os.path.join(getSharePath(), projectName + '-' + shortVersion)
    if os.path.isdir(sharePath):
        break
    # Sources organization
    sharePath = os.path.normpath(
        os.path.join(mainPath, '..', 'share', projectName + '-' + shortVersion))
    if os.path.isdir(sharePath):
        break
iconPath = os.path.join(sharePath, 'icons')
uiPath = os.path.join(sharePath, 'ui')
toolboxesDir = os.path.join(mainPath, 'toolboxes')
# environment variable holding path for dynamic libraries
def libraryPathEnvironmentVariable():
    if platform == 'windows':
        return 'PATH'
    elif platform == 'darwin':
        return 'DYLD_LIBRARY_PATH'
    return 'LD_LIBRARY_PATH'
# Define system environment variables that have to be passed to external
# command to restore environment if it have been modified at brainvisa
# startup
brainvisaSysEnv = BrainvisaSystemEnv()
# try to determine if we are in a build tree with system libraries - in that
# case, brainvisaSysEnv should not be altered when calling external commands
if not sys.executable.startswith(basePath):
    # python is not in the BV tree, or it is a system-wide installation
    brainvisaSysEnv.variables = {}
userLevel = 0
sessionID = Uuid()
temporaryDirectory = tempfile.gettempdir()
[docs]def getDocPath(path, project=''):
    """Returns the path of the documentation directory of the given project."""
    # Language and documentation
    result = os.path.join(getSharePath(), 'doc', project)
    if not os.path.exists(result):
        result = os.path.normpath(
            os.path.join(path, '..', 'share', 'doc', project))
        if not os.path.exists(result):
            result = os.path.normpath(os.path.join(path, '..', 'doc'))
    return result 
docPath = mainDocPath = getDocPath(
    mainPath, projectName + '-' + str(versionNumber()))
_languages = []
if os.path.exists(docPath):
    for l in os.listdir(docPath):
        if len(l) == 2 and os.path.isdir(os.path.join(mainDocPath, l)):
            _languages.append(l)
else:
    print(
        'WARNING: You should check your BrainVISA installation because the following directory does not exist:',
          repr(docPath), file=sys.stderr)
for i in ('LANGUAGE', 'LC_ALL', 'LC_MESSAGES', 'LANG'):
    language = os.environ.get(i, '')[: 2]
    if language in _languages:
        break
if language not in _languages:
    language = 'en'
# variable to ensure the format used for numbers
os.environ["LC_NUMERIC"] = "C"
# debug console defaults
shell = 0
# GUI defaults
gui = True
guiLoaded = False
qtApplication = None
# Create $HOME/.brainvisa directory
homedir = os.getenv('HOME')
if not homedir:
    homedir = ''
    if sys.platform[:3] == 'win':
        homedir = os.getenv('USERPROFILE')
        if not homedir:
            homedir = os.getenv('HOMEPATH')
            if not homedir:
                homedir = '\\'
            drive = os.getenv('HOMEDRIVE')
            if not drive:
                drive = os.getenv('SystemDrive')
                if not drive:
                    drive = os.getenv('SystemRoot')
                    if not drive:
                        drive = os.getenv('windir')
                    if drive and len(drive) >= 2:
                        drive = drive[:2]
                    else:
                        drive = ''
            homedir = drive + homedir
# Try to get BrainVISA user dir from environment variable
homeBrainVISADir = os.getenv('BRAINVISA_USER_DIR')
if not homeBrainVISADir:
    # Uses default BrainVISA home directory
    homeBrainVISADir = os.path.join(homedir, '.brainvisa')
if not os.path.exists(homeBrainVISADir):
    if os.path.lexists(homeBrainVISADir):
        # .brainvisa is a broken symbolic link, likely from
        # /casa/home/.brainvisa to the host home directory; make the target
        # directory
        path_to_make = os.readlink(homeBrainVISADir)
    else:
        path_to_make = homeBrainVISADir
    try:
        os.mkdir(path_to_make)
    except OSError as e:
        if e.errno == errno.EEXIST:
            # filter out 'File exists' exception, if the same dir has been
            # created concurrently by another instance of BrainVisa or another
            # thread
            pass
        else:
            raise
# Other defaults
anatomistExecutable = 'anatomist'
anatomistImplementation = 'threaded'
remoteBrainvisaExecutable = ''
HTMLBrowser = ''
useHTMLBrowser = 0
matlabExecutable = 'matlab'
matlabRelease = None
matlabOptions = '-nosplash -nodisplay'
matlabPath = []
tmp = [os.path.join(homeBrainVISADir, 'matlab'),
       os.path.join(mainPath, 'matlab')]
while tmp:
    p = tmp.pop()
    if os.path.isdir(p):
        matlabPath.append(p)
        for x in os.listdir(p):
            tmp.append(os.path.join(p, x))
spmDirectory = ''
textEditor = ''
matlabStartup = []
dataPath = []
logFileName = None
cleanLog = False
profileFileName = ''
mainLog = None
brainvisaSessionLog = None
brainvisaSessionLogItem = None
startup = []
flatHierarchy = os.path.join(mainPath, 'shfjFlatHierarchy.py')
debugHierarchyScanning = None
debugParametersLinks = None
historyBookDirectory = None
userEmail = ''
supportEmail = 'support@brainvisa.info'
SMTP_server_name = 'localhost'
if platform == 'windows':
    Rexecutable = 'Rterm.exe'
    Roptions = '--no-restore --no-save --args'
else:
    Rexecutable = 'R'
    Roptions = '--vanilla --slave --args'
_openedDebugFiles = {
    '-': sys.stdout,
  '~': sys.stderr,
}
app = Application('brainvisa', versionString())
app.directories.user = homeBrainVISADir
app.directories.application = sharePath
[docs]def openDebugFile(fileName):
    '''Opens a file to put debug messages in. If '-' is given, sys.stdout is
    returned. If '~' is given, sys.stderr is returned. If this function is
    used several times with the same fileName, the same file object is retured.
    '''
    result = _openedDebugFiles.get(fileName)
    if result is None:
        result = open(fileName, 'a')
        _openedDebugFiles[fileName] = result
    return result 
#------------------------------------------------------------------------------
[docs]def chooseDatabaseVersionSyncOption(context):
    """
    Asks user to choose a database synchronization mode (Automatic or manual) when a database is used with different versions of Brainvisa.
    The choice is saved in brainvisa options file.
    :param context: The context enables to adapt the interaction with the user according to Brainvisa mode of execution (graphical, batch)
    :returns: the user choice: *auto* for automatic mode, *man* for manual mode.
    """
    global databaseVersionSync, userOptionFile
    choice = context.ask(
        "<p><b>Database synchronization between different versions of BrainVISA<b></p><p>Some of your databases have been used with different versions of BrainVISA. They may need to be updated when you switch from one BrainVISA version to another.</p> Please choose the way you want to manage the database synchronization throught BrainVISA versions : <ul><li>Automatic (recommended) : BrainVISA will automatically update your database if you switch from one BrainVISA version to another. </li><li>Manual : Database update is not automatic when switch from one BrainVISA version to another but if you modify a database in one version, you will have to update it with the other version for BrainVISA to take into account the modifications.</li></ul><p>You can change this option later in BrainVISA preferences.</p>", "Automatic (recommended)", "Manual")
    if (choice == 0):
        databaseVersionSync = "auto"
    else:
        databaseVersionSync = "man"
    app = Application()
    app.configuration.brainvisa.databaseVersionSync = databaseVersionSync
    app.configuration.save(userOptionFile)
    return databaseVersionSync 
[docs]def stdinLoop():
    """
    Reads Brainvisa commands on stdin and executes them.
    """
    e = []
    for l in sys.stdin:
        if l.startswith('# brainvisa run commands'):
            exec(''.join(e))
            e = []
        else:
            e.append(l)
    if e:
        exec(''.join(e)) 
# Parse command Line
# To use -- <Other options> do not use sys.argv but args (returned by getopt)
userProfile = None
openMainWindow = 1
showHelp = 0
fastStart = False
global setup
setup = False
noToolBox = False
ignoreValidation = False
def convertCommandLineParameter(i):
    if len(i) > 0 and (i[0] in '[({' or i in ('None', 'True', 'False')):
        try:
            res = eval(i)
        except Exception:
            res = i
    else:
        res = i
    return res
try:
    i = sys.argv.index('-r')
except ValueError:
    i = -1
if i >= 0:
    gui = 0
    fastStart = True
    # noToolBox = True
    logFileName = ''
    startup.append('defaultContext().runProcess' + repr(
        tuple((convertCommandLineParameter(i) for i in sys.argv[i + 1:]))))
else:
    import getopt
    # Ignore Qt -style attribute
    try:
        i = sys.argv.index('-style')
        argv = sys.argv[1:i] + sys.argv[i + 2:]
    except ValueError:
        argv = sys.argv[1:]
    try:
        opts, args = getopt.getopt(argv, "bfe:c:s:u:h",
                                   ["updateDocumentation", "noMainWindow",
                                    "logFile=", "cleanLog", "profile=", "shell",
                                    "debugHierarchy=", "debugLinks=",
                                    "help", "setup", "noToolBox",
                                    "ignoreValidation"])
    except getopt.GetoptError as msg:
        # print help information and exit:
        sys.stderr.write(
            "error in options: %s\nUse -h or --help for help\n" % msg)
        sys.exit(1)
    for o, a in opts:
        if o in ("-b", ):
            gui = 0
        elif o in ("-e", ):
            if a == '-':
                startup.append('neuroConfig.stdinLoop()')
            else:
                startup.append("with open({0!r}, 'rb') as f:\n"
                               "    code = compile(f.read(), {0!r}, 'exec')\n"
                               "six.exec_(code)\n"
                               .format(a))
        elif o in ("-c", ):
            startup.append(a)
        elif o in ("-s", ):
            m = re.match(r'(.*)\((.*[^)])\)?', a)
            if m:
                startup.append(
                    'brainvisa.processing.qt4gui.neuroProcessesGUI.showProcess("' + m.group(1) + '",' + m.group(2) + ')')
            else:
                startup.append(
                    'brainvisa.processing.qt4gui.neuroProcessesGUI.showProcess("' + a + '")')
        elif o in ("-u", ):
            userProfile = a
        elif o in ("-f", ):
            fastStart = True
        elif o in ("--updateDocumentation", ):
            startup.append('generateHTMLProcessesDocumentation()')
        elif o in ("--noMainWindow", ):
            openMainWindow = 0
        elif o in ("--logFile", ):
            logFileName = a
        elif o in ("--cleanLog",):
            cleanLog = True
        elif o in ("--profile", ):
            profileFileName = a
        elif o in ("--shell", ):
            shell = 1
        elif o in ("--debugHierarchy", ):
            debugHierarchyScanning = openDebugFile(a)
        elif o in ("--debugLinks", ):
            debugParametersLinks = openDebugFile(a)
        elif o in ("-h", "--help"):
            showHelp = 1
        elif o in ("--setup"):
            setup = True
        elif o in ("--noToolBox"):
            noToolBox = True
        elif o in ("--ignoreValidation"):
            ignoreValidation = True
# Print(help)
if showHelp == 1:
    print('''
Usage: brainvisa [ <BrainVISA options> ] [ -- <other options> ]
<BrainVISA options> are interpreted by BrainVISA, <other options> are
passed to BrainVISA scripts (technically, they are kept in sys.argv).
BrainVISA options:
  -b                      Run in batch mode: no graphical interface started by BrainVISA.
  -e <file>               Execute <file> which must be a valid Python script.
  -c <command>            Execute <command> which must be a valid Python command.
  --shell                 Run BrainVISA in a IPython shell, if IPython is
                          available (see http://ipython.scipy.org).
  -s <process_id>         Open a process window. Equivalent to -c 'brainvisa.processing.qt4gui.neuroProcessesGUI.showProcess("<process_id>")'.
  -u <profile>            Select a user profile.
  --logFile <file>        Change the log file name (default=$HOME/.brainvisa/brainvisa.log).
  --updateDocumentation   Generate processes and types HTML documentation pages.
  --setup                 Update the shared database at startup.
  --noMainWindow          Do not open Brainvisa main window.
  --noToolBox             Do not load any process nor toolbox.
  --cleanLog              Clean home brainvisa directory by removing session information (current_runs.minf) and all log files (brainvisa*.log)
  --ignoreValidation      Do not check vor invalid processes, all are enabled.
                          (generally not useful)
  -f                      Run in faststart mode: databases are not loaded, processes are loaded from a cache
                          (this mode is used when processes are run in parallel  via Soma-workflow).
  --debugHierarchy <file> Write ontology rules debug information in <file>.
  --debugLinks <file>     Write parameter links debug information in <file>.
  -r <process specs>      Run a process in batch mode, and quit after execution.
                          The process specs can be either a .bvproc filename,
                          or a process name followed by its paremeters.
                          Parameters names cannot be specified in arguments,
                          so they must be provided in the correct order:
                          brainvisa -r process.bvproc
                          brainvisa -r threshold ~/data/irm.ima /tmp/th.nii "greater than" 80
                          This used to be the standard way to run batches, but
                          now it is recommended to use
                          "python -m brainvisa.axon.runprocess",
                          which is lighter, instead, and more flexible on
                          parameters (parameters names are allowed).
  -h  or --help           Show help message in batch mode and exit.
Notes:
  Multiple -e and -c commands are executed in the order they are given after
  all initialization steps are done (options parsing, databases and processes
  parsing, etc.).
''')
    sys.exit()
if setup:
    startup.append(
        'from brainvisa.data.neuroHierarchy import databases\nfrom brainvisa.processes import defaultContext\ndb = list( databases.iterDatabases() )[0]\ndb.clear(context=defaultContext())\ndb.update(context=defaultContext())')
#
[docs]class RunsInfo(object):
    """
    This class gets information about possibly existing runs of Brainvisa and adds information about the current one.
    :var string file: information about current runs is stored in *<Brainvisa home dir>/current_runs.minf*
    :var integer currentRun: index of the current execution of Brainvisa (from 1)
    :var float timeout: timeout before asking the user if the execution of Brainvisa is still alive. When Brainvisa fails, the file current_runs.minf may not be cleaned.
    :var dictionary runs: information about current executions of Brainvisa. The information is loaded from the minf file and information about the current execution is added. It is a dictionary *{index -> {host, pid, time, logFileName} }*
    :var integer count: number of executions of Brainvisa
    :var dictonary expiredRuns: dictionary containing the runs for which the timeout is reached. The user will be asked if these runs are still alive. If not, the corresponding log files will be deleted and the *current_runs.minf* file will be cleaned.
    """
    def __init__(self, dontrecordruns=False):
        global logFileName
        global cleanLog
        self.dontrecordruns = dontrecordruns
        if dontrecordruns:
            fd, self.file = tempfile.mkstemp(suffix='.minf',
                                             prefix='bv_current_runs', dir=temporaryDirectory, text=True)
            os.close(fd)
            os.unlink(self.file)
        else:
            self.file = os.path.join(homeBrainVISADir, "current_runs.minf")
        if cleanLog:
            try:
                if os.path.exists(self.file):
                    os.remove(self.file)
                for f in os.listdir(homeBrainVISADir):
                    if f.startswith("brainvisa") and (f.endswith(".log") or f.endswith(".log~")):
                        os.remove(os.path.join(homeBrainVISADir, f))
            except Exception as e:
                print("Fail cleaning log files:")
                print(e)
        self.currentRun = 1
        self.timeout = 604800  # 7 days in seconds
        self.runs = {}
        self.count = 0
        self.expiredRuns = {}
        try:
            if os.path.exists(self.file):
                self.runs, self.count = readMinf(self.file)
            currentTime = time.time()
            # register information for current run
            infos = {
                'host': socket.gethostname(), 'pid': os.getpid(), 'time': currentTime}
            self.count += 1
            i = 1
            while ((i <= self.count + 1) and i in self.runs):
                i += 1
            self.currentRun = i
            if logFileName is None:
                if dontrecordruns:
                    fd, logFileName = tempfile.mkstemp(
                        suffix='.log', prefix='brainvisa',
                      dir=temporaryDirectory, text=True)
                    os.close(fd)
                    os.unlink(logFileName)
                elif self.currentRun > 1:
                    logFileName = os.path.join(
                        homeBrainVISADir, 'brainvisa' + str(self.currentRun) + '.log')
                else:
                    logFileName = os.path.join(
                        homeBrainVISADir, 'brainvisa.log')
            else:
                self.currentRun = logFileName
            infos["logFileName"] = logFileName
            self.runs[self.currentRun] = infos
            self.write()
        except Exception as e:
            print("Fail to get or set current runs information:")
            print(e)
            if os.path.exists(self.file):
                os.remove(self.file)
[docs]    def delete(self):
        """
        Removes current run information from the current_runs.minf file.
        """
        if os.path.exists(self.file):
            try:
                if self.dontrecordruns:
                    os.unlink(self.file)
                else:
                    self.runs, self.count = readMinf(self.file)
                    self.runs.pop(self.currentRun, None)
                    self.count = len(self.runs)
                    self.write()
            except Exception:
                pass 
[docs]    def check(self, context):
        """
        Checks if there are expired runs and asks the user what to do.
        """
        if self.dontrecordruns:
            return  # don't check in this mode
        if os.path.exists(self.file):
            try:
                self.runs, self.count = readMinf(self.file)
            except Exception as e:
                print('Cannot read "' + self.file + '":', file=sys.stderr)
                print(e, file=sys.stderr)
                return
            currentTime = time.time()
            # check for expired runs
            for n, run in self.runs.items():
                if currentTime - run["time"] > self.timeout:
                    self.expiredRuns[n] = run
            if self.expiredRuns:
                choice = 0
                if gui:  # ask user if brainvisa is not  started in batch mode
                    message = "The following Brainvisa sessions have expired. Maybe they terminated abnormally : \n"
                    for n, run in self.expiredRuns.items():
                        logfile = run.get("logFileName", os.path.join(
                            homeBrainVISADir, 'brainvisa' + str(n) + '.log'))
                        run["logFileName"] = logfile
                        message += "\t- Brainvisa process " + str(run["pid"]) + " on machine " + str(
                            run["host"]) + " started at " + time.ctime(run["time"]) + " - log file : " + logfile + "\n"
                    message += "\nAre these processes still running?\nIf no, sessions information and associated log file will be deleted.\nif yes, the timeout will be increased."
                    currentTime = time.time()
                    choice = context.ask(message, "No", "Yes")
                if choice == 1:  # the processes are still running
                    for n in self.expiredRuns.keys():
                        self.runs[n]["time"] = currentTime
                else:
                    for n in self.expiredRuns.keys():
                        logfile = self.expiredRuns[n].get("logFileName", None)
                        if logfile is not None and os.path.exists(logfile):
                            try:
                                os.remove(logfile)
                                if os.path.exists(logfile + "~"):
                                    os.remove(logfile + "~")
                            except Exception as e:
                                print(e)
                                print("Fail removing log file.")
                        del self.runs[n]
                    self.count = len(self.runs)
                self.write() 
    def write(self):
        writeMinf(self.file, (self.runs, self.count,)) 
# Set log file name
if logFileName is None:
    if userProfile:
        logFileName = os.path.join(
            homeBrainVISADir, 'brainvisa-' + userProfile + '.log')
runsInfo = None
initializeConfiguration()
# add brainvisa shared database to the list of available databases
sharedDatabaseFound = False
try:
    import brainvisa_share.config
    bvShareDirectory = brainvisa_share.config.share
except Exception:
    bvShareDirectory = 'brainvisa-share-' + shortVersion
for p in (os.path.join(getSharePath(), bvShareDirectory),
          os.path.join(getSharePath(), 'shfj-' + shortVersion),
          os.path.join(getSharePath(), 'shfj')):
    if os.path.isdir(p):
        dataPath.insert(0, DatabaseSettings(p, read_only=True))
        dataPath[0].builtin = True  # mark as a builtin, non-removable database
        sharedDatabaseFound = True
        break
class Translator(object):
    def __init__(self, lang=language):
        self.language = lang
        self.translations = self.getTranslations()
    def translate(self, msg):
        return self.translations.get(msg, msg)
    def getTranslations(self):
        translations = dict()
        for filePath in self.getTranslationFiles():
            file = io.open(filePath, 'r', encoding='utf-8')
            translations.update(readMinf(file)[0])
            file.close()
        return translations
    def getTranslationFiles(self):
        baseDocPath = getDocPath(mainPath)
        for directory in os.listdir(baseDocPath):
            file = os.path.join(
                baseDocPath, directory, self.language, 'translation.minf')
            if os.path.exists(file):
                yield file
def initGlobalVariables():
    global mainPath, userProfile, homeBrainVISADir
    for attr, value in readConfiguration(mainPath, userProfile, homeBrainVISADir):
        if isinstance(value, list):
            globals()[attr] += value
        else:
            globals()[attr] = value
    # Clean pathes
    global typesPath, dataPath, processesPath, fileSystemOntologiesPath, matlabPath
    for p in (typesPath, dataPath, processesPath, fileSystemOntologiesPath, matlabPath):
        i = 0
        l = []
        while i < len(p):
            if p[i] in l:
                del p[i]
            else:
                l.append(p[i])
                i += 1
    # Translations
    global docPath, language, _defaultTranslateFunction
    os.environ['LANGUAGE'] = language
    docPath = os.path.join(docPath, language)
    if _t_ is _defaultTranslateFunction:
        
        try:
            six.moves.builtins.__dict__['_t_'] = Translator(language).translate
        except Exception as msg:
            six.moves.builtins.__dict__['_t_'] = lambda x: x
            sys.stderr.write(str(msg) + '\n')
def get_database_settings(name, selected=True, read_only=False):
    global dataPath
    for dbs in dataPath:
        if dbs.directory == name:
            return dbs
    # not found, create a new one
    return DatabaseSettings(name, selected=selected, read_only=read_only)
[docs]def getDocFile(filename):
    """
    Search doc file in doc path and if not found, in english documentation path.
    """
    global docPath, mainDocPath
    path = os.path.join(docPath, filename)
    if not os.path.exists(path):
        path = os.path.join(mainDocPath, "en", filename)
    return path 
# Pathes for binaries and libraries
# (shouldn't we just test platform != 'windows' ?) (Denis)
# if platform != 'windows':
    # if 'PATH' in os.environ:
        # os.environ[ 'PATH' ] = os.path.join( mainPath, 'bin', platform ) + ':' + os.path.join( mainPath, 'bin' ) + ':' + \
                             # os.environ[ 'PATH' ]
    # else:
        # os.environ[ 'PATH' ] = os.path.join( mainPath, 'bin', platform ) + ':' + os.path.join( mainPath, 'bin' )
    # libpathenv = libraryPathEnvironmentVariable()
    # if libpathenv in os.environ:
        # os.environ[ libpathenv ] = \
            # os.path.join( mainPath, 'lib', platform ) + ':' + \
            # os.environ[ libpathenv ]
    # else:
        # os.environ[ libpathenv ] = os.path.join( mainPath, 'lib', platform )
# Setup GUI
_allObjects = {}
def registerObject(object):
    global _allObjects
    _allObjects[object] = object
def unregisterObject(object):
    global _allObjects
    try:
        del _allObjects[object]
        return True
    except Exception:
        return False
def clearObjects():
    global _allObjects
    _allObjects = {}
[docs]def environmentHTML():
    """
    Returns an HTML page displaying Brainvisa configuration:
    * Brainvisa version
    * Python Version
    * Command line used to start Brainvisa
    * Environment variables
    * Brainvisa options (global variables of this module)
    This page is displayed in Brainvisa log in starting Brainvisa item.
    """
    from brainvisa.toolboxes import allToolboxes
    content = '<html><body><h1>' + htmlEscape( versionText() ) + '''</h1>
<h2>''' + _t_( 'Python version' ) + '</h2>' + htmlEscape( sys.version ) + '''
<h2>''' + _t_( 'Command line' ) + '''</h2>
<tt>''' + htmlEscape( commandLine() ) + '''</tt>
<h2>''' + _t_( 'Toolboxes' ) + '</h2>\n' + \
        
'\n'.join((i.name + '<br>' for i in allToolboxes()))
    content += '<h2>' + _t_('Environment variables') + '</h2>'
    for n, v in os.environ.items():
        content += '<tt><em>' + n + '</em> = ' + htmlEscape(v) + '</tt><p>'
    content += '<h2>' + _t_('BrainVISA options') + '</h2>'
    g = globals()
    for n in ('platform', 'gui', 'sessionID', 'userProfile', 'siteOptionFile',
              'userOptionFile',
              'logFileName', 'temporaryDirectory', 'mainPath', 'iconPath',
              'typesPath', 'dataPath', 'processesPath', 'fileSystemOntologiesPath',
              'mainDocPath', 'docPath',
              'anatomistExecutable', 'matlabRelease', 'matlabExecutable',
              'matlabOptions', 'matlabPath',
              #'matlabLibraryDirectory',
              'matlabStartup', 'spmDirectory',
              'logFileName', 'language', 'userLevel',
              'startup', 'supportEmail', 'SMTP_server_name', 'flatHierarchy',
              'textEditor'):
        content += '<code><em>' + n + '</em> = ' + \
            
htmlEscape(str(g[n])) + '</code><p>'
    content += '</body></html>'
    return content