# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
# vi: set ft=python sts=4 ts=4 sw=4 et:
'''
Created on 20 Apr 2010

logging options : INFO, DEBUG
hash_method : content, timestamp

@author: Chris Filo Gorgolewski
'''
from future import standard_library
standard_library.install_aliases()
from builtins import object

import configparser
from json import load, dump
import os
import shutil
import errno
from warnings import warn

from ..external import portalocker
from ..external.six import StringIO


# Get home directory in platform-agnostic way
homedir = os.path.expanduser('~')
default_cfg = """
[logging]
workflow_level = INFO
filemanip_level = INFO
interface_level = INFO
log_to_file = false
log_directory = %s
log_size = 16384000
log_rotate = 4

[execution]
create_report = true
crashdump_dir = %s
display_variable = :1
hash_method = timestamp
job_finished_timeout = 5
keep_inputs = false
local_hash_check = true
matplotlib_backend = Agg
plugin = Linear
remove_node_directories = false
remove_unnecessary_outputs = true
try_hard_link_datasink = true
single_thread_matlab = true
stop_on_first_crash = false
stop_on_first_rerun = false
use_relative_paths = false
stop_on_unknown_version = false
write_provenance = false
parameterize_dirs = true
poll_sleep_duration = 60
xvfb_max_wait = 10
profile_runtime = false

[check]
interval = 1209600
""" % (homedir, os.getcwd())


def mkdir_p(path):
    try:
        os.makedirs(path)
    except OSError as exc:
        if exc.errno == errno.EEXIST and os.path.isdir(path):
            pass
        else:
            raise


class NipypeConfig(object):
    """Base nipype config class
    """

    def __init__(self, *args, **kwargs):
        self._config = configparser.ConfigParser()
        config_dir = os.path.expanduser('~/.nipype')
        mkdir_p(config_dir)
        old_config_file = os.path.expanduser('~/.nipype.cfg')
        new_config_file = os.path.join(config_dir, 'nipype.cfg')
        # To be deprecated in two releases
        if os.path.exists(old_config_file):
            if os.path.exists(new_config_file):
                msg = ("Detected presence of both old (%s, used by versions "
                       "< 0.5.2) and new (%s) config files.  This version will "
                       "proceed with the new one. We advise to merge settings "
                       "and remove old config file if you are not planning to "
                       "use previous releases of nipype.") % (old_config_file,
                                                              new_config_file)
                warn(msg)
            else:
                warn("Moving old config file from: %s to %s" % (old_config_file,
                                                                new_config_file))
                shutil.move(old_config_file, new_config_file)
        self.data_file = os.path.join(config_dir, 'nipype.json')
        self._config.readfp(StringIO(default_cfg))
        self._config.read([new_config_file, old_config_file, 'nipype.cfg'])

    def set_default_config(self):
        self._config.readfp(StringIO(default_cfg))

    def enable_debug_mode(self):
        """Enables debug configuration
        """
        self._config.set('execution', 'stop_on_first_crash', 'true')
        self._config.set('execution', 'remove_unnecessary_outputs', 'false')
        self._config.set('execution', 'keep_inputs', 'true')
        self._config.set('logging', 'workflow_level', 'DEBUG')
        self._config.set('logging', 'interface_level', 'DEBUG')

    def set_log_dir(self, log_dir):
        """Sets logging directory

        This should be the first thing that is done before any nipype class
        with logging is imported.
        """
        self._config.set('logging', 'log_directory', log_dir)

    def get(self, section, option):
        return self._config.get(section, option)

    def set(self, section, option, value):
        if isinstance(value, bool):
            value = str(value)

        return self._config.set(section, option, value)

    def getboolean(self, section, option):
        return self._config.getboolean(section, option)

    def has_option(self, section, option):
        return self._config.has_option(section, option)

    @property
    def _sections(self):
        return self._config._sections

    def get_data(self, key):
        if not os.path.exists(self.data_file):
            return None
        with open(self.data_file, 'rt') as file:
            portalocker.lock(file, portalocker.LOCK_EX)
            datadict = load(file)
        if key in datadict:
            return datadict[key]
        return None

    def save_data(self, key, value):
        datadict = {}
        if os.path.exists(self.data_file):
            with open(self.data_file, 'rt') as file:
                portalocker.lock(file, portalocker.LOCK_EX)
                datadict = load(file)
        with open(self.data_file, 'wt') as file:
            portalocker.lock(file, portalocker.LOCK_EX)
            datadict[key] = value
            dump(datadict, file)

    def update_config(self, config_dict):
        for section in ['execution', 'logging', 'check']:
            if section in config_dict:
                for key, val in list(config_dict[section].items()):
                    if not key.startswith('__'):
                        self._config.set(section, key, str(val))

    def update_matplotlib(self):
        import matplotlib
        matplotlib.use(self.get('execution', 'matplotlib_backend'))

    def enable_provenance(self):
        self._config.set('execution', 'write_provenance', 'true')
        self._config.set('execution', 'hash_method', 'content')
