"""
Append module search paths for third-party packages to sys.path.

This is stripped down and customized for use in py2app applications
"""

import sys
import os


def makepath(*paths):
    dir = os.path.abspath(os.path.join(*paths))
    return dir, os.path.normcase(dir)


def abs__file__():
    """Set all module __file__ attribute to an absolute path"""
    for m in sys.modules.values():
        if hasattr(m, '__loader__'):
            continue  # don't mess with a PEP 302-supplied __file__
        try:
            m.__file__ = os.path.abspath(m.__file__)
        except AttributeError:
            continue


# This ensures that the initial path provided by the interpreter contains
# only absolute pathnames, even if we're running from the build directory.
L = []
_dirs_in_sys_path = {}
dir = dircase = None  # sys.path may be empty at this point
for dir in sys.path:
    # Filter out duplicate paths (on case-insensitive file systems also
    # if they only differ in case); turn relative paths into absolute
    # paths.
    dir, dircase = makepath(dir)
    if dircase not in _dirs_in_sys_path:
        L.append(dir)
        _dirs_in_sys_path[dircase] = 1
sys.path[:] = L
del dir, dircase, L
_dirs_in_sys_path = None


def _init_pathinfo():
    global _dirs_in_sys_path
    _dirs_in_sys_path = d = {}
    for dir in sys.path:
        if dir and not os.path.isdir(dir):
            continue
        dir, dircase = makepath(dir)
        d[dircase] = 1


def addsitedir(sitedir):
    global _dirs_in_sys_path
    if _dirs_in_sys_path is None:
        _init_pathinfo()
        reset = 1
    else:
        reset = 0
    sitedir, sitedircase = makepath(sitedir)
    if sitedircase not in _dirs_in_sys_path:
        sys.path.append(sitedir)  # Add path component
    try:
        names = os.listdir(sitedir)
    except os.error:
        return
    names.sort()
    for name in names:
        if name[-4:] == os.extsep + "pth":
            addpackage(sitedir, name)
    if reset:
        _dirs_in_sys_path = None


def addpackage(sitedir, name):
    global _dirs_in_sys_path
    if _dirs_in_sys_path is None:
        _init_pathinfo()
        reset = 1
    else:
        reset = 0
    fullname = os.path.join(sitedir, name)
    try:
        f = open(fullname)
    except IOError:
        return
    while True:
        dir = f.readline()
        if not dir:
            break
        if dir[0] == '#':
            continue
        if dir.startswith("import"):
            exec dir
            continue
        if dir[-1] == '\n':
            dir = dir[:-1]
        dir, dircase = makepath(sitedir, dir)
        if dircase not in _dirs_in_sys_path and os.path.exists(dir):
            sys.path.append(dir)
            _dirs_in_sys_path[dircase] = 1
    if reset:
        _dirs_in_sys_path = None


# Remove sys.setdefaultencoding() so that users cannot change the
# encoding after initialization.  The test for presence is needed when
# this module is run as a script, because this code is executed twice.
#
if hasattr(sys, "setdefaultencoding"):
    sys.setdefaultencoding('utf-8')
    del sys.setdefaultencoding


def run_entry_point():
    bname, mod, func = sys.calibre_basename, sys.calibre_module, sys.calibre_function
    sys.argv[0] = bname
    pmod = __import__(mod, fromlist=[1], level=0)
    return getattr(pmod, func)()


def read_user_env_vars():
    try:
        with open(os.path.expanduser('~/Library/Preferences/calibre/macos-env.txt'), 'rb') as f:
            raw = f.read().decode('utf-8', 'replace')
    except EnvironmentError as err:
        return
    for line in raw.splitlines():
        if line.startswith('#'):
            continue
        parts = line.split('=', 1)
        if len(parts) == 2:
            key, val = parts
            os.environ[key] = os.path.expandvars(os.path.expanduser(val))


def add_calibre_vars(base):
    sys.frameworks_dir = os.path.join(os.path.dirname(base), 'Frameworks')
    sys.resources_location = os.path.abspath(os.path.join(base, 'resources'))
    sys.extensions_location = os.path.join(sys.frameworks_dir, 'plugins')
    sys.binaries_path = os.path.join(os.path.dirname(base), 'MacOS')

    try:
        read_user_env_vars()
    except Exception as err:
        try:
            sys.stderr.write('Failed to read user env vars with error: {}\n'.format(err))
            sys.stderr.flush()
        except Exception:
            pass

    dv = os.environ.get('CALIBRE_DEVELOP_FROM', None)
    if dv and os.path.exists(dv):
        sys.path.insert(0, os.path.abspath(dv))


def nuke_stdout():
    # Redirect stdout, stdin and stderr to /dev/null
    from calibre.constants import plugins
    plugins['speedup'][0].detach(os.devnull)


def main():
    global __file__

    # Needed on OS X <= 10.8, which passes -psn_... as a command line arg when
    # starting via launch services
    for arg in tuple(sys.argv[1:]):
        if arg.startswith('-psn_'):
            sys.argv.remove(arg)

    base = sys.resourcepath
    sys.frozen = 'macosx_app'
    sys.new_app_bundle = True
    abs__file__()

    add_calibre_vars(base)
    addsitedir(sys.site_packages)

    if sys.calibre_is_gui_app and not (
        sys.stdout.isatty() or sys.stderr.isatty() or sys.stdin.isatty()
    ):
        nuke_stdout()

    return run_entry_point()
