#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
    ebuild.py
    ~~~~~~~~~~~~~

    ebuild generation

    :copyright: (c) 2013-2015 by Jauhien Piatlicki
    :license: GPL-2, see LICENSE for more details.
"""

from .compatibility import basestring
from .exceptions import DependencyError

class EbuildGenerator(object):
    """
    Ebuild generator.
    """
    def __init__(self, package_db):
        """
        Args:
            package_db: Package database.
        """
        self.package_db = package_db

    def generate(self, package, ebuild_data=None):
        """
        Generate an ebuild for a package.

        Args:
            package: g_collections.Package instance.
            ebuild_data: Dictionary with ebuild data.

        Returns:
            Ebuild source as a list of strings.
        """
        #a possible exception should be catched in the caller
        if not ebuild_data:
            ebuild_data = self.package_db.get_package_description(package)
        ebuild_data = self.process_ebuild_data(ebuild_data)
        ebuild = self.get_template(package, ebuild_data)
        ebuild = self.process(ebuild, ebuild_data)
        ebuild = self.postprocess(ebuild, ebuild_data)
        return ebuild

    def process_ebuild_data(self, ebuild_data):
        """
        A hook allowing changing ebuild_data before ebuild generation.

        Args:
            ebuild_data: Dictinary with ebuild data.

        Returns:
            Dictinary with ebuild data.
        """
        return ebuild_data

    def process(self, ebuild, ebuild_data):
        """
        Fill ebuild template with data.

        Args:
            ebuild: Ebuild template.
            ebuild_data: Dictionary with ebuild data.

        Returns:
            Ebuild source as a list of strings.
        """
        result = []
        for line in ebuild:
            error = ""
            try:
                line = line % ebuild_data
            except ValueError as e:
                error = str(e)
            if error:
                error = "substitution failed in line '" + line + "': " + error
                raise DependencyError(error)
            result.append(line)

        return result

    def get_template(self, package, ebuild_data):
        """
        Generate ebuild template. Should be overriden.

        Args:
            package: g_collections.Package instance.
            ebuild_data: Dictionary with ebuild data.

        Returns:
            Ebuild template.
        """
        ebuild = []
        return ebuild

    def postprocess(self, ebuild, ebuild_data):
        """
        A hook for changing of a generated ebuild.

        Args:
            ebuild: Ebuild source as a list of strings.
            ebuild_data: Dictionary with ebuild data.

        Returns:
            Ebuild source as a list of strings.
        """
        return ebuild

class EbuildGeneratorFromFile(EbuildGenerator):
    """
    Ebuild generators that takes templates from files.
    """
    def __init__(self, package_db, filename=""):
        super(EbuildGeneratorFromFile, self).__init__(package_db)
        self.filename = filename

    def get_template(self, package, ebuild_data):
        """
        Generate ebuild template.

        Args:
            package: g_collections.Package instance.
            ebuild_data: Dictionary with ebuild data.

        Returns:
            Ebuild template.
        """
        name = self.get_template_file(package, ebuild_data)
        with open(name, 'r') as f:
            ebuild = f.read().split('\n')
            if ebuild[-1] == '':
                ebuild = ebuild[:-1]
        return ebuild

    def get_template_file(self, package, ebuild_data):
        """
        Get template filename for a package. Should be overriden.

        Args:
            package: g_collections.Package instance.
            ebuild_data: Dictionary with ebuild data.

        Returns:
            Template filename.
        """
        return self.filename


class DefaultEbuildGenerator(EbuildGenerator):
    """
    Default ebuild generator.

    Takes a layout dictinary that describes ebuild structure and generates
    an ebuild template basing on it.

    Layout has entries for vars and inherited eclasses. Each entry is a list.
    Entries are processed in the following order:

    vars_before_inherit
    inherit
    vars_after_inherit
    vars_after_description
    vars_after_keywords

    inherit entry is just a list of eclass names.
    vars* entries are lists of variables in tw0 possible formats:
    1. A string with variable name
    2. A dictinary with entries:
        name: variable name
        value: variable value
        raw: if present, no quotation of value will be done
    Variable names are automatically transformed to the upper-case.
    """
    def __init__(self, package_db, layout):
        super(DefaultEbuildGenerator, self).__init__(package_db)
        self.template = ["# automatically generated by g-sorcery",
                         "# please do not edit this file",
                         ""]

        if hasattr(layout, "eapi"):
            self.template.append("EAPI=%s" % layout.eapi)
        else:
            self.template.append("EAPI=8")
        self.template.append("")

        if hasattr(layout, "vars_before_inherit"):
            self._append_vars_to_template(layout.vars_before_inherit)
            self.template.append("")

        if hasattr(layout, "inherit"):
            self.template.append("inherit " + " ".join(layout.inherit))
            self.template.append("")

        if hasattr(layout, "vars_after_inherit"):
            self._append_vars_to_template(layout.vars_after_inherit)
            self.template.append("")

        self.template.append('DESCRIPTION="%(description)s"')
        self.template.append("")

        if hasattr(layout, "vars_after_description"):
            self._append_vars_to_template(layout.vars_after_description)
            self.template.append("")

        self.template.append('SLOT="0"')
        self.template.append('KEYWORDS="~amd64 ~x86"')
        self.template.append("")

        if hasattr(layout, "vars_after_keywords"):
            self._append_vars_to_template(layout.vars_after_keywords)
            self.template.append("")


    def _append_vars_to_template(self, variables):
        """
        Add a list of variables to the end of template.

        Args:
            variables: List of variables.
        """
        for var in variables:
            if isinstance(var, basestring):
                self.template.append(var.upper() + '="%(' + var + ')s"')
            else:
                if "raw" in var:
                    quote = ''
                else:
                    quote = '"'
                if "value" in var:
                    self.template.append(var["name"].upper() \
                                         + '=' + quote + var["value"] + quote)
                else:
                    self.template.append(var["name"].upper() + '=' + quote + '%(' + var["name"] + ')s' + quote)


    def get_template(self, package, ebuild_data):
        """
        Generate ebuild template.

        Args:
            package: g_collections.Package instance.
            ebuild_data: Dictionary with ebuild data.

        Returns:
            Ebuild template.
        """
        return self.template
