import os
import shutil
from os import path
from ConfigParser import SafeConfigParser

import sqlalchemy as sa
from unstdlib import chdir
from unstdlib.standard.functools_ import memoized_method

from .global_ import g
from . import db


class ProctorConfig(object):
    def __init__(self, parser):
        self._parser = parser

    @classmethod
    def load(cls, files):
        parser = SafeConfigParser()
        parser.read(files)
        return cls(parser)

    def __iter__(self):
        for section in self._parser.sections():
            for name, value in self._parser.items(section):
               yield "%s.%s" %(section, name)

    def __getitem__(self, item):
        prefix, _, suffix = item.partition(".")
        if not suffix:
            raise KeyError(item)
        return self._parser.get(prefix, suffix)

    def __contains__(self, item):
        try:
            self[item]
            return True
        except KeyError:
            return False

    def get(self, item, default=None):
        try:
            return self.__getitem__(item)
        except KeyError:
            return None


class ProctorEnv(object):
    default_config_file = path.join(path.dirname(__file__), "proctor-default.cfg")

    def __init__(self, root, conf):
        if not root.endswith("/"):
            root += "/"
        self.root = root
        self.conf = conf
        self.db = db

    @classmethod
    def activate_from_dir(cls, root, create=False):
        root = os.path.expanduser(root)
        if not path.exists(root):
            if not create:
                raise ValueError("Environment root does not exist: %r" %(root, ))
            os.mkdir(root)

        # conf
        config_file = path.join(root, "proctor.cfg")
        if create and not os.path.exists(config_file):
            shutil.copy(cls.default_config_file, config_file)
        conf =  ProctorConfig.load([
            cls.default_config_file,
            config_file
        ])

        # engine
        with chdir(root):
            engine = sa.engine_from_config(conf, prefix="db.")
            if create:
                db.Base.metadata.create_all(engine)
        db.set_engine(engine)

        env = cls(
            root=root,
            conf=conf,
        )
        env.activate()
        return env

    def activate(self):
        g.env = self

    def repository_import(self, name, path):
        if not (path.startswith("http") or os.path.exists(path)):
            raise ValueError("Source path does not exist: %r" %(path, ))
        if db.session.query(db.Repository).filter_by(name=name).first():
            raise ValueError("Repository already exists: %r" %(name, ))
        repo = db.Repository.create(name=name, root=path)
        repo.refresh()

    @memoized_method
    def repository_get(self, name):
        return db.Repository.get(name)

    def repository_list(self):
        return db.session.query(db.Repository).order_by(db.Repository.name)
