# -*- coding: utf-8 -*-
"""

PyMzn can be configured with custom executable paths and other variables.
Configuration is done via the module ``pymzn.config``. For instance::

    import pymzn.config

    pymzn.config.set('mzn2fzn', 'path/to/mzn2fzn')
    pymzn.config.set('solns2out', 'path/to/solns2out')

The configurable properties used by PyMzn are the following:

 * **mzn2fzn**: Path to the *mzn2fzn* executable;
 * **solns2out**: Path to the *solns2out* executable;
 * **solver**: Solver instance to use when calling pymzn.minizinc;
 * **solver_args**: Arguments to pass to the solver when calling pymzn.minizinc;
 * **keep**: Overrides the keep flag of all minizinc and mzn2fzn calls;
 * **output_dir**: Set a default output directory for generated files;
 * **force_flatten**: Overrides the force_flatten flag of all minizinc calls;
 * **no_output_annotations**: Overrides the no_output_annotation flag of all
   minizinc calls;
 * **dzn_width**: The horizontal character limit for dzn files;
   This property is used to wrap long dzn statements when writing dzn files.
   This property is also used in the ``pymzn.minizinc`` function as a limit to
   decide whether to write the inline data into a file.

One can also set custom properties to be used for custom solvers.


Debug
-----

PyMzn can also be set to print debugging messages on standard output via::

    pymzn.debug()

This function is meant to be used in interactive sessions or in
applications that do not configure the ``logging`` library. If you configure the
``logging`` library in your application, then PyMzn will print logging messages
as well. The logging level in PyMzn is always ``DEBUG``. To disable debugging
messages you can then call::

    pymzn.debug(False)

"""
import os


_modified = False
_config = None
_defaults = {
    'mzn2fzn': 'mzn2fzn',
    'solns2out': 'solns2out',
    'dzn_width': 70
}


def _cfg_file():
    try:
        import appdirs
        return os.path.join(appdirs.user_config_dir(__name__), 'config.yml')
    except ImportError:
        return None


def get(key, default=None):
    """Get the value of a configuration variable.

    Parameters
    ----------
    key : str
        The key of the variable to retrieve.
    default
        The default value to return if the key does not exist.

    Returns
    -------
        The value associated to the key if the key exists, otherwise the default
        if provided.
    """
    global _config
    if _config is None:
        _config = {}
        try:
            import yaml
            cfg_file = _cfg_file()
            if cfg_file and os.path.isfile(cfg_file):
                with open(cfg_file) as f:
                    _config = yaml.load(f)
        except ImportError:
            pass
    if default is None:
        default = _defaults.get(key)
    return _config.get(key, default)


def set(key, value):
    """Set the value of configuration variable.

    Parameters
    ----------
    key : str
        The key of the variable to set.
    value
        The value to assign to the variable.
    """
    global _config
    global _modified
    if get(key) != value:
        _config[key] = value
        _modified = True


def dump():
    """Writes the changes to the configuration file."""
    global _config
    global _modified
    if _modified:
        try:
            import yaml
            cfg_file = _cfg_file()
            cfg_dir, __ = os.path.split(cfg_file)
            os.makedirs(cfg_dir, exist_ok=True)
            with open(cfg_file, 'w') as f:
                yaml.dump(_config, f)
            _modified = False
        except ImportError as err:
            raise RuntimeError(
                'Cannot dump the configuration settings to file. You need to '
                'install the necessary dependencies (pyyaml, appdirs).'
            ) from err

