# Copyright (c) 2009 ActiveState Software Inc.
# See http://www.activestate.com/activepython/license/ for licensing
# information.

"""
    PyPM client base
    ~~~~~~~~~~~~~~~~
    
"""

import os
from os.path import join, exists, expanduser
import io
import sys
import urllib
import string
import gzip
from contextlib import contextmanager
from ConfigParser import SafeConfigParser

from applib.base import Application

import pypm
from pypm.common import console, python, net
from pypm.common.supported import PLATNAME
from pypm.common.util import url_join, pypm_file, dlocked
from pypm.common.repository import RemoteRepositoryManager, RemoteRepositorySet

from pypm.client import store

__all__ = ['make_pypm_environment']


application = Application(
    'PyPM', 'ActiveState', '.'.join(pypm.__version_info__[:2]))

PYPM_CLIENT_CONF_FILE = pypm_file('pypm', 'client', 'client.conf')
IDX_PATH = join(application.locations.user_cache_dir, 'idx')


class PyPMEnvironment(object):
    """A PyPM environment that is tied to

      - one `PythonEnvironment`
      - one or more `RemoteRepository`

    Packages can, thus, be searched and installed from any number of remote
    repositories (although usually it is the main respository) but can only be
    installed to the specified Python environment
    """

    def __init__(self, pyenv, repository_list, interactive=False):
        self.pyenv = pyenv
        self.repository_list = repository_list
        self.interactive = interactive # if raw_input() can be used
        
        self.pypm_dir = join(self.pyenv.site_packages_dir, '_pypm')
        self.repo_store = store.RepoPackageStore(
            RemoteRepositoryManager(IDX_PATH), repository_list)

        if not exists(self.pypm_dir):
            self.pyenv.ensure_write_access()
            console.mkdirs(self.pypm_dir)
        self.installed_store = store.InstalledPackageStore(
            join(self.pypm_dir, 'installed.db')
        )
        
    def clone(self, altattr={}):
        """Clone ``self`` with alternate attributes"""
        return PyPMEnvironment(
            pyenv = altattr.get('pyenv', self.pyenv),
            repository_list = altattr.get('repository_list', self.repository_list),
            interactive = altattr.get('interactive', self.interactive)
        )

    @contextmanager 
    def locked(self):
        """Lock the PyPM environment"""
        with dlocked(self.pypm_dir):
            yield

def get_default_repo_urls():
    """Return the repository URLs from client.conf

    This is typically a single activestate repository
    """
    cfgparser = SafeConfigParser()
    cfgparser.read(PYPM_CLIENT_CONF_FILE)
    repo_urls = [url.strip() for url in \
                     cfgparser.get('cmdln', 'repository_urls').split()]
    return repo_urls
    

def make_pypm_environment(pyenv, *repo_urls):
    return make_pypm_environment2(repo_urls, pyenv=pyenv)

def make_pypm_environment2(repo_urls, pyenv, **kwargs):
    """Make a PyPMEnvironment

    If repo_urls is None or empty, the one from the default config file is used.
    """
    repository_list = [
        RemoteRepositorySet(url.strip()).get_repository(
            pyenv.pyver, PLATNAME)
        for url in (repo_urls or get_default_repo_urls())
    ]
    return PyPMEnvironment(repository_list=repository_list,
                           pyenv=pyenv, **kwargs)
    

class ImagePythonEnvironment(python.PythonEnvironment):
    """A Python environment pointing to a *temporary* Python image"""

    def __init__(self, image_root, target_python_exe):
        """
        - image_root: path to Python image
        - target_python_exe: actual python executable path to use
        """
        self.target_python_exe = target_python_exe
        super(ImagePythonEnvironment, self).__init__(image_root)


class Adapter(object): pass
class PyPMFeature(Adapter):

    def __init__(self, pypmenv):
        assert type(pypmenv) is PyPMEnvironment
        self.pypmenv = pypmenv
