#coding:utf-8
#########################################################################
"""  minimalconfig.py -- Minimal configuration for IDE

Copyright (c) 1999-2018, Archaeopteryx Software, Inc.  All rights reserved.

Written by Stephan R.A. Deibel and John P. Ehresman

"""
#########################################################################

# This file needs to work with all supported versions of Python

# IMPORTANT:  This module should import as little as possible --
# it gets imported before we install our update manager so anything
# imported here cannot be updated!

# Implementation note: print statements can throw exceptions because
# of unicode conversion failures

import sys
import os

#----------------------------------------------------------------------
def NP_LoadModuleHere(modname):
  """Load the given module from same directory as this file
  without adding it to sys.modules"""
  
  sys.modules.pop(modname, None)
  
  sys.path.insert(0, os.path.dirname(__file__))
  mod = __import__(modname)
  sys.modules.pop(modname, None)
  
  sys.path = sys.path[1:]
  return mod

bootstrap_utils = NP_LoadModuleHere('bootstrap_utils')

# Make sure we get the right values if debugging Wing with itself
bootstrap_vinfo = NP_LoadModuleHere('bootstrap_vinfo')
kInstallVersion = bootstrap_vinfo.kInstallVersion
kProduct = bootstrap_vinfo.kProduct
kOSXBundleName = bootstrap_vinfo.kOSXBundleName
kOSXBundleIdentifier = bootstrap_vinfo.kOSXBundleIdentifier

kMajorVersion = kInstallVersion[0]

# Product codes
kProdPersonal = 0x00000001
kProdProfessional = 0x00000002
kProd101 = 0x00000008

if kProduct.lower().strip()[:3] == 'pro':
  kRunningProduct = kProdProfessional
elif kProduct.lower().strip()[:3] == 'per':
  kRunningProduct = kProdPersonal
else:
  kRunningProduct = kProd101

# Product names
kProductNames = {
  kProd101: '101',
  kProdPersonal: 'Personal',
  kProdProfessional: 'Pro',
}

for key, value in kProductNames.items():
    if value == kProduct:
        kProductCode = key
        break
kProductName = "Wing %s" % kProduct

# Define file system encoding; note that it can be None and defaults to default encoding
# if it is
kFileSystemEncoding = sys.getfilesystemencoding()
if kFileSystemEncoding is None:
    kFileSystemEncoding = sys.getdefaultencoding()

import _winghome
kWingHome = _winghome.kWingHome

def GetUserSettingsDir(major_version, platform=sys.platform, create=True):
    """Get the user settings dir for given version of Wing and platform.  This
    records the history of how the settings directory names have changed over
    time, so that we can pull old settings during upgrades.  When platform
    is None, unconditionally returns the Posix dot directory."""

    def get_posix_dir(major_version):
        if kProduct == '101':
            dirname = '.wing101-%d' % major_version
        elif kProduct == 'Personal' and major_version >= 3:
            dirname = '.wingpersonal%d' % major_version
        else:
            if major_version <= 6:
                dirname = '.wingide%d' % major_version
            else:
                dirname = '.wingpro%d' % major_version
        base_dir = os.path.join(os.path.expanduser('~'), dirname)
        return base_dir
        
    def get_win32_dir(major_version):
        """ Return dir in user's AppData -- can return None, especially on
        cygwin """
        
        # Note that this fails on msys2 build as of Dec 2024 because sys.platform
        # is cygwin but the APPDATA env variable value is a win32 path and not
        # a unixish one. ctypes in the msys2 build is missing support for windll
        # .dll's so minimalwin32 cannot be imported. Issues may be fixable but
        # it's probably not worth the time.
      
        app_dir = None
        # Use win32 api call, except on cygwin where sys.platform is cygwin
        # or cygwin-64. The api call should nearly always work. Note that
        # minimalwin32 is not importable on cygwin
        if sys.platform == 'win32':
            try:
                import minimalwin32
                app_dir = minimalwin32.SHGetFolderPath(minimalwin32.CSIDL_APPDATA, True)
            except:
                app_dir = None
                
        # Fall back on the env variable
        if app_dir is None:
            app_dir = bootstrap_utils._NP_GetUnicodeEnvValue('APPDATA')

        if app_dir is None:
            return None
          
        if kProduct == '101':
            if major_version <= 6:
                subdir = 'Wing IDE 101 %d' % major_version
            else:
                subdir = 'Wing 101 %d' % major_version
        elif kProduct == 'Personal' and major_version >= 3:
            if major_version <= 6:
                subdir = 'Wing IDE Personal %d' % major_version
            else:
                subdir = 'Wing Personal %d' % major_version
        else:
            if major_version <= 6:
                subdir = 'Wing IDE %d' % major_version
            else:
                subdir = 'Wing Pro %d' % major_version

        base_dir = os.path.join(app_dir, subdir)
        return base_dir
        
    def get_cyg_path_for_win_path(p):
    
        if platform != 'cygwin' or not os.path.isdir('/cygdrive'):
            return p
    
        if len(p) < 3 or not p[0].isalpha() or p[1] != ':' or p[2] not in ('\\', '/'):
            return p
    
        return '/cygdrive/' + p[0].lower() + '/' + p[2:].replace('\\', '/')
        
    # Compute fallback directory to use if regular default cannot be created
    if kWingHome is not None and major_version == kMajorVersion:
      fallback_userdir = os.path.join(kWingHome, 'user-settings')
    else:
      fallback_userdir = None
      
    if platform is not None and major_version == kMajorVersion:

      # Determine if user passed in an alternative user settings directory
      # Not supported when running in the debugger, because then _winghome.kUserSettings
      # is already set by the debugger and it is wrong if e.g. debugging Personal with Pro
      if 'WINGDB_ACTIVE' not in os.environ and _winghome.kUserSettings is not None:
        return _winghome.kUserSettings

      settings = None
      try:
        argv = sys.argv
      except AttributeError:
        argv = []
        
      for arg in argv:
          if arg.startswith('--settings='):
              sys.argv.remove(arg)
              settings = arg[len('--settings='):]
              _winghome.kUserSettings = settings
              if not os.path.exists(settings):
                  if os.path.exists(os.path.dirname(settings)):
                      os.mkdir(settings)
                      break
                  else:
                      try:
                          print("Cannot create designated settings directory", settings)
                      except:
                          pass
                      settings = None
      if settings:
          return settings
        
      # Let WINGHOME/user-settings override the default location, if present
      if fallback_userdir is not None and os.path.exists(fallback_userdir):
        return fallback_userdir

    # Special case cygwin: use ~/wing<product> if it exists and contains 1+
    # files / subdirs, otherwise try to use use cygwin path to win32 settings
    # directory
    if platform == 'cygwin':
        base_dir = get_posix_dir(major_version)
        try:
            use_cygwin_home = (len(os.listdir(base_dir)) != 0)
        except OSError:
            use_cygwin_home = False
        if not use_cygwin_home:
            win32_base_dir = get_win32_dir(major_version)
            if win32_base_dir is not None:
                base_dir = get_cyg_path_for_win_path(win32_base_dir)

    elif platform == 'win32':
        base_dir = get_win32_dir(major_version)
                
    elif platform == 'darwin' and major_version >= 5:
        if kProduct == 'Pro' and major_version <= 6:
            base_dir = os.path.expanduser('~/Library/Application Support/%s/v%s'
                                                  % ("Wing IDE", major_version))
        else:
            base_dir = os.path.expanduser('~/Library/Application Support/%s/v%s'
                                                  % (kOSXBundleName, major_version))
        
    else:
        base_dir = get_posix_dir(major_version)

    if sys.version_info < (3, 0) and isinstance(base_dir, bytes):
        base_dir = base_dir.decode(kFileSystemEncoding, 'strict')
    
    # Work around bug in os.path.join on win32
    if base_dir.replace('\\', '/').startswith('//'):
        return os.path.normpath(base_dir)
    
    if sys.version_info < (3, 0):
        cwd = os.getcwdu()
    else:
        cwd = os.getcwd()
        
    userdir = os.path.normpath(os.path.join(cwd, base_dir))

    # Make sure it exists if for currently running version
    def try_create(dirname):
      if os.path.exists(dirname) or major_version != kMajorVersion:
        return True
      
      try:
        CACHE_DIR_UMASK = 0x1c0  # 0o700 in a form that works w/ all Python versions
        os.makedirs(dirname, CACHE_DIR_UMASK)
        return True
      except:
        import traceback
        print("EXCEPTION in os.makedirs for user settings directory", dirname)
        traceback.print_exc()
        return False
      
    # Try to create dir if missing; fail silently so debugger can run on hosts w/ r/o file system
    if create and not try_create(userdir):
      print("FAILURE: Could not create user directory: %s\n" % repr(userdir))
      if fallback_userdir is not None:
        print("Falling back to using %s\n" % repr(fallback_settings))
        userdir = fallback_userdir
        if not try_create(userdir):
          print("ERROR: Also failed to create fallback user directory: %s\n" % userdir)

    return userdir

