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

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

public class ProxyRestrictionImpl implements ProxyRestriction {
   private static final String PROXY_RESTRICTION_ELEMENT = "ProxyRestriction";
   private static final String COUNT_ATTR = "Count";
   private static final String AUDIENCE_ELEMENT = "Audience";
   private int count;
   private boolean isMutable = true;
   private List<String> audiences = new ArrayList<>();

   public ProxyRestrictionImpl() {
   }

   public ProxyRestrictionImpl(String xml) throws SAML2Exception {
      Document document = XMLUtils.toDOMDocument(xml, SAML2SDKUtils.DEBUG);
      if (document != null) {
         Element rootElement = document.getDocumentElement();
         this.processElement(rootElement);
         this.makeImmutable();
      } else {
         SAML2SDKUtils.DEBUG.error("ProxyRestrictionImpl.processElement(): invalid XML input");
         throw new SAML2Exception(SAML2SDKUtils.BUNDLE.getString("errorObtainingElement"));
      }
   }

   public ProxyRestrictionImpl(Element element) throws SAML2Exception {
      this.processElement(element);
      this.makeImmutable();
   }

   private void processElement(Element element) throws SAML2Exception {
      if (element == null) {
         SAML2SDKUtils.DEBUG.error("ProxyRestrictionImpl.processElement(): invalid root element");
         throw new SAML2Exception(SAML2SDKUtils.BUNDLE.getString("invalid_element"));
      }

      String elemName = element.getLocalName();
      if (elemName == null) {
         SAML2SDKUtils.DEBUG.error("ProxyRestrictionImpl.processElement(): local name missing");
         throw new SAML2Exception(SAML2SDKUtils.BUNDLE.getString("missing_local_name"));
      }

      if (!elemName.equals("ProxyRestriction")) {
         SAML2SDKUtils.DEBUG.error("ProxyRestrictionImpl.processElement(): invalid local name " + elemName);
         throw new SAML2Exception(SAML2SDKUtils.BUNDLE.getString("invalid_local_name"));
      }

      String attrValue = element.getAttribute("Count");
      if (attrValue != null && !attrValue.trim().isEmpty()) {
         try {
            this.setCount(Integer.parseInt(attrValue));
         } catch (NumberFormatException e) {
            SAML2SDKUtils.DEBUG.error("ProxyRestrictionImpl.processElement(): count is not an integer " + attrValue);
            throw new SAML2Exception(SAML2SDKUtils.BUNDLE.getString("invalid_count_number"));
         }
      }

      NodeList nodes = element.getChildNodes();
      int numOfNodes = nodes.getLength();
      if (numOfNodes >= 1) {
         for (int nextElem = 0; nextElem < numOfNodes; nextElem++) {
            Node child = nodes.item(nextElem);
            if (child.getNodeType() == 1) {
               String childName = child.getLocalName();
               if (childName != null) {
                  if (!childName.equals("Audience")) {
                     SAML2SDKUtils.DEBUG.error("AudienceRestrictionImpl.processElement(): unexpected subelement " + childName);
                     throw new SAML2Exception(SAML2SDKUtils.BUNDLE.getString("unexpected_subelement"));
                  }

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

   @Override
   public int getCount() {
      return this.count;
   }

   @Override
   public void setCount(int value) throws SAML2Exception {
      if (!this.isMutable) {
         throw new SAML2Exception(SAML2SDKUtils.BUNDLE.getString("objectImmutable"));
      }

      if (this.count < 0) {
         SAML2SDKUtils.DEBUG.error("AudienceRestrictionImpl.setCount(): count is negative");
         throw new SAML2Exception(SAML2SDKUtils.BUNDLE.getString("negative_count_number"));
      }

      this.count = value;
   }

   @Override
   public List<String> getAudience() {
      return this.audiences;
   }

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

      this.audiences = audiences;
   }

   @Override
   public String toXMLString(boolean includeNSPrefix, boolean declareNS) throws SAML2Exception {
      StringBuilder sb = new StringBuilder(2000);
      String ns = "";
      String appendNS = "";
      if (declareNS) {
         ns = " xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\"";
      }

      if (includeNSPrefix) {
         appendNS = "saml:";
      }

      sb.append("<").append(appendNS).append("ProxyRestriction").append(ns);
      if (this.count >= 0) {
         sb.append(" ").append("Count").append("=\"").append(this.count).append("\"");
      }

      sb.append(">\n");
      int length = 0;
      if (this.audiences != null && (length = this.audiences.size()) > 0) {
         for (int i = 0; i < length; i++) {
            String au = this.audiences.get(i);
            sb.append("<").append(appendNS).append("Audience").append(">").append(au).append("</").append(appendNS).append("Audience").append(">\n");
         }
      }

      sb.append("</").append(appendNS).append("ProxyRestriction").append(">\n");
      return sb.toString();
   }

   @Override
   public void makeImmutable() {
      if (this.isMutable) {
         if (this.audiences != null) {
            this.audiences = Collections.unmodifiableList(this.audiences);
         }

         this.isMutable = false;
      }
   }

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