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.IDPList;
import com.sun.identity.saml2.protocol.ProtocolFactory;
import com.sun.identity.saml2.protocol.RequesterID;
import com.sun.identity.saml2.protocol.Scoping;
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 ScopingImpl implements Scoping {
   private static final String PROXYCOUNT = "ProxyCount";
   private IDPList idpList;
   private List<RequesterID> requesterIDList;
   private boolean isMutable;
   private Integer proxyCount;

   public ScopingImpl() {
      this.isMutable = true;
   }

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

   @Override
   public IDPList getIDPList() {
      return this.idpList;
   }

   @Override
   public void setIDPList(IDPList idpList) throws SAML2Exception {
      if (this.isMutable) {
         this.idpList = idpList;
      } else {
         throw new SAML2Exception(SAML2SDKUtils.BUNDLE.getString("objectImmutable"));
      }
   }

   @Override
   public List<RequesterID> getRequesterIDs() {
      return this.requesterIDList;
   }

   @Override
   public void setRequesterIDs(List<RequesterID> value) throws SAML2Exception {
      if (this.isMutable) {
         this.requesterIDList = value;
      } else {
         throw new SAML2Exception(SAML2SDKUtils.BUNDLE.getString("objectImmutable"));
      }
   }

   @Override
   public Integer getProxyCount() {
      return this.proxyCount;
   }

   @Override
   public void setProxyCount(Integer proxyCount) throws SAML2Exception {
      if (this.isMutable) {
         this.proxyCount = proxyCount;
      } else {
         throw new SAML2Exception(SAML2SDKUtils.BUNDLE.getString("objectImmutable"));
      }
   }

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

   @Override
   public String toXMLString(boolean includeNSPrefix, boolean declareNS) throws SAML2Exception {
      String xmlElementString = null;
      if (this.idpList != null || this.requesterIDList != null && !this.requesterIDList.isEmpty() || this.proxyCount != null) {
         validateProxyCount(this.proxyCount);
         StringBuilder xmlString = new StringBuilder(300);
         xmlString.append("<");
         if (includeNSPrefix) {
            xmlString.append("samlp:");
         }

         xmlString.append("Scoping");
         if (declareNS) {
            xmlString.append(" xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\"");
         }

         if (this.proxyCount != null) {
            xmlString.append(" ").append("ProxyCount").append("=").append("\"").append(this.proxyCount.intValue()).append("\"");
         }

         xmlString.append(">").append("\n");
         if (this.idpList != null) {
            xmlString.append(this.idpList.toXMLString(includeNSPrefix, declareNS)).append("\n");
         }

         if (this.requesterIDList != null && !this.requesterIDList.isEmpty()) {
            for (RequesterID reqID : this.requesterIDList) {
               String reqIDStr = reqID.toXMLString(includeNSPrefix, declareNS);
               xmlString.append(reqIDStr).append("\n");
            }
         }

         xmlString.append("</samlp:").append("Scoping").append(">");
         xmlElementString = xmlString.toString();
      }

      return xmlElementString;
   }

   @Override
   public void makeImmutable() {
      if (this.isMutable) {
         this.idpList.makeImmutable();

         for (RequesterID reqID : this.requesterIDList) {
            reqID.makeImmutable();
         }

         this.isMutable = false;
      }
   }

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

   private void parseElement(Element element) throws SAML2Exception {
      String proxyCountStr = element.getAttribute("ProxyCount");
      if (proxyCountStr != null && !proxyCountStr.isEmpty()) {
         this.proxyCount = Integer.valueOf(proxyCountStr);
         validateProxyCount(this.proxyCount);
      }

      NodeList nList = element.getChildNodes();
      if (nList != null && nList.getLength() > 0) {
         if (this.requesterIDList == null || this.requesterIDList.isEmpty()) {
            this.requesterIDList = new ArrayList<>();
         }

         for (int i = 0; i < nList.getLength(); i++) {
            Node childNode = nList.item(i);
            String cName = childNode.getLocalName();
            if (cName != null) {
               if (cName.equals("IDPList")) {
                  this.validateIDPList();
                  this.idpList = ProtocolFactory.getInstance().createIDPList((Element)childNode);
               } else if (cName.equals("RequesterID")) {
                  RequesterID reqID = ProtocolFactory.getInstance().createRequesterID((Element)childNode);
                  this.requesterIDList.add(reqID);
               }
            }
         }

         if (this.requesterIDList != null && !this.requesterIDList.isEmpty()) {
            this.requesterIDList = Collections.unmodifiableList(this.requesterIDList);
         }
      }
   }

   private void validateIDPList() throws SAML2Exception {
      if (this.idpList != null) {
         SAML2SDKUtils.DEBUG.message("Too many IDPList Elements");
         throw new SAML2Exception(SAML2SDKUtils.BUNDLE.getString("schemaViolation"));
      }

      if (this.requesterIDList != null && !this.requesterIDList.isEmpty()) {
         SAML2SDKUtils.DEBUG.message("IDPList should be the first element");
         throw new SAML2Exception(SAML2SDKUtils.BUNDLE.getString("schemaViolation"));
      }
   }

   private static void validateProxyCount(Integer proxyCount) throws SAML2Exception {
      if (proxyCount != null && (proxyCount < 0 || proxyCount > 65535)) {
         if (SAML2SDKUtils.DEBUG.messageEnabled()) {
            SAML2SDKUtils.DEBUG.message("ProxyCount value should be a nonnegative Integer");
         }

         throw new SAML2Exception(SAML2SDKUtils.BUNDLE.getString("invalidProxyCount"));
      }
   }
}