kUserSettings = GetUserSettingsDir(kMajorVersion)

def GetOldUserSettingsDir():
    """Get next most recent user settings dir, for Wing version before the current one"""
    
    for i in range(kMajorVersion-1, 1, -1):
        old_dir = GetUserSettingsDir(i)
        if os.path.exists(old_dir):
            return old_dir
        
    return None

def _GetDefaultCacheDir(major_version):

    # Determine if user passed in an alternative cache directory
    if _winghome.kCacheDir is not None:
      return _winghome.kCacheDir

    cache_dir = None
    try:
      argv = sys.argv
    except AttributeError:
      argv = []
      
    for arg in argv:
        if arg.startswith('--cache='):
            sys.argv.remove(arg)
            cache_dir = arg[len('--cache='):]
            _winghome.kCacheDir = cache_dir
            if not os.path.exists(cache_dir):
                if os.path.exists(os.path.dirname(cache_dir)):
                    os.mkdir(cache_dir)
                    break
                else:
                    try:
                        print("Cannot create designated cache directory", cache_dir)
                    except:
                        pass
                    cache_dir = None
    if cache_dir:
        return cache_dir

    if sys.platform == 'win32':
        import minimalwin32
        if major_version >= 2:
            try:
                app_dir = minimalwin32.SHGetFolderPath(minimalwin32.CSIDL_LOCAL_APPDATA, True)
            except:
                pass
            else:
                if kProduct == '101':
                    return os.path.join(app_dir, 'Wing 101 %d' % major_version)
                elif kProduct == 'Personal' and major_version >= 3:
                    return os.path.join(app_dir, 'Wing Personal %d' % major_version)
                else:
                    # XXX Change to Wing Pro %d in Wing 7+
                    return os.path.join(app_dir, 'Wing Pro %d' % major_version)
    elif sys.platform == 'darwin' and major_version >= 5:
        base_dir = os.path.expanduser('~/Library/Caches/%s/v%s'
                                      % (kOSXBundleIdentifier, major_version))
        if sys.version_info < (3, 0, 0):
            return base_dir.decode(kFileSystemEncoding, 'strict')
        else:
            return base_dir
    else:
        if major_version >= 4:
            xdg_cache_dir = os.environ.get('XDG_CACHE_DIR')
            if xdg_cache_dir is None:
                xdg_cache_dir = os.path.join(os.path.expanduser('~'), '.cache')
            if kProduct == '101':
                base_dir = os.path.join(xdg_cache_dir, 'wing101-%d' % major_version)
            elif kProduct == 'Personal':
                base_dir = os.path.join(xdg_cache_dir, 'wingpersonal%d' % major_version)      
            else:
                base_dir = os.path.join(xdg_cache_dir, 'wingpro%d' % major_version)
            if sys.version_info < (3, 0, 0):
                return unicode(base_dir, kFileSystemEncoding, 'strict')
            else:
                return base_dir

    return GetUserSettingsDir(major_version)

kCacheDir = _GetDefaultCacheDir(kMajorVersion)

