package com.sun.identity.cot;

import com.sun.identity.plugin.configuration.ConfigurationException;
import com.sun.identity.plugin.configuration.ConfigurationInstance;
import com.sun.identity.plugin.configuration.ConfigurationManager;
import com.sun.identity.shared.debug.Debug;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;

public class CircleOfTrustManager {
   private static ConfigurationInstance configInst;
   private static final Debug DEBUG = COTUtils.DEBUG;

   public CircleOfTrustManager() throws COTException {
      if (configInst == null) {
         throw new COTException("nullConfig", null);
      }
   }

   private Set<String> getAllCirclesOfTrust(String realm) throws COTException {
      Set<String> cotSet = new HashSet<>();
      if (realm == null) {
         realm = "/";
      }

      String classMethod = "COTManager.getAllCircleOfTrust: ";

      try {
         Set<String> valueSet = configInst.getAllConfigurationNames(realm);
         if (valueSet != null && !valueSet.isEmpty()) {
            cotSet.addAll(valueSet);
         }

         return cotSet;
      } catch (ConfigurationException e) {
         DEBUG.error(classMethod, e);
         String[] data = new String[]{e.getMessage(), realm};
         LogUtil.error(Level.INFO, "CONFIG_ERROR_GET_ALL_COT_DESCRIPTOR", data);
         throw new COTException(e);
      }
   }

   private CircleOfTrustDescriptor getCircleOfTrust(String realm, String name) throws COTException {
      String classMethod = "COTManager.getCircleOfTrust :";
      if (realm == null) {
         realm = "/";
      }

      this.validateCOTName(realm, name);
      String[] data = new String[]{name, realm};
      CircleOfTrustDescriptor cotDesc = COTCache.getCircleOfTrust(realm, name);
      if (cotDesc != null) {
         LogUtil.access(Level.FINE, "COT_FROM_CACHE", data);
      } else {
         try {
            Map<String, Set<String>> attrs = configInst.getConfiguration(realm, name);
            if (attrs == null) {
               cotDesc = new CircleOfTrustDescriptor();
            } else {
               cotDesc = new CircleOfTrustDescriptor(attrs);
            }

            COTCache.putCircleOfTrust(realm, name, cotDesc);
            LogUtil.access(Level.INFO, "COT_DESCRIPTOR_RETRIEVED", data);
         } catch (ConfigurationException e) {
            DEBUG.error(classMethod, e);
            LogUtil.error(Level.INFO, "CONFIG_ERROR_GET_COT_DESCRIPTOR", new String[]{e.getMessage(), name, realm});
            throw new COTException(e);
         }
      }

      return cotDesc;
   }

   public boolean isInCircleOfTrust(String realm, String name, String protocolType, String entityId) {
      try {
         CircleOfTrustDescriptor cotd = this.getCircleOfTrust(realm, name);
         Set<String> pSet = cotd.getTrustedProviders(protocolType);
         return pSet.contains(entityId);
      } catch (Exception me) {
         DEBUG.error("COTManager.isInCircleOfTrust", me);
         String[] data = new String[]{me.getMessage(), name, entityId, realm};
         LogUtil.error(Level.INFO, "CONFIG_ERROR_RETREIVE_COT", data);
         return false;
      }
   }

   private void validateCOTName(String realm, String name) throws COTException {
      String classMethod = "COTManager.isValidCOTName: ";
      if (name == null || name.trim().isEmpty() || !this.getAllCirclesOfTrust(realm).contains(name)) {
         DEBUG.error(classMethod + "invalid circle of trust name :" + name);
         String[] data = new String[]{realm, name};
         LogUtil.error(Level.INFO, "INVALID_COT_NAME", data);
         throw new COTException("invalidCOTName", data);
      }
   }

   static {
      try {
         configInst = ConfigurationManager.getConfigurationInstance("LIBCOT");
      } catch (ConfigurationException ce) {
         DEBUG.error("COTManager.static: Unable to get COT service config", ce);
         configInst = null;
      }

      if (configInst != null) {
         try {
            configInst.addListener(new COTServiceListener());
         } catch (ConfigurationException ce) {
            DEBUG.error("COTManager.static: Unable to add ConfigurationListener for COT service.", ce);
         }
      }
   }
}
