import numbers
import sys
from os import getenv, makedirs, mkdir, pardir
from os.path import expanduser, dirname, isdir, join, normpath
from sys import platform


appname = 'EDMarketConnector'
applongname = 'E:D Market Connector'
appcmdname = 'EDMC'
appversion = '2.1.7.2'

update_feed = 'https://marginal.org.uk/edmarketconnector.xml'
update_interval = 47*60*60


if platform=='darwin':
    from Foundation import NSBundle, NSUserDefaults, NSSearchPathForDirectoriesInDomains, NSApplicationSupportDirectory, NSDocumentDirectory, NSLibraryDirectory, NSUserDomainMask

elif platform=='win32':
    import ctypes

    CSIDL_PERSONAL = 0x0005
    CSIDL_LOCAL_APPDATA = 0x001C
    CSIDL_PROFILE = 0x0028

    # _winreg that ships with Python 2 doesn't support unicode, so do this instead
    from ctypes.wintypes import *

    HKEY_CURRENT_USER       = 0x80000001
    KEY_ALL_ACCESS          = 0x000F003F
    REG_CREATED_NEW_KEY     = 0x00000001
    REG_OPENED_EXISTING_KEY = 0x00000002
    REG_SZ    = 1
    REG_DWORD = 4
    REG_MULTI_SZ = 7

    RegCreateKeyEx = ctypes.windll.advapi32.RegCreateKeyExW
    RegCreateKeyEx.restype = LONG
    RegCreateKeyEx.argtypes = [HKEY, LPCWSTR, DWORD, LPCVOID, DWORD, DWORD, LPCVOID, ctypes.POINTER(HKEY), ctypes.POINTER(DWORD)]

    RegOpenKeyEx = ctypes.windll.advapi32.RegOpenKeyExW
    RegOpenKeyEx.restype = LONG
    RegOpenKeyEx.argtypes = [HKEY, LPCWSTR, DWORD, DWORD, ctypes.POINTER(HKEY)]

    RegCloseKey = ctypes.windll.advapi32.RegCloseKey
    RegCloseKey.restype = LONG
    RegCloseKey.argtypes = [HKEY]

    RegQueryValueEx = ctypes.windll.advapi32.RegQueryValueExW
    RegQueryValueEx.restype = LONG
    RegQueryValueEx.argtypes = [HKEY, LPCWSTR, LPCVOID, ctypes.POINTER(DWORD), LPCVOID, ctypes.POINTER(DWORD)]

    RegSetValueEx = ctypes.windll.advapi32.RegSetValueExW
    RegSetValueEx.restype = LONG
    RegSetValueEx.argtypes = [HKEY, LPCWSTR, LPCVOID, DWORD, LPCVOID, DWORD]

    RegCopyTree = ctypes.windll.advapi32.RegCopyTreeW
    RegCopyTree.restype = LONG
    RegCopyTree.argtypes = [HKEY, LPCWSTR, HKEY]

    RegDeleteKey = ctypes.windll.advapi32.RegDeleteTreeW
    RegDeleteKey.restype = LONG
    RegDeleteKey.argtypes = [HKEY, LPCWSTR]

    RegDeleteValue = ctypes.windll.advapi32.RegDeleteValueW
    RegDeleteValue.restype = LONG
    RegDeleteValue.argtypes = [HKEY, LPCWSTR]

elif platform=='linux2':
    import codecs
    # requires python-iniparse package - ConfigParser that ships with Python < 3.2 doesn't support unicode
    from iniparse import RawConfigParser


