package com.sun.identity.saml2.protocol.impl;

import com.sun.identity.saml2.common.SAML2Exception;
import com.sun.identity.saml2.common.SAML2SDKUtils;
import com.sun.identity.saml2.protocol.RequestedAuthnContext;
import com.sun.identity.shared.xml.XMLUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class RequestedAuthnContextImpl implements RequestedAuthnContext {
   private static final String ELEMENT_NAME = "RequestedAuthnContext";
   private boolean mutable;
   private List<String> authnContextClassRef;
   private List<String> authnContextDeclRef;
   private String comparison;

   public RequestedAuthnContextImpl() {
      this.mutable = true;
   }

   public RequestedAuthnContextImpl(Element element) throws SAML2Exception {
      this.parseElement(element);
      this.makeImmutable();
   }

   private void parseElement(Element element) throws SAML2Exception {
      String eltName = element.getLocalName();
      if (eltName == null) {
         if (SAML2SDKUtils.DEBUG.messageEnabled()) {
            SAML2SDKUtils.DEBUG.message("parseElement(Element): local name missing");
         }

         throw new SAML2Exception("");
      } else {
         this.comparison = element.getAttribute("Comparison");
         if (!eltName.equals("RequestedAuthnContext")) {
            if (SAML2SDKUtils.DEBUG.messageEnabled()) {
               SAML2SDKUtils.DEBUG.message("RequestedAuthnContextImpl: invalid element");
            }

            throw new SAML2Exception(SAML2SDKUtils.BUNDLE.getString("wrongInput"));
         } else {
            NodeList nl = element.getChildNodes();
            int length = nl.getLength();

            for (int i = 0; i < length; i++) {
               Node child = nl.item(i);
               String childName = child.getLocalName();
               if (childName != null) {
                  if (childName.equals("AuthnContextClassRef")) {
                     if (this.authnContextDeclRef != null) {
                        SAML2SDKUtils.DEBUG.error("AuthnContext(Element): Should contain either <AuthnContextClassRef> or <AuthnContextDeclRef>");
                        throw new SAML2Exception(SAML2SDKUtils.BUNDLE.getString("wrongInput"));
                     }

                     this.getAuthnContextClassRef().add(XMLUtils.getElementValue((Element)child));
                  } else if (childName.equals("AuthnContextDeclRef")) {
                     if (this.authnContextClassRef != null) {
                        SAML2SDKUtils.DEBUG.error("AuthnContext(Element): Should contain either <AuthnContextClassRef> or <AuthnContextDeclRef>");
                        throw new SAML2Exception(SAML2SDKUtils.BUNDLE.getString("wrongInput"));
                     }

                     this.getAuthnContextDeclRef().add(XMLUtils.getElementValue((Element)child));
                  }
               }
            }
         }
      }
   }

   @Override
   public List<String> getAuthnContextClassRef() {
      if (this.authnContextClassRef == null) {
         this.authnContextClassRef = new ArrayList<>();
      }

      return this.authnContextClassRef;
   }

   @Override
   public void setAuthnContextClassRef(List<String> value) throws SAML2Exception {
      if (!this.mutable) {
         throw new SAML2Exception(SAML2SDKUtils.BUNDLE.getString("objectImmutable"));
      }

      if (this.authnContextDeclRef != null && !this.authnContextDeclRef.isEmpty()) {
         SAML2SDKUtils.DEBUG.error("setAuthnContextClassRef: Should contain either <AuthnContextClassRef> or <AuthnContextDeclRef>");
         throw new SAML2Exception(SAML2SDKUtils.BUNDLE.getString("wrongInput"));
      }

      this.authnContextClassRef = value;
   }

   @Override
   public List<String> getAuthnContextDeclRef() {
      if (this.authnContextDeclRef == null) {
         this.authnContextDeclRef = new ArrayList<>();
      }

      return this.authnContextDeclRef;
   }

   @Override
   public void setAuthnContextDeclRef(List<String> value) throws SAML2Exception {
      if (!this.mutable) {
         throw new SAML2Exception(SAML2SDKUtils.BUNDLE.getString("objectImmutable"));
      }

      if (this.authnContextClassRef != null && !this.authnContextClassRef.isEmpty()) {
         SAML2SDKUtils.DEBUG.error("setAuthnContextDeclRef: Should contain either <AuthnContextClassRef> or <AuthnContextDeclRef>");
         throw new SAML2Exception(SAML2SDKUtils.BUNDLE.getString("wrongInput"));
      }

      this.authnContextDeclRef = value;
   }

   @Override
   public String getComparison() {
      return this.comparison;
   }

   @Override
   public void setComparison(String value) throws SAML2Exception {
      if (!this.mutable) {
         throw new SAML2Exception(SAML2SDKUtils.BUNDLE.getString("objectImmutable"));
      }

      this.comparison = value;
   }

   @Override
   public String toXMLString() throws SAML2Exception {
      return this.toXMLString(true, false);
   }

   @Override
   public String toXMLString(boolean includeNSPrefix, boolean declareNS) throws SAML2Exception {
      StringBuilder xml = new StringBuilder();
      String ns = "";
      String nsp = "";
      String assertNS = "";
      String assertNSP = "";
      if (declareNS) {
         ns = " xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\"";
         assertNS = " xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\"";
      }

      if (includeNSPrefix) {
         nsp = "samlp:";
         assertNSP = "saml:";
      }

      xml.append("<").append(nsp).append("RequestedAuthnContext");
      xml.append(ns).append(" ");
      if (this.comparison == null) {
         this.comparison = "exact";
      }

      xml.append("Comparison=\"");
      xml.append(this.comparison);
      xml.append("\">");
      if (this.authnContextClassRef != null && this.authnContextDeclRef != null) {
         throw new SAML2Exception("");
      }

      if (this.authnContextClassRef != null && this.authnContextClassRef != Collections.EMPTY_LIST) {
         for (String element : this.authnContextClassRef) {
            xml.append("<").append(assertNSP);
            xml.append("AuthnContextClassRef").append(assertNS).append(">");
            xml.append(element);
            xml.append("</").append(assertNSP);
            xml.append("AuthnContextClassRef").append(">");
         }
      }

      if (this.authnContextDeclRef != null && this.authnContextDeclRef != Collections.EMPTY_LIST) {
         for (String element : this.authnContextDeclRef) {
            xml.append("<").append(assertNSP);
            xml.append("AuthnContextDeclRef").append(assertNS).append(">");
            xml.append(element);
            xml.append("</").append(assertNSP);
            xml.append("AuthnContextDeclRef").append(">");
         }
      }

      xml.append("</").append(nsp).append("RequestedAuthnContext").append(">");
      return xml.toString();
   }

   @Override
   public void makeImmutable() {
      this.mutable = false;
      if (this.authnContextClassRef != null) {
         this.authnContextClassRef = Collections.unmodifiableList(this.authnContextClassRef);
      }

      if (this.authnContextDeclRef != null) {
         this.authnContextDeclRef = Collections.unmodifiableList(this.authnContextDeclRef);
      }
   }

   @Override
   public boolean isMutable() {
      return this.mutable;
   }
}
