import re
 import six
 import time
+import types
 
 from keystone.common import manager
 from keystone import config
 CONF.register_opts(_OPTS, group='moon')
 
 
-def filter_args(func):
+def filter_input(func_or_str):
+
+    def __filter(string):
+        return "".join(re.findall("[\w\-+]*", string))
+
     def wrapped(*args, **kwargs):
         _args = []
         for arg in args:
-            if type(arg) in (unicode, str):
-                arg = "".join(re.findall("[\w\-+]*", arg))
+            if isinstance(arg, str) or isinstance(arg, unicode):
+                arg = __filter(arg)
+            elif isinstance(arg, list):
+                arg =  [__filter(item) for item in arg]
+            elif isinstance(arg, tuple):
+                arg =  (__filter(item) for item in arg)
+            elif isinstance(arg, dict):
+                arg =  {item: __filter(arg[item]) for item in arg.keys()}
             _args.append(arg)
         for arg in kwargs:
             if type(kwargs[arg]) in (unicode, str):
-                kwargs[arg] = "".join(re.findall("[\w\-+]*", kwargs[arg]))
-        return func(*_args, **kwargs)
-    return wrapped
+                kwargs[arg] = __filter(kwargs[arg])
+            if isinstance(kwargs[arg], str) or isinstance(kwargs[arg], unicode):
+                kwargs[arg] = __filter(kwargs[arg])
+            elif isinstance(kwargs[arg], list):
+                kwargs[arg] =  [__filter(item) for item in kwargs[arg]]
+            elif isinstance(kwargs[arg], tuple):
+                kwargs[arg] =  (__filter(item) for item in kwargs[arg])
+            elif isinstance(kwargs[arg], dict):
+                kwargs[arg] =  {item: __filter(kwargs[arg][item]) for item in kwargs[arg].keys()}
+        return func_or_str(*_args, **kwargs)
+
+    if isinstance(func_or_str, str) or isinstance(func_or_str, unicode):
+        return __filter(func_or_str)
+    if isinstance(func_or_str, list):
+        return [__filter(item) for item in func_or_str]
+    if isinstance(func_or_str, tuple):
+        return (__filter(item) for item in func_or_str)
+    if isinstance(func_or_str, dict):
+        return {item: __filter(func_or_str[item]) for item in func_or_str.keys()}
+    if isinstance(func_or_str, types.FunctionType):
+        return wrapped
+    return None
 
 
 def enforce(action_names, object_name, **extra):
     return wrap
 
 
-# TODO (dthom) join with filer_args
-def filter_input(data):
-    if type(data) not in (str, unicode):
-        return data
-    try:
-        return "".join(re.findall("[\w\-+*]", data))
-    except TypeError:
-        LOG.error("Error in filtering input data: {}".format(data))
-
-
 @dependency.provider('configuration_api')
 @dependency.requires('moonlog_api')
 class ConfigurationManager(manager.Manager):
 
     # Metadata functions
 
-    @filter_args  # TODO: check for each function if intra_entension_id exists
+    @filter_input  # TODO: check for each function if intra_entension_id exists
     @enforce("read", "subject_categories")
     def get_subject_categories_dict(self, user_id, intra_extension_id):
         """
         """
         return self.driver.get_subject_categories_dict(intra_extension_id)
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "subject_categories")
     def add_subject_category(self, user_id, intra_extension_id, subject_category_dict):
         subject_category_dict = self.driver.get_subject_categories_dict(intra_extension_id)
                 raise SubjectCategoryNameExisting()
         return self.driver.set_subject_category(intra_extension_id, uuid4().hex, subject_category_dict)
 
-    @filter_args
+    @filter_input
     @enforce("read", "subject_categories")
     def get_subject_category(self, user_id, intra_extension_id, subject_category_id):
         subject_category_dict = self.driver.get_subject_categories_dict(intra_extension_id)
             raise SubjectCategoryUnknown()
         return subject_category_dict[subject_category_id]
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "subject_categories")
     @enforce(("read", "write"), "subject_scopes")
     @enforce(("read", "write"), "subject_assignments")
                 self.driver.del_subject_assignment(intra_extension_id, subject_id, subject_category_id, assignment_id)
         self.driver.del_subject_category(intra_extension_id, subject_category_id)
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "subject_categories")
     def set_subject_category(self, user_id, intra_extension_id, subject_category_id, subject_category_dict):
         if subject_category_id not in self.driver.get_subject_categories_dict(intra_extension_id):
             raise SubjectCategoryUnknown()
         return self.driver.set_subject_category(intra_extension_id, subject_category_id, subject_category_dict)
 
-    @filter_args
+    @filter_input
     @enforce("read", "object_categories")
     def get_object_category_dict(self, user_id, intra_extension_id):
         """
         """
         return self.driver.get_object_categories_dict(intra_extension_id)
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "object_categories")
     @enforce(("read", "write"), "object_scopes")
     def add_object_category(self, user_id, intra_extension_id, object_category_name):
                 raise ObjectCategoryNameExisting()
         return self.driver.add_object_category(intra_extension_id, uuid4().hex, object_category_name)
 
-    @filter_args
+    @filter_input
     @enforce("read", "object_categories")
     def get_object_category(self, user_id, intra_extension_id, object_category_id):
         object_category_dict = self.driver.get_object_categories_dict(intra_extension_id)
             raise ObjectCategoryUnknown()
         return object_category_dict[object_category_id]
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "object_categories")
     @enforce(("read", "write"), "object_scopes")
     @enforce(("read", "write"), "object_assignments")
                 self.driver.del_object_assignment(intra_extension_id, object_id, object_category_id, assignment_id)
         self.driver.del_object_category(intra_extension_id, object_category_id)
 
-    @filter_args
+    @filter_input
     @enforce("read", "action_categories")
     def get_action_category_dict(self, user_id, intra_extension_id):
         """
         """
         return self.driver.get_action_categories_dict(intra_extension_id)
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "action_categories")
     @enforce(("read", "write"), "action_scopes")
     def add_action_category(self, user_id, intra_extension_id, action_category_name):
                 raise ActionCategoryNameExisting()
         return self.driver.add_action_category(intra_extension_id, uuid4().hex, action_category_name)
 
-    @filter_args
+    @filter_input
     @enforce("read", "action_categories")
     def get_action_category(self, user_id, intra_extension_id, action_category_id):
         action_category_dict = self.driver.get_action_categories_dict(intra_extension_id)
             raise ActionCategoryUnknown()
         return self.driver.get_action_categories_dict(intra_extension_id)[action_category_id]
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "action_categories")
     @enforce(("read", "write"), "action_category_scopes")
     def del_action_category(self, user_id, intra_extension_id, action_category_id):
 
     # Perimeter functions
 
-    @filter_args
+    @filter_input
     @enforce("read", "subjects")
     def get_subjects_dict(self, user_id, intra_extension_id):
         return self.driver.get_subjects_dict(intra_extension_id)
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "subjects")
     def add_subject_dict(self, user_id, intra_extension_id, subject_dict):
         subjects_dict = self.driver.get_subjects_dict(intra_extension_id)
         subject_item_dict = self.identity_api.get_user_by_name(subject_dict['name'], "default")
         return self.driver.set_subject_dict(intra_extension_id, subject_item_dict["id"], subject_dict)
 
-    @filter_args
+    @filter_input
     @enforce("read", "subjects")
     def get_subject_dict(self, user_id, intra_extension_id, subject_id):
         subject_dict = self.driver.get_subjects_dict(intra_extension_id)
             raise SubjectUnknown()
         return subject_dict[subject_id]
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "subjects")
     def del_subject(self, user_id, intra_extension_id, subject_id):
         if subject_id in self.driver.get_subjects_dict(intra_extension_id):
                     self.driver.del_subject_assignment(intra_extension_id, _subject_id, subject_category_id, assignment_id)
         self.driver.del_subject(intra_extension_id, subject_id)
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "subjects")
     def set_subject_dict(self, user_id, intra_extension_id, subject_id, subject_dict):
         subjects_dict = self.driver.get_subjects_dict(intra_extension_id)
         subject_item_dict = self.identity_api.get_user_by_name(subject_dict['name'], "default")
         return self.driver.set_subject_dict(intra_extension_id, subject_item_dict["id"], subject_dict)
 
-    @filter_args
+    @filter_input
     @enforce("read", "objects")
     def get_objects_dict(self, user_id, intra_extension_id):
         return self.driver.get_objects_dict(intra_extension_id)
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "objects")
     def add_object_dict(self, user_id, intra_extension_id, object_name):
         object_dict = self.driver.get_objects_dict(intra_extension_id)
                 raise ObjectNameExisting()
         return self.driver.set_object_dict(intra_extension_id, uuid4().hex, object_name)
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "objects")
     def set_object_dict(self, user_id, intra_extension_id, object_id, object_dict):
         objects_dict = self.driver.get_objects_dict(intra_extension_id)
                 raise ObjectNameExisting()
         return self.driver.set_object_dict(intra_extension_id, object_id, object_dict)
 
-    @filter_args
+    @filter_input
     @enforce("read", "objects")
     def get_object_dict(self, user_id, intra_extension_id, object_id):
         object_dict = self.driver.get_objects_dict(intra_extension_id)
             raise ObjectUnknown()
         return object_dict[object_id]
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "objects")
     def del_object(self, user_id, intra_extension_id, object_id):
         if object_id in self.driver.get_objects_dict(intra_extension_id):
                     self.driver.del_object_assignment(intra_extension_id, _object_id, object_category_id, assignment_id)
         self.driver.del_object(intra_extension_id, object_id)
 
-    @filter_args
+    @filter_input
     @enforce("read", "actions")
     def get_actions_dict(self, user_id, intra_extension_id):
         return self.driver.get_actions_dict(intra_extension_id)
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "actions")
     def add_action_dict(self, user_id, intra_extension_id, action_name):
         action_dict = self.driver.get_actions_dict(intra_extension_id)
                 raise ActionNameExisting()
         return self.driver.add_action_dict(intra_extension_id, uuid4().hex, action_name)
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "actions")
     def set_action_dict(self, user_id, intra_extension_id, action_id, action_dict):
         actions_dict = self.driver.get_actions_dict(intra_extension_id)
                 raise ActionNameExisting()
         return self.driver.set_action_dict(intra_extension_id, action_id, action_dict)
 
-    @filter_args
+    @filter_input
     @enforce("read", "actions")
     def get_action_dict(self, user_id, intra_extension_id, action_id):
         action_dict = self.driver.get_actions_dict(intra_extension_id)
             raise ActionUnknown()
         return action_dict[action_id]
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "actions")
     def del_action(self, user_id, intra_extension_id, action_id):
         if action_id in self.driver.get_actions_dict(intra_extension_id):
 
     # Scope functions
 
-    @filter_args
+    @filter_input
     @enforce("read", "subject_scopes")
     @enforce("read", "subject_categories")
     def get_subject_scopes_dict(self, user_id, intra_extension_id, subject_category_id):
             raise SubjectCategoryUnknown()
         return self.driver.get_subject_scopes_dict(intra_extension_id, subject_category_id)
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "subject_scopes")
     @enforce("read", "subject_categories")
     def add_subject_scope_dict(self, user_id, intra_extension_id, subject_category_id, subject_scope_dict):
         subject_scope_id = uuid4().hex
         return self.driver.add_subject_scope_dict(intra_extension_id, subject_category_id, subject_scope_id, subject_scope_dict)
 
-    @filter_args
+    @filter_input
     @enforce("read", "subject_scopes")
     @enforce("read", "subject_categories")
     def get_subject_scope_dict(self, user_id, intra_extension_id, subject_category_id, subject_scope_id):
             raise SubjectScopeUnknown()
         return subject_scopes_dict[subject_scope_id]
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "subject_scopes")
     @enforce("read", "subject_categories")
     def del_subject_scope(self, user_id, intra_extension_id, subject_category_id, subject_scope_id):
                     self.driver.del_rule(intra_extension_id, sub_meta_rule_id, rule_id)
         return self.driver.del_subject_scope(intra_extension_id, subject_category_id, subject_scope_id)
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "subject_scopes")
     @enforce("read", "subject_categories")
     def set_subject_scope_dict(self, user_id, intra_extension_id, subject_category_id, subject_scope_id, subject_scope_name):
                 raise SubjectScopeNameExisting()
         return self.driver.set_subject_scope_dict(intra_extension_id, subject_category_id, uuid4().hex, subject_scope_dict)
 
-    @filter_args
+    @filter_input
     @enforce("read", "object_category_scopes")
     @enforce("read", "object_categories")
     def get_object_scopes_dict(self, user_id, intra_extension_id, object_category_id):
             raise ObjectCategoryUnknown()
         return self.driver.get_object_scopes_dict(intra_extension_id, object_category_id)
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "object_scopes")
     @enforce("read", "object_categories")
     def add_object_scope_dict(self, user_id, intra_extension_id, object_category_id, object_scope_name):
             object_scope_id,
             object_scope_name)
 
-    @filter_args
+    @filter_input
     @enforce("read", "object_scopes")
     @enforce("read", "object_categories")
     def get_object_scope_dict(self, user_id, intra_extension_id, object_category_id, object_scope_id):
             raise ObjectScopeUnknown()
         return object_scopte_dict[object_scope_id]
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "object_scopes")
     @enforce("read", "object_categories")
     def del_object_scope(self, user_id, intra_extension_id, object_category_id, object_scope_id):
                     self.driver.del_rule(intra_extension_id, sub_meta_rule_id, rule_id)
         return self.driver.del_object_scope(intra_extension_id, object_category_id, object_scope_id)
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "object_scopes")
     @enforce("read", "object_categories")
     def set_object_scope_dict(self, user_id, intra_extension_id, object_category_id, object_scope_id, object_scope_name):
                 raise ObjectScopeNameExisting()
         return self.driver.set_object_scope_dict(intra_extension_id, object_category_id, uuid4().hex, object_scope_dict)
 
-    @filter_args
+    @filter_input
     @enforce("read", "action_category_scopes")
     @enforce("read", "action_categories")
     def get_action_scopes_dict(self, user_id, intra_extension_id, action_category_id):
             raise ActionCategoryUnknown()
         return self.driver.get_action_scopes_dict(intra_extension_id, action_category_id)
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "action_scopes")
     @enforce("read", "action_categories")
     def add_action_scope_dict(self, user_id, intra_extension_id, action_category_id, action_scope_name):
             action_scope_id,
             action_scope_name)
 
-    @filter_args
+    @filter_input
     @enforce("read", "action_scopes")
     @enforce("read", "action_categories")
     def get_action_scope_dict(self, user_id, intra_extension_id, action_category_id, action_scope_id):
             raise ActionScopeUnknown()
         return action_scopte_dict[action_scope_id]
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "action_scopes")
     @enforce("read", "action_categories")
     def del_action_scope(self, user_id, intra_extension_id, action_category_id, action_scope_id):
 
     # Assignment functions
 
-    @filter_args
+    @filter_input
     @enforce("read", "subject_assignments")
     @enforce("read", "subjects")
     @enforce("read", "subject_categories")
             raise SubjectCategoryUnknown()
         return self.driver.get_subject_assignment_list(intra_extension_id, subject_id, subject_category_id)
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "subject_assignments")
     @enforce("read", "subjects")
     @enforce("read", "subject_categories")
             raise SubjectAssignmentExisting()
         return self.driver.add_subject_assignment_list(intra_extension_id, subject_id, subject_category_id, subject_scope_id)
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "subject_assignments")
     @enforce("read", "subjects")
     @enforce("read", "subject_categories")
             raise SubjectAssignmentUnknown()
         self.driver.del_subject_category_assignment(intra_extension_id, subject_id, subject_category_id, subject_scope_id)
 
-    @filter_args
+    @filter_input
     @enforce("read", "object_assignments")
     @enforce("read", "objects")
     @enforce("read", "object_categories")
             raise ObjectCategoryUnknown()
         return self.driver.get_object_assignment_list(intra_extension_id, object_id, object_category_id)
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "object_assignments")
     @enforce("read", "objects")
     @enforce("read", "object_categories")
             raise ObjectAssignmentExisting()
         return self.driver.add_object_assignment_list(intra_extension_id, object_id, object_category_id, object_scope_id)
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "object_assignments")
     @enforce("read", "objects")
     @enforce("read", "object_categories")
             raise ObjectAssignmentUnknown()
         return self.driver.del_object_assignment(intra_extension_id, object_id, object_category_id, object_scope_id)
 
-    @filter_args
+    @filter_input
     @enforce("read", "action_assignments")
     @enforce("read", "actions")
     @enforce("read", "action_categories")
             raise ActionCategoryUnknown()
         return self.driver.get_action_assignment_list(intra_extension_id, action_id, action_category_id)
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "action_assignments")
     @enforce("read", "actions")
     @enforce("read", "action_categories")
             raise ObjectAssignmentExisting()
         return self.driver.add_action_assignment_list(intra_extension_id, action_id, action_category_id, action_scope_id)
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "action_assignments")
     @enforce("read", "actions")
     @enforce("read", "action_categories")
 
     # Metarule functions
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "aggregation_algorithm")
     def set_aggregation_algorithm_dict(self, user_id, intra_extension_id, aggregation_algorithm_id, aggregation_algorithm_dict):
         if aggregation_algorithm_id:
             aggregation_algorithm_id = uuid4().hex
         return self.driver.set_aggregation_algorithm_dict(intra_extension_id, aggregation_algorithm_id, aggregation_algorithm_dict)
 
-    @filter_args
+    @filter_input
     @enforce("read", "aggregation_algorithm")
     def get_aggregation_algorithm_dict(self, user_id, intra_extension_id):
         """
             raise AggregationAlgorithmNotExisting()
         return self.driver.get_aggregation_algorithm_dict(intra_extension_id)
 
-    @filter_args
+    @filter_input
     @enforce("read", "sub_meta_rules")
     def get_sub_meta_rules_dict(self, user_id, intra_extension_id):
         """
         """
         return self.driver.get_sub_meta_rules_dict(intra_extension_id)
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "sub_meta_rules")
     @enforce("write", "rule")
     def add_sub_meta_rule_dict(self, user_id, intra_extension_id, sub_meta_rule_dict):
         # self.driver.add_rule(intra_extension_id, sub_meta_rule_id, [])
         return self.driver.set_sub_meta_rule_dict(intra_extension_id, sub_meta_rule_id, sub_meta_rule_dict)
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "sub_meta_rules")
     def get_sub_meta_rule_dict(self, user_id, intra_extension_id, sub_meta_rule_id):
         sub_meta_rule_dict = self.driver.get_sub_meta_rules_dict(intra_extension_id)
             raise SubMetaRuleUnknown()
         return sub_meta_rule_dict[sub_meta_rule_id]
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "sub_meta_rules")
     @enforce(("read", "write"), "rule")
     def del_sub_meta_rule(self, user_id, intra_extension_id, sub_meta_rule_id):
         # self.driver.del_rule(intra_extension_id, sub_meta_rule_id, "*")
         self.driver.del_sub_meta_rule(intra_extension_id, sub_meta_rule_id)
 
-    @filter_args
+    @filter_input
     @enforce(("read", "write"), "sub_meta_rules")
     @enforce("write", "rule")
     def set_sub_meta_rule_dict(self, user_id, intra_extension_id, sub_meta_rule_id, sub_meta_rule_dict):
         return self.driver.set_sub_meta_rule_dict(intra_extension_id, sub_meta_rule_id, sub_meta_rule_dict)
 
     # Rule functions
-    @filter_args
+    @filter_input
     @enforce("read", "rules")
     def get_rules_dict(self, user_id, intra_extension_id, sub_meta_rule_id):
         """
         """
         return self.driver.get_rules_dict(intra_extension_id, sub_meta_rule_id)
 
-    @filter_args
+    @filter_input
     @enforce("read", "sub_meta_rules")
     @enforce(("read", "write"), "rules")
     def add_rule_dict(self, user_id, intra_extension_id, sub_meta_rule_id, rule_list):
         rule_id = uuid4().hex
         return self.driver.set_rule_dict(intra_extension_id, sub_meta_rule_id, rule_id, rule_list)
 
-    @filter_args
+    @filter_input
     @enforce("read", "sub_meta_rules")
     @enforce("read", "rules")
     def get_rule_dict(self, user_id, intra_extension_id, sub_meta_rule_id, rule_id):
             raise RuleUnknown()
         return rules_dict[rule_id]
 
-    @filter_args
+    @filter_input
     @enforce("read", "sub_meta_rules")
     @enforce(("read", "write"), "rules")
     def del_rule(self, user_id, intra_extension_id, sub_meta_rule_id, rule_id):
             raise RuleUnknown()
         self.driver.del_rule(intra_extension_id, sub_meta_rule_id, rule_id)
 
-    @filter_args
+    @filter_input
     @enforce("read", "sub_meta_rules")
     @enforce(("read", "write"), "rules")
     def set_rule_dict(self, user_id, intra_extension_id, sub_meta_rule_id, rule_id, rule_list):