# Copyright 2015 Docker, Inc.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

# Taken from Docker Compose:
# https://github.com/docker/compose/blob/master/compose/config/interpolation.py

import string


class InvalidInterpolation(Exception):
    def __init__(self, string):
        self.string = string


class Interpolator(object):
    """
    Configuration options may contain environment variables.  For example,
    suppose the shell contains `ETCD_VERSION=1.0` and the following
    gilt.yml is supplied.
    .. code-block:: yaml
        - git: https://github.com/retr0h/ansible-etcd.git
          version: ${ETCD_VERSION}
          dst: roles/retr0h.ansible-etcd-${ETCD_VERSION}/
       will substitute `${ETCD_VERSION}` with the value of the
    `ETCD_VERSION` environment variable.
    .. warning::
        If an environment variable is not set, gilt substitutes with an
        empty string.
    Both `$VARIABLE` and `${VARIABLE}` syntax are supported. Extended
    shell-style features, such as `${VARIABLE-default}` and
    `${VARIABLE:-default}` are also supported.
    If a literal dollar sign is needed in a configuration, use a double dollar
    sign (`$$`).
    """

    def __init__(self, templater, mapping):
        self.templater = templater
        self.mapping = mapping

    def interpolate(self, string):
        try:
            return self.templater(string).substitute(self.mapping)
        except ValueError:
            raise InvalidInterpolation(string)


class TemplateWithDefaults(string.Template):
    idpattern = r'[_a-z][_a-z0-9]*(?::?-[^}]+)?'

    # Modified from python2.7/string.py
    def substitute(self, mapping):
        # Helper function for .sub()
        def convert(mo):
            # Check the most common path first.
            named = mo.group('named') or mo.group('braced')
            if named is not None:
                if ':-' in named:
                    var, _, default = named.partition(':-')
                    return mapping.get(var) or default
                if '-' in named:
                    var, _, default = named.partition('-')
                    return mapping.get(var, default)
                val = mapping.get(named, '')
                return '%s' % (val, )
            if mo.group('escaped') is not None:
                return self.delimiter
            if mo.group('invalid') is not None:
                self._invalid(mo)

        return self.pattern.sub(convert, self.template)
