from collections import defaultdict
import re

from corehq.apps.app_manager.util import get_app_manager_template
from dimagi.utils.decorators.memoized import memoized
from django.utils.translation import ugettext_noop, ugettext
from corehq.apps.app_manager import static_strings
import os
import yaml


PROFILE_SETTINGS_TO_TRANSLATE = [
    'name',
    'description',
    'value_names',
    'disabled_txt',
    'values_txt',
]

LAYOUT_SETTINGS_TO_TRANSLATE = [
    'title'
]


def _load_custom_commcare_settings(user=None):
    path = os.path.join(os.path.dirname(__file__), 'static', 'app_manager', 'json')
    settings = []
    with open(os.path.join(
            path,
            get_app_manager_template(
                user,
                'v1/commcare-profile-settings.yaml',
                'v2/commcare-profile-settings.yaml'
            )
    )) as f:
        for setting in yaml.load(f):
            if not setting.get('type'):
                setting['type'] = 'properties'
            settings.append(setting)

    with open(os.path.join(path, get_app_manager_template(
        user,
        'v1/commcare-app-settings.yaml',
        'v2/commcare-app-settings.yaml'
    ))) as f:
        for setting in yaml.load(f):
            if not setting.get('type'):
                setting['type'] = 'hq'
            settings.append(setting)
    for setting in settings:
        if not setting.get('widget'):
            setting['widget'] = 'select'

        for prop in PROFILE_SETTINGS_TO_TRANSLATE:
            if prop in setting:
                setting[prop] = ugettext(setting[prop])
    return settings


def _load_commcare_settings_layout(doc_type, user):
    settings = dict([
        ('{0}.{1}'.format(setting.get('type'), setting.get('id')), setting)
        for setting in _load_custom_commcare_settings(user)
    ])
    path = os.path.join(os.path.dirname(__file__), 'static', 'app_manager', 'json')
    with open(os.path.join(
            path,
            get_app_manager_template(
                user,
                'v1/commcare-settings-layout.yaml',
                'v2/commcare-settings-layout.yaml'
            ))) as f:
        layout = yaml.load(f)

    for section in layout:
        # i18n; not statically analyzable
        section['title'] = ugettext_noop(section['title'])
        for i, key in enumerate(section['settings']):
            setting = settings.pop(key)
            if doc_type == 'Application' or setting['type'] == 'hq':
                section['settings'][i] = setting
            else:
                section['settings'][i] = None
        section['settings'] = filter(None, section['settings'])
        for setting in section['settings']:
            setting['value'] = None
            for prop in LAYOUT_SETTINGS_TO_TRANSLATE:
                if prop in setting:
                    setting[prop] = ugettext(setting[prop])

    if settings:
        raise Exception(
            "CommCare settings layout should mention "
            "all the available settings. "
            "The following settings went unmentioned: %s" % (
                ', '.join(settings.keys())
            )
        )
    return layout


@memoized
def get_custom_commcare_settings():
    return _load_custom_commcare_settings()


@memoized
def get_commcare_settings_layout(user):
    layout = {
        doc_type: _load_commcare_settings_layout(doc_type, user)
        for doc_type in ('Application', 'RemoteApp', 'LinkedApplication')
    }
    layout.update({'LinkedApplication': {}})
    return layout


@memoized
def get_commcare_settings_lookup():
    settings_lookup = defaultdict(lambda: defaultdict(dict))
    for setting in get_custom_commcare_settings():
        settings_lookup[setting['type']][setting['id']] = setting
    return settings_lookup


def parse_condition_string(condition_str):
    pattern = re.compile("{(?P<type>[\w-]+?)\.(?P<id>[\w-]+?)}=(?P<equals>true|false|'[\w-]+')")
    match = pattern.match(condition_str).groupdict()
    if match["equals"] == 'true':
        match["equals"] = True
    elif match["equals"] == 'false':
        match["equals"] = False
    elif len(match["equals"]) > 1 and match["equals"][0] is "'" and match["equals"][-1] is "'":
            match["equals"] = match["equals"][1:-1]
    else:
        raise Exception("Error parsing contingent condition")
    return match


def check_condition(app, condition_str):
    cond = parse_condition_string(condition_str)
    attr_val = app.get_profile_setting(cond["type"], cond["id"])
    return attr_val == cond["equals"] or \
           (cond["equals"] == 'true' and attr_val is True) or (cond["equals"] == 'false' and attr_val is False)


def check_contingent_for_circular_dependency(contingent, yaml_lookup, deps=None):
    deps = deps or []
    cond = parse_condition_string(contingent["condition"])
    dep = "%s.%s" % (cond["type"], cond["id"])
    if dep in deps:
        return True
    deps.append(dep)
    cond_setting = yaml_lookup[cond["type"]][cond["id"]]
    return check_setting_for_circular_dependency(cond_setting, yaml_lookup, deps)


def check_setting_for_circular_dependency(setting, yaml_lookup, deps=None):
    deps = deps or []
    for contingent in setting.get("contingent_default", []):
        if check_contingent_for_circular_dependency(contingent, yaml_lookup, deps):
            return True
    return False


def circular_dependencies(settings, yaml_lookup):
    """
    Checks the settings yaml file for circular dependencies in the contingent_defaults.
    This is here that we can test that SETTINGS has no cycles in our test suite.
    """
    for s in settings:
        if check_setting_for_circular_dependency(s, yaml_lookup):
            return True
    return False

@@ -470,16 +470,262 @@
 le'%0A%5D%0A%0A%0A
+def _translate_setting(setting, prop):%0A    if prop not in setting:%0A        return setting%0A%0A    value = setting%5Bprop%5D%0A    if not isinstance(value, basestring):%0A        return %5Bugettext(v) for v in value%5D%0A    else:%0A        return ugettext(value)%0A%0A%0A
 def _loa
@@ -759,24 +759,24 @@
 user=None):%0A
-
     path = o
@@ -1810,32 +1810,42 @@
 prop%5D = 
-ugettext
+_translate_setting
 (setting
 %5Bprop%5D)%0A
@@ -1836,22 +1836,22 @@
 (setting
-%5B
+, 
 prop
-%5D
 )%0A    re
@@ -3107,24 +3107,34 @@
 %5D = 
-ugettext
+_translate_setting
 (setting
 %5Bpro
@@ -3129,22 +3129,22 @@
 (setting
-%5B
+, 
 prop
-%5D
 )%0A%0A    i

fix translating list