# -*- coding: utf-8 -*-
'''
cpenv.api
=========
This module provides the main api for cpenv. Members of the api return models which can be used to manipulate virtualenvs and modules. Members are available directly from the cpenv namespace.
'''
import os
import virtualenv
import shutil
from .cache import EnvironmentCache
from .resolver import Resolver
from .utils import unipath, touch
from .models import VirtualEnvironment
from .hooks import run_global_hook
from .deps import Git
from . import utils, defaults


def create(name_or_path=None, config=None):
    '''Create a virtual environment. You can pass either the name of a new
    environment to create in your CPENV_HOME directory OR specify a full path
    to create an environment outisde your CPENV_HOME.

    Create an environment in CPENV_HOME::

        >>> cpenv.create('myenv')

    Create an environment elsewhere::

        >>> cpenv.create('~/custom_location/myenv')

    :param name_or_path: Name or full path of environment
    :param config: Environment configuration including dependencies etc...
    '''

    # Get the real path of the environment
    if utils.is_system_path(name_or_path):
        path = unipath(name_or_path)
    else:
        path = unipath(get_home_path(), name_or_path)

    if os.path.exists(path):
        raise OSError('{} already exists'.format(path))

    os.makedirs(path)

    config_path = unipath(path, 'environment.yml')
    if config:
        if utils.is_git_repo(config):
            Git('').clone(config, path)
        else:
            shutil.copy2(config, config_path)
            os.mkdir(unipath(path, 'hooks'))
    else:
        with open(config_path, 'w') as f:
            f.write(defaults.environment_config)

    os.mkdir(unipath(path, 'modules'))
    env = VirtualEnvironment(path)

    run_global_hook('precreate', env)

    virtualenv.create_environment(env.path)
    if not utils.is_home_environment(env.path):
        EnvironmentCache.add(env)

    try:
        env.update()
    except:
        utils.rmtree(path)
        raise

    run_global_hook('postcreate', env)

    return env


def resolve(*args):
    '''Resolve a list of virtual environment and module names then return
    a :class:`Resolver` instance.'''

    r = Resolver(*args)
    r.resolve()
    return r


def activate(*args):
    '''Activate a virtual environment by name or path. Additional args refer
    to modules residing in the specified environment that you would
    also like to activate.

    Activate an environment::

        >>> cpenv.activate('myenv')

    Activate an environment with some modules::

        >>> cpenv.activate('myenv', 'maya', 'mtoa', 'vray_for_maya')

    :param name_or_path: Name or full path of environment
    :param modules: Additional modules to activate
    '''

    r = resolve(*args)
    r.activate()
    return get_active_env()


def launch(module_name, *args, **kwargs):
    '''Activates and launches a module

    :param module_name: name of module to launch
    '''

    r = resolve(module_name)
    r.activate()
    mod = r.resolved[0]
    mod.launch(*args, **kwargs)


def deactivate():
    '''Deactivates an environment by restoring all env vars to a clean state
    stored prior to activating environments
    '''

    if 'CPENV_ACTIVE' not in os.environ:
        return
    if 'CPENV_CLEAN_ENV' not in os.environ:
        raise EnvironmentError('Can not deactivate environment...')

    utils.restore_env_from_file(os.environ['CPENV_CLEAN_ENV'])


def get_home_path():
    '''Returns your home path...CPENV_HOME env var OR ~/.cpenv'''

    home = unipath(os.environ.get('CPENV_HOME', '~/.cpenv'))
    if not os.path.exists(home):
        os.makedirs(home)
    return home


def get_active_env():
    '''Returns the active environment as a :class:`VirtualEnvironment` instance or
    None if one is not active.
    '''

    active = os.environ.get('CPENV_ACTIVE', None)
    if active:
        return VirtualEnvironment(active)


def get_environments():
    '''Returns a list of all known virtual environments as :class:`VirtualEnvironment`
    instances. This includes those in CPENV_HOME and any others that are
    cached(created by the current user or activated once by full path.)
    '''

    environments = []

    cwd = os.getcwd()
    for d in os.listdir(cwd):

        if d == 'environment.yml':
            environments.append(VirtualEnvironment(cwd))
            continue

        path = unipath(cwd, d)
        if utils.is_environment(path):
            environments.append(VirtualEnvironment(path))

    home = get_home_path()
    for d in os.listdir(home):

        path = unipath(home, d)
        if utils.is_environment(path):
            environments.append(VirtualEnvironment(path))

    for env in EnvironmentCache:
        environments.append(env)

    return environments


def get_environment(name_or_path):
    '''Get a :class:`VirtualEnvironment` by name or path.'''

    r = resolve(name_or_path)
    return r.resolved[0]

