# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# Copyright (c) Spyder Project Contributors
#
# Licensed under the terms of the MIT License
# (see spyder/__init__.py for details)
# -----------------------------------------------------------------------------
"""Miscellaneous utilities."""

# yapf: disable

# Standard library imports
import os
import os.path as osp
import stat
import tempfile

# Third party imports
import psutil

# Local imports
from anaconda_navigator.config import LOCKFILE, PIDFILE


# yapf: enable


def __remove_pyc_pyo(fname):
    """Eventually remove .pyc and .pyo files associated to a Python script"""
    if osp.splitext(fname)[1] == '.py':
        for ending in ('c', 'o'):
            if osp.exists(fname + ending):
                os.remove(fname + ending)


def rename_file(source, dest):
    """
    Rename file from *source* to *dest*
    If file is a Python script, also rename .pyc and .pyo files if any
    """
    os.rename(source, dest)
    __remove_pyc_pyo(source)


def remove_file(fname):
    """
    Remove file *fname*
    If file is a Python script, also rename .pyc and .pyo files if any
    """
    os.remove(fname)
    __remove_pyc_pyo(fname)


def move_file(source, dest):
    """
    Move file from *source* to *dest*
    If file is a Python script, also rename .pyc and .pyo files if any
    """
    import shutil
    shutil.copy(source, dest)
    remove_file(source)


def onerror(function, path, excinfo):
    """Error handler for `shutil.rmtree`.

    If the error is due to an access error (read-only file), it
    attempts to add write permission and then retries.
    If the error is for another reason, it re-raises the error.

    Usage: `shutil.rmtree(path, onerror=onerror)"""
    if not os.access(path, os.W_OK):
        # Is the error an access error?
        os.chmod(path, stat.S_IWUSR)
        function(path)
    else:
        raise


def abspardir(path):
    """Return absolute parent dir"""
    return osp.abspath(osp.join(path, os.pardir))


def get_common_path(pathlist):
    """Return common path for all paths in pathlist"""
    common = osp.normpath(osp.commonprefix(pathlist))
    if len(common) > 1:
        if not osp.isdir(common):
            return abspardir(common)
        else:
            for path in pathlist:
                if not osp.isdir(osp.join(common, path[len(common) + 1:])):
                    # `common` is not the real common prefix
                    return abspardir(common)
            else:
                return osp.abspath(common)


def path_is_writable(path):
    """Check if given path is writable."""
    path = os.path.abspath(os.path.expanduser(os.path.expandvars(path)))

    if os.path.isfile(path):
        test_filepath = path
        remove = False
    else:
        path_exists = os.path.isdir(path)
        remove = True
        if not path_exists:
            try:
                os.makedirs(path)
            except Exception:
                return False

        i, temp_folder = tempfile.mkstemp()
        temp_name = os.path.basename(temp_folder)
        test_filepath = os.path.join(path, temp_name)

    try:
        fh = open(test_filepath, 'a+')
    except (IOError, OSError):
        return False
    else:
        fh.close()
        try:
            if remove:
                os.remove(test_filepath)
            if not path_exists:
                os.rmdir(path)
        except Exception:
            pass
        return True


def save_pid():
    """Save navigator process ID."""
    pid = os.getpid()

    try:
        with open(PIDFILE, 'w') as f:
            f.write(str(pid))
    except Exception:
        pid = None

    return pid


def load_pid():
    """Load navigator process ID."""
    try:
        with open(PIDFILE, 'r') as f:
            pid = f.read()
        pid = int(pid)
    except Exception:
        pid = None

    if pid is not None:
        is_running = psutil.pid_exists(pid)
        process = None
        cmds = []
        try:
            process = psutil.Process(pid)
            if process and is_running:
                cmds = process.cmdline()
        except psutil.NoSuchProcess:
            # print('no such process')
            pass
        except psutil.AccessDenied:
            # Try to remove the pid file, if not possible return False
            if not remove_pid():
                return False

        cmds = [cmd.lower() for cmd in cmds]

        # Check bootstrap
        ch1 = [c for c in cmds if 'python' in c or 'bootstrap.py' in c]
        ch2 = [c for c in cmds if 'python' in c or 'anaconda-navigator' in c]
        ch3 = [c for c in cmds if 'navigator.app' in c]

        check = any(ch1) or any(ch2) or any(ch3)

        if not check:
            pid = None

    return pid


def remove_pid():
    """Load navigator process ID."""
    check = True
    try:
        os.remove(PIDFILE)
    except Exception:
        check = False
    return check


def remove_lock():
    """Load navigator process ID."""
    check = True
    try:
        os.remove(LOCKFILE)
    except Exception:
        check = False
    return check


def set_windows_appusermodelid():
    """Make sure correct icon is used on Windows 7 taskbar"""
    try:
        from ctypes import windll
        name = "anaconda.Anaconda-Navigator"
        return windll.shell32.SetCurrentProcessExplicitAppUserModelID(name)
    except AttributeError:
        return "SetCurrentProcessExplicitAppUserModelID not found"


if __name__ == '__main__':
    if os.name == 'nt':
        assert get_common_path(
            [
                'D:\\Python\\spyder-v21\\spyder\\widgets',
                'D:\\Python\\spyder\\spyder\\utils',
                'D:\\Python\\spyder\\spyder\\widgets',
                'D:\\Python\\spyder-v21\\spyder\\utils',
            ]
        ) == 'D:\\Python'
    else:
        assert get_common_path(
            [
                '/Python/spyder-v21/spyder.widgets',
                '/Python/spyder/spyder.utils',
                '/Python/spyder/spyder.widgets',
                '/Python/spyder-v21/spyder.utils',
            ]
        ) == '/Python'
    print(save_pid())
    print(load_pid())
    print(remove_pid())
