#
# Module that parses constraints
#
# The current version of juju core expects the client to take
# constraints given in the form "mem=10G foo=bar" and parse them into
# json that looks like {"mem": 10240, "foo": "bar"}. This module helps us
# accomplish that task.
#
# We do not attempt to duplicate the checking done in
# client/_client.py:Value here. That class will verify that the
# constraints keys are valid, and that we can successfully dump the
# constraints dict to json.
#
# Once https://bugs.launchpad.net/juju/+bug/1645402 is addressed, this
# module should be deprecated.
#

import re

# Matches on a string specifying memory size
MEM = re.compile('^[1-9][0-9]*[MGTP]$')

# Multiplication factors to get Megabytes
# https://github.com/juju/juju/blob/master/constraints/constraints.go#L666
FACTORS = {
    "M": 1,
    "G": 1024,
    "T": 1024 * 1024,
    "P": 1024 * 1024 * 1024
}

LIST_KEYS = {'tags', 'spaces'}

SNAKE1 = re.compile(r'(.)([A-Z][a-z]+)')
SNAKE2 = re.compile('([a-z0-9])([A-Z])')


def parse(constraints):
    """
    Constraints must be expressed as a string containing only spaces
    and key value pairs joined by an '='.

    """
    if not constraints:
        return None

    if type(constraints) is dict:
        # Fowards compatibilty: already parsed
        return constraints

    constraints = {
        normalize_key(k): (
            normalize_list_value(v) if k in LIST_KEYS else
            normalize_value(v)
        ) for k, v in [s.split("=") for s in constraints.split(" ")]}

    return constraints


def normalize_key(key):
    key = key.strip()

    key = key.replace("-", "_")  # Our _client lib wants "_" in place of "-"

    # Convert camelCase to snake_case
    key = SNAKE1.sub(r'\1_\2', key)
    key = SNAKE2.sub(r'\1_\2', key).lower()

    return key


def normalize_value(value):
    value = value.strip()

    if MEM.match(value):
        # Translate aliases to Megabytes. e.g. 1G = 10240
        return int(value[:-1]) * FACTORS[value[-1:]]

    if value.isdigit():
        return int(value)

    return value


def normalize_list_value(value):
    values = value.strip().split(',')
    return [normalize_value(value) for value in values]