class Config:

    OUT_MKT_EDDN      = 1
    OUT_MKT_BPC       = 2
    OUT_MKT_TD        = 4
    OUT_MKT_CSV       = 8
    OUT_SHIP_EDS      = 16
    # OUT_SYS_FILE    = 32	# No longer supported
    # OUT_STAT        = 64	# No longer available
    OUT_SHIP_CORIOLIS = 128
    OUT_SYS_EDSM      = 256
    # OUT_SYS_AUTO    = 512	# Now always automatic
    OUT_MKT_MANUAL    = 1024

    if platform=='darwin':

        def __init__(self):
            self.app_dir = join(NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, True)[0], appname)
            if not isdir(self.app_dir):
                mkdir(self.app_dir)

            self.plugin_dir = join(self.app_dir, 'plugins')
            if not isdir(self.plugin_dir):
                mkdir(self.plugin_dir)

            self.home = expanduser('~')

            self.respath = getattr(sys, 'frozen', False) and normpath(join(dirname(sys.executable), pardir, 'Resources')) or dirname(__file__)

            if not getattr(sys, 'frozen', False):
                # Don't use Python's settings if interactive
                self.bundle = 'uk.org.marginal.%s' % appname.lower()
                NSBundle.mainBundle().infoDictionary()['CFBundleIdentifier'] = self.bundle
            else:
                self.bundle = NSBundle.mainBundle().bundleIdentifier()
            self.defaults = NSUserDefaults.standardUserDefaults()
            self.settings = dict(self.defaults.persistentDomainForName_(self.bundle) or {})	# make writeable

            # Check out_dir exists
            if not self.get('outdir') or not isdir(self.get('outdir')):
                self.set('outdir', NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, True)[0])

        def get(self, key):
            val = self.settings.get(key)
            if hasattr(val, '__iter__'):
                return list(val)	# make writeable
            else:
                return val

        def getint(self, key):
            try:
                return int(self.settings.get(key, 0))	# should already be int, but check by casting
            except:
                return 0

        def set(self, key, val):
            self.settings[key] = val

        def delete(self, key):
            self.settings.pop(key, None)

        def save(self):
            self.defaults.setPersistentDomain_forName_(self.settings, self.bundle)
            self.defaults.synchronize()

        def close(self):
            self.save()
            self.defaults = None

    elif platform=='win32':

        def __init__(self):

            buf = ctypes.create_unicode_buffer(MAX_PATH)
            ctypes.windll.shell32.SHGetSpecialFolderPathW(0, buf, CSIDL_LOCAL_APPDATA, 0)
            self.app_dir = join(buf.value, appname)
            if not isdir(self.app_dir):
                mkdir(self.app_dir)
            
            self.plugin_dir = join(self.app_dir, 'plugins')
            if not isdir(self.plugin_dir):
                mkdir(self.plugin_dir)

            # expanduser in Python 2 on Windows doesn't handle non-ASCII - http://bugs.python.org/issue13207
            ctypes.windll.shell32.SHGetSpecialFolderPathW(0, buf, CSIDL_PROFILE, 0)
            self.home = buf.value

            self.respath = dirname(getattr(sys, 'frozen', False) and sys.executable or __file__)

            self.hkey = HKEY()
            disposition = DWORD()
            if RegCreateKeyEx(HKEY_CURRENT_USER, r'Software\Marginal\EDMarketConnector', 0, None, 0, KEY_ALL_ACCESS, None, ctypes.byref(self.hkey), ctypes.byref(disposition)):
                raise Exception()

            if disposition.value == REG_CREATED_NEW_KEY:

                # Migrate pre-1.3.4 registry location
                oldkey = HKEY()
                if not RegOpenKeyEx(HKEY_CURRENT_USER, r'Software\EDMarketConnector', 0, KEY_ALL_ACCESS, ctypes.byref(oldkey)):
                    RegCopyTree(oldkey, None, self.hkey)
                    RegCloseKey(oldkey)
                    RegDeleteKey(HKEY_CURRENT_USER, r'Software\EDMarketConnector')

                # set WinSparkle defaults - https://github.com/vslavik/winsparkle/wiki/Registry-Settings
                sparklekey = HKEY()
                if not RegCreateKeyEx(self.hkey, 'WinSparkle', 0, None, 0, KEY_ALL_ACCESS, None, ctypes.byref(sparklekey), ctypes.byref(disposition)):
                    if disposition.value == REG_CREATED_NEW_KEY:
                        buf = ctypes.create_unicode_buffer('1')
                        RegSetValueEx(sparklekey, 'CheckForUpdates', 0, 1, buf, len(buf)*2)
                        buf = ctypes.create_unicode_buffer(unicode(update_interval))
                        RegSetValueEx(sparklekey, 'UpdateInterval', 0, 1, buf, len(buf)*2)
                    RegCloseKey(sparklekey)

            if not self.get('outdir') or not isdir(self.get('outdir')):
                buf = ctypes.create_unicode_buffer(MAX_PATH)
                ctypes.windll.shell32.SHGetSpecialFolderPathW(0, buf, CSIDL_PERSONAL, 0)
                self.set('outdir', buf.value)

        def get(self, key):
            typ  = DWORD()
            size = DWORD()
            if RegQueryValueEx(self.hkey, key, 0, ctypes.byref(typ), None, ctypes.byref(size)) or typ.value not in [REG_SZ, REG_MULTI_SZ]:
                return None
            buf = ctypes.create_unicode_buffer(size.value / 2)
            if RegQueryValueEx(self.hkey, key, 0, ctypes.byref(typ), buf, ctypes.byref(size)):
                return None
            elif typ.value == REG_MULTI_SZ:
                return [x.strip() for x in ctypes.wstring_at(buf, len(buf)-2).split(u'\x00')]
            else:
                return buf.value

        def getint(self, key):
            typ  = DWORD()
            size = DWORD(4)
            val  = DWORD()
            if RegQueryValueEx(self.hkey, key, 0, ctypes.byref(typ), ctypes.byref(val), ctypes.byref(size)) or typ.value != REG_DWORD:
                return 0
            else:
                return val.value

        def set(self, key, val):
            if isinstance(val, basestring):
                buf = ctypes.create_unicode_buffer(val)
                RegSetValueEx(self.hkey, key, 0, REG_SZ, buf, len(buf)*2)
            elif isinstance(val, numbers.Integral):
                RegSetValueEx(self.hkey, key, 0, REG_DWORD, ctypes.byref(DWORD(val)), 4)
            elif hasattr(val, '__iter__'):	# iterable
                stringval = u'\x00'.join([unicode(x) or u' ' for x in val] + [u''])	# null terminated non-empty strings
                buf = ctypes.create_unicode_buffer(stringval)
                RegSetValueEx(self.hkey, key, 0, REG_MULTI_SZ, buf, len(buf)*2)
            else:
                raise NotImplementedError()

        def delete(self, key):
            RegDeleteValue(self.hkey, key)

        def save(self):
            pass	# Redundant since registry keys are written immediately

        def close(self):
            RegCloseKey(self.hkey)
            self.hkey = None

    elif platform=='linux2':

        SECTION = 'config'

        def __init__(self):

            # http://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
            self.app_dir = join(getenv('XDG_DATA_HOME', expanduser('~/.local/share')), appname)
            if not isdir(self.app_dir):
                makedirs(self.app_dir)

            self.plugin_dir = join(self.app_dir, 'plugins')
            if not isdir(self.plugin_dir):
                mkdir(self.plugin_dir)

            self.home = expanduser('~')

            self.respath = dirname(__file__)

            self.filename = join(getenv('XDG_CONFIG_HOME', expanduser('~/.config')), appname, '%s.ini' % appname)
            if not isdir(dirname(self.filename)):
                makedirs(dirname(self.filename))

            self.config = RawConfigParser()
            try:
                self.config.readfp(codecs.open(self.filename, 'r', 'utf-8'))
            except:
                self.config.add_section(self.SECTION)

            if not self.get('outdir') or not isdir(self.get('outdir')):
                self.set('outdir', expanduser('~'))

        def get(self, key):
            try:
                val = self.config.get(self.SECTION, key)
                if u'\n' in val:
                    return val.split(u'\n')
                else:
                    return val
            except:
                return None

        def getint(self, key):
            try:
                return self.config.getint(self.SECTION, key)
            except:
                return 0

        def set(self, key, val):
            if isinstance(val, basestring) or isinstance(val, numbers.Integral):
                self.config.set(self.SECTION, key, val)
            elif hasattr(val, '__iter__'):	# iterable
                self.config.set(self.SECTION, key, u'\n'.join([unicode(x) for x in val]))
            else:
                raise NotImplementedError()

        def delete(self, key):
            self.config.remove_option(self.SECTION, key)

        def save(self):
            with codecs.open(self.filename, 'w', 'utf-8') as h:
                h.write(unicode(self.config.data))

        def close(self):
            self.save()
            self.config = None

    else:	# ???

        def __init__(self):
            raise NotImplementedError('Implement me')

# singleton
config = Config()