package org.onap.policy.pdp.xacml.application.common.std;
 
 import com.att.research.xacml.api.Advice;
+import com.att.research.xacml.api.Attribute;
+import com.att.research.xacml.api.AttributeCategory;
 import com.att.research.xacml.api.Decision;
 import com.att.research.xacml.api.Obligation;
 import com.att.research.xacml.api.Request;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
+import lombok.Getter;
+import lombok.Setter;
 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType;
 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ApplyType;
 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeDesignatorType;
     private static final Logger LOGGER = LoggerFactory.getLogger(StdBaseTranslator.class);
     private static final ObjectFactory factory = new ObjectFactory();
 
+    @Getter
+    @Setter
+    protected boolean booleanReturnAttributes = false;
+
+    @Getter
+    @Setter
+    protected boolean booleanReturnSingleValueAttributesAsCollection = false;
+
     public static final String POLICY_ID = "policy-id";
     public static final String POLICY_VERSION = "policy-version";
 
                 decisionResponse.setStatus("error");
                 decisionResponse.setMessage(xacmlResult.getStatus().getStatusMessage());
             }
+            //
+            // Add attributes
+            //
+            if (booleanReturnAttributes) {
+                scanAttributes(xacmlResult.getAttributes(), decisionResponse);
+            }
         }
 
         return decisionResponse;
      */
     protected abstract void scanAdvice(Collection<Advice> advice, DecisionResponse decisionResponse);
 
+    /**
+     * scanAttributes - scans the attributes that are returned in the XACML Decision and puts them into the
+     * DecisionResponse object.
+     *
+     * @param attributeCategories Collection of AttributeCategory objects
+     * @param decisionResponse DecisionResponse object used to store any attributes
+     */
+    protected void scanAttributes(Collection<AttributeCategory> attributeCategories,
+            DecisionResponse decisionResponse) {
+        var returnedAttributes = new HashMap<String, Object>();
+        for (AttributeCategory attributeCategory : attributeCategories) {
+            var mapCategory = new HashMap<String, Object>();
+            for (Attribute attribute : attributeCategory.getAttributes()) {
+                //
+                // Most attributes have a single value, thus the collection is not necessary to
+                // return. However, we will allow this to be configurable.
+                //
+                if (! booleanReturnSingleValueAttributesAsCollection && attribute.getValues().size() == 1) {
+                    var iterator = attribute.getValues().iterator();
+                    var value = iterator.next();
+                    mapCategory.put(attribute.getAttributeId().stringValue(), value.getValue().toString());
+                } else {
+                    mapCategory.put(attribute.getAttributeId().stringValue(), attribute.getValues());
+                }
+            }
+            returnedAttributes.put(attributeCategory.getCategory().stringValue(), mapCategory);
+        }
+        if (! returnedAttributes.isEmpty()) {
+            decisionResponse.setAttributes(returnedAttributes);
+        }
+    }
+
     /**
      * From the TOSCA metadata section, pull in values that are needed into the XACML policy.
      *
 
         // Dump it out as Json
         //
         LOGGER.info(gson.encode(response));
+        //
+        // Guard does not return these
+        //
+        assertThat(response.getAdvice()).isNull();
+        assertThat(response.getObligations()).isNull();
+        assertThat(response.getAttributes()).isNull();
     }
 
     /**
 
         assertThat(response).isNotNull();
         assertThat(response.getPolicies()).isEmpty();
         //
+        // Match applications should not have this information returned
+        //
+        assertThat(response.getAdvice()).isNull();
+        assertThat(response.getObligations()).isNull();
+        assertThat(response.getAttributes()).isNull();
+        //
         // Ask for foo
         //
         baseRequest.getResource().put("matchable", "foo");
         assertThat(response).isNotNull();
         assertThat(response.getPolicies()).hasSize(1);
         //
+        // Match applications should not have this information returned
+        //
+        assertThat(response.getAdvice()).isNull();
+        assertThat(response.getObligations()).isNull();
+        assertThat(response.getAttributes()).isNull();
+        //
         // Validate it
         //
         validateDecision(response, baseRequest, "value1");
 
 
         assertThat(decision.getKey()).isNotNull();
         assertThat(decision.getKey().getPolicies()).isEmpty();
+        //
+        // Monitoring applications should not have this information returned
+        //
+        assertThat(decision.getKey().getAdvice()).isNull();
+        assertThat(decision.getKey().getObligations()).isNull();
+        assertThat(decision.getKey().getAttributes()).isNull();
     }
 
     @SuppressWarnings("unchecked")
         //
         Pair<DecisionResponse, Response> decision = service.makeDecision(requestSinglePolicy, null);
         LOGGER.info("Decision {}", decision);
-
+        //
+        // Should have one policy returned
+        //
         assertThat(decision.getKey()).isNotNull();
         assertThat(decision.getKey().getPolicies()).hasSize(1);
         //
+        // Monitoring applications should not have this information returned
+        //
+        assertThat(decision.getKey().getAdvice()).isNull();
+        assertThat(decision.getKey().getObligations()).isNull();
+        assertThat(decision.getKey().getAttributes()).isNull();
+        //
         // Dump it out as Json
         //
         LOGGER.info(gson.encode(decision.getKey()));
         //
         decision = service.makeDecision(requestPolicyType, null);
         LOGGER.info("Decision {}", decision);
-
+        //
+        // Should have one policy returned
+        //
         assertThat(decision.getKey()).isNotNull();
         assertThat(decision.getKey().getPolicies()).hasSize(1);
+        //
+        // Monitoring applications should not have this information returned
+        //
+        assertThat(decision.getKey().getAdvice()).isNull();
+        assertThat(decision.getKey().getObligations()).isNull();
+        assertThat(decision.getKey().getAttributes()).isNull();
+        //
+        // Validate the full policy is returned
+        //
         Map<String, Object> jsonPolicy = (Map<String, Object>) decision.getKey().getPolicies().get("onap.scaleout.tca");
         assertThat(jsonPolicy).isNotNull();
         assertThat(jsonPolicy.get("properties")).isNotNull();
         requestQueryParams.put("abbrev", new String[] {"true"});
         decision = service.makeDecision(requestPolicyType, requestQueryParams);
         LOGGER.info("Decision {}", decision);
-
+        //
+        // Should have one policy returned
+        //
         assertThat(decision.getKey()).isNotNull();
         assertThat(decision.getKey().getPolicies()).hasSize(1);
+        //
+        // Monitoring applications should not have this information returned
+        //
+        assertThat(decision.getKey().getAdvice()).isNull();
+        assertThat(decision.getKey().getObligations()).isNull();
+        assertThat(decision.getKey().getAttributes()).isNull();
+        //
+        // Validate an abbreviated policy is returned
+        //
         jsonPolicy = (Map<String, Object>) decision.getKey().getPolicies().get("onap.scaleout.tca");
         assertThat(jsonPolicy).isNotNull().doesNotContainKey("properties");
         //
         requestQueryParams.put("abbrev", new String[] {"false"});
         decision = service.makeDecision(requestPolicyType, requestQueryParams);
         LOGGER.info("Decision {}", decision);
-
+        //
+        // Should have one policy returned
+        //
         assertThat(decision.getKey()).isNotNull();
         assertThat(decision.getKey().getPolicies()).hasSize(1);
+        //
+        // Monitoring applications should not have this information returned
+        //
+        assertThat(decision.getKey().getAdvice()).isNull();
+        assertThat(decision.getKey().getObligations()).isNull();
+        assertThat(decision.getKey().getAttributes()).isNull();
+        //
+        // And should have full policy returned
+        //
         jsonPolicy = (Map<String, Object>) decision.getKey().getPolicies().get("onap.scaleout.tca");
         assertThat(jsonPolicy).isNotNull();
         assertThat(jsonPolicy.get("properties")).isNotNull();
 
 
         assertThat(decision.getKey()).isNotNull();
         assertThat(decision.getKey().getPolicies()).isEmpty();
+        //
+        // Naming applications should not have this information returned
+        //
+        assertThat(decision.getKey().getAdvice()).isNull();
+        assertThat(decision.getKey().getObligations()).isNull();
+        assertThat(decision.getKey().getAttributes()).isNull();
     }
 
     @Test
         assertThat(response).isNotNull();
         assertThat(response.getPolicies()).hasSize(1);
         //
+        // Naming applications should not have this information returned
+        //
+        assertThat(response.getAdvice()).isNull();
+        assertThat(response.getObligations()).isNull();
+        assertThat(response.getAttributes()).isNull();
+        //
         // Validate it
         //
         validateDecision(response, baseRequest);
 
 
         assertThat(decision.getKey()).isNotNull();
         assertThat(decision.getKey().getPolicies()).isEmpty();
+        //
+        // Optimization applications should not have this information returned. Except advice
+        // for subscriber details, which does get checked in the tests following.
+        //
+        assertThat(decision.getKey().getAdvice()).isNull();
+        assertThat(decision.getKey().getObligations()).isNull();
+        assertThat(decision.getKey().getAttributes()).isNull();
     }
 
     /**
         assertThat(response).isNotNull();
         assertThat(response.getPolicies()).hasSize(expectedPolicyCount);
         //
+        // Optimization applications should not have this information returned
+        //
+        assertThat(response.getObligations()).isNull();
+        assertThat(response.getAttributes()).isNull();
+        //
         // Validate it
         //
         validateDecision(response, baseRequest);