# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/01_config.ipynb.

# %% auto 0
__all__ = ['find_dir_edition', 'set_pystata_path', 'launch_stata', 'set_graph_format', 'set_graph_size', 'is_graph_size_valid',
           'Config']

# %% ../nbs/01_config.ipynb 5
from .misc_utils import print_red
import os
import sys
import platform
from shutil import which
from pathlib import Path
from packaging import version
from configparser import ConfigParser, NoSectionError

# %% ../nbs/01_config.ipynb 6
def _win_find_path():
    import winreg
    reg = winreg.ConnectRegistry(None, winreg.HKEY_CLASSES_ROOT)
    subkeys = [r'Stata17Do\shell\do\command',
                r'Stata18Do\shell\do\command',
                r'Stata19Do\shell\do\command']

    fpath = ''
    for subkey in subkeys:
        try:
            key = winreg.OpenKey(reg, subkey)
            fpath = winreg.QueryValue(key, None).split('"')[1]
        except FileNotFoundError:
            pass
        if fpath:
            break

    return fpath


def _mac_find_path():
    """
    Attempt to find Stata path on macOS when not on user's PATH.
    Modified from stata_kernel's original to only location "Applications/Stata". 

    Returns:
        (str): Path to Stata. Empty string if not found.
    """
    path = Path('/Applications/Stata')
    if not path.exists():
        return ''
    else:
        return str(path)

# %% ../nbs/01_config.ipynb 7
def _find_path():
    if os.getenv('CONTINUOUS_INTEGRATION'):
        print('WARNING: Running as CI; Stata path not set correctly')
        return 'stata'
    if platform.system() == 'Windows':
        return _win_find_path()
    elif platform.system() == 'Darwin':
        return _mac_find_path()
    else:
        for i in ['stata-mp', 'stata-se', 'stata']:
            stata_path = which(i)
            if stata_path:
                break
        return stata_path

# %% ../nbs/01_config.ipynb 9
def find_dir_edition():
    stata_path = _find_path()
    if stata_path is None:
        raise OSError("Stata path not found.")
    stata_dir = str(os.path.dirname(stata_path))
    stata_exe = str(os.path.basename(stata_path)).lower()

    edition = 'be'
    for e in ('se','mp'):
        if stata_exe.find(e) > -1:
            edition = e            
    return stata_dir, edition

# %% ../nbs/01_config.ipynb 12
def set_pystata_path(path=None):
    if path == None:
        path, _ = find_dir_edition()
    if not os.path.isdir(path):
        raise OSError(path + ' is invalid')
    if not os.path.isdir(os.path.join(path, 'utilities')):
        raise OSError(path + " is not Stata's installation path")
    sys.path.append(os.path.join(path, 'utilities'))

# %% ../nbs/01_config.ipynb 16
def launch_stata(path=None, edition=None, splash=True):
    """
    We modify stata_setup to make splash screen optional
    """
    try:
        if path == None or edition == None:
            path_found, edition_found = find_dir_edition()
            path = path_found if path==None else path
            edition = edition_found if edition==None else edition
        set_pystata_path(path)
    except OSError as err:
        pass
    import pystata
    if version.parse(pystata.__version__) >= version.parse("0.1.1"):
        # Splash message control is a new feature of pystata-0.1.1
        pystata.config.init(edition,splash=splash)
    else:
        pystata.config.init(edition)

# %% ../nbs/01_config.ipynb 21
def set_graph_format(gformat):
    import pystata
    if gformat == 'pystata':
        gformat = 'svg' # pystata default
    pystata.config.set_graph_format(gformat)

# %% ../nbs/01_config.ipynb 23
def set_graph_size(width, height):
    import pystata
    pystata.config.set_graph_size(width, height)

# %% ../nbs/01_config.ipynb 25
def is_graph_size_valid(size):
    import pystata
    try:
        size = pystata.config._get_figure_size_info(str(size))
        if size[0] == 'default' or size[0] < 0:
            raise ValueError('graph size is invalid')
    except ValueError:
        return False
    else:
        return True

# %% ../nbs/01_config.ipynb 29
def _get_config_settings(cpath):
    parser = ConfigParser(
        empty_lines_in_values=False,
        comment_prefixes=('*','//'),
        inline_comment_prefixes=('//',),
    )
    parser.read(str(cpath))
    return dict(parser.items('nbstata'))

# %% ../nbs/01_config.ipynb 30
class Config:
    env = {'stata_dir': None,
           'edition': 'be',
           'graph_format': 'png',
           'graph_width': '5.5in',
           'graph_height': '4in',
           'echo': 'None',
           'splash': 'False',
           'missing': '.',
          }
    valid_values_of = dict(
        graph_format={'pystata', 'svg', 'png', 'pdf'},
        echo={'True', 'False', 'None'},
        splash={'True', 'False'},
    )
    
    @property
    def splash(self):
        return False if self.env['splash']=='False' else True
    
    @property
    def noecho(self):
        return self.env['echo'] == 'None'
    
    @property
    def echo(self):
        return self.env['echo'] == 'True'
    
    def __init__(self):
        """First check if a configuration file exists. If not, try `find_dir_edition`."""
        self.errors = []
        self.config_path = None
        self._process_config_file()
        if self.env['stata_dir'] == None or self.env['edition'] == None:
            try:    
                stata_dir, stata_ed = find_dir_edition()     
            except OSError:
                pass
            else:
                self.env.update({'stata_dir': stata_dir, 'edition': stata_ed})

    def _process_config_file(self):
        global_config_path = Path(os.path.join(sys.prefix, 'etc', 'nbstata.conf'))
        user_config_path = Path('~/.nbstata.conf').expanduser()
        for cpath in (user_config_path, global_config_path):      
            if cpath.is_file():
                self._get_config_env(cpath)
                break
            
    def _get_config_env(self, cpath):
        try:
            settings = _get_config_settings(cpath)
        except ParsingError:
            print_red(f"Configuration error in {cpath}:\n"
                      "    invalid syntax")
        except DuplicateOptionError:
            print_red(f"Configuration error in {cpath}:\n"
                      "    attempted to set the same thing twice")
        except ConfigParserError:
            print_red(f"Configuration error in {cpath}")
        else:
            self.config_path = str(cpath)
            self.update(
                settings, 
                init=True, 
                error_header=f"Configuration errors in {self.config_path}:"  
            )
            
    def update(self, env, init=False, error_header="%set error(s):"):
        allowed_settings = self.env if init else set(self.env)-{'stata_dir','edition'}
        for key in list(env):
            if key not in allowed_settings:
                self.errors.append(f"    '{key}' is not a valid setting.")
                env.pop(key)
            elif (
                (key in self.valid_values_of and env[key] not in self.valid_values_of[key])
                or (key in {'graph_width', 'graph_height'} and not is_graph_size_valid(env[key]))
            ):
                self.errors.append(
                    f"    '{key}' configuration invalid. "
                    f"Reverting to: {key} = {self.env[key]}"
                )
                env.pop(key)
        self._display_and_clear_update_errors(error_header)
        for key in env:
            if not init: print(f"{key} was {self.env[key]}, is now {env[key]}")
        self.env.update(env)
  
    def _display_and_clear_update_errors(self, error_header):
        if self.errors:
            print_red(error_header)
        for message in self.errors:
            print_red(message)
        self.errors = []
        
    def display_status(self):
        import pystata
        pystata.config.status()
        print(f"""
      echo                   {self.env['echo']}
      missing                {self.env['missing']}""")
