package com.sun.identity.common;

import com.sun.identity.plugin.configuration.ConfigurationActionEvent;
import com.sun.identity.plugin.configuration.ConfigurationException;
import com.sun.identity.plugin.configuration.ConfigurationInstance;
import com.sun.identity.plugin.configuration.ConfigurationListener;
import com.sun.identity.plugin.configuration.ConfigurationManager;
import com.sun.identity.shared.configuration.SystemPropertiesManager;
import com.sun.identity.shared.debug.Debug;
import jakarta.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

public final class SystemConfigurationUtil implements ConfigurationListener {
   private static final String SVC_PLATFORM = "PLATFORM";
   private static ConfigurationInstance platformConfig;
   private static List<String> serverList;
   private static List<String> siteList;
   private static Map<String, String> serverToIdTable;
   private static Map<String, String> idToServerTable;
   private static boolean platformConfigInitialized;

   private SystemConfigurationUtil() {
   }

   private static Debug getDebug() {
      return Debug.getInstance("libPlugins");
   }

   public static List<String> getServerList() throws SystemConfigurationException {
      if (!platformConfigInitialized) {
         initPlatformConfig();
      }

      return serverList;
   }

   public static List<String> getSiteList() {
      if (!platformConfigInitialized) {
         initPlatformConfig();
      }

      return siteList;
   }

   public static String getServerID(String protocol, String hostname, int port, String uri) throws SystemConfigurationException {
      if (!platformConfigInitialized) {
         initPlatformConfig();
      }

      if (protocol != null && !protocol.isEmpty() && hostname != null && !hostname.isEmpty()) {
         String server = uri != null ? protocol + "://" + hostname + ":" + port + uri : protocol + "://" + hostname + ":" + port;
         server = server.toLowerCase(Locale.ROOT);
         String serverID = serverToIdTable.get(server);
         if (serverID == null) {
            Object[] data = new Object[]{server};
            throw new SystemConfigurationException("noServerID", data);
         } else {
            return serverID;
         }
      } else {
         throw new SystemConfigurationException("missingProtHost");
      }
   }

   public static String getServerFromID(String id) throws SystemConfigurationException {
      if (!platformConfigInitialized) {
         initPlatformConfig();
      }

      String server = idToServerTable.get(id);
      if (server == null) {
         Object[] data = new Object[]{id};
         throw new SystemConfigurationException("noServerFromID", data);
      } else {
         return server;
      }
   }

   @Nullable
   public static String getProperty(String propertyName) {
      return SystemPropertiesManager.get(propertyName);
   }

   @Nullable
   public static String getProperty(String propertyName, String defaultValue) {
      String value = SystemPropertiesManager.get(propertyName);
      return value == null ? defaultValue : value;
   }

   private static void storeServerList(Set<String> servers) {
      if (servers != null && !servers.isEmpty()) {
         int serverSize = servers.size();
         serverList = new ArrayList<>(serverSize);
         serverToIdTable = new Hashtable<>(serverSize);
         idToServerTable = new Hashtable<>(serverSize);

         for (String serverEntry : servers) {
            int index = serverEntry.indexOf(124);
            if (index != -1) {
               String server = serverEntry.substring(0, index).toLowerCase(Locale.ROOT);
               String serverId = serverEntry.substring(index + 1);
               index = serverId.indexOf(124);
               if (index != -1) {
                  serverId = serverId.substring(0, 2);
               }

               serverList.add(server);
               idToServerTable.put(serverId, server);
               serverToIdTable.put(server, serverId);
            } else {
               getDebug().error("SystemConfigurationUtil.storeServerList: Platform Server List entry is invalid:" + serverEntry);
            }
         }
      } else {
         serverList = Collections.emptyList();
         serverToIdTable = null;
         idToServerTable = null;
      }
   }

   private static void storeSiteList(Set<String> sites) {
      if (sites != null && !sites.isEmpty()) {
         siteList = new ArrayList<>(sites.size());

         for (String siteEntry : sites) {
            int index = siteEntry.indexOf(124);
            if (index != -1) {
               String site = siteEntry.substring(0, index).toLowerCase(Locale.ROOT);
               if (getDebug().messageEnabled()) {
                  getDebug().message("SystemConfigUtil.storeSiteList: add site" + site);
               }

               siteList.add(site);
            } else {
               getDebug().error("SystemConfigurationUtil.storeSiteList: Platform Server List entry is invalid:" + siteEntry);
            }
         }
      } else {
         siteList = Collections.emptyList();
      }
   }

   @Override
   public void configChanged(ConfigurationActionEvent event) {
      if (getDebug().messageEnabled()) {
         getDebug()
            .message(
               "SystemConfigurationUtil.configChanged: type = "
                  + event.getType()
                  + ", configuration name = "
                  + event.getConfigurationName()
                  + ", component name = "
                  + event.getComponentName()
                  + ", realm = "
                  + event.getRealm()
            );
      }

      update();
   }

   private static synchronized void update() {
      try {
         Map<String, Set<String>> avPairs = platformConfig.getConfiguration(null, null);
         if (avPairs != null && !avPairs.isEmpty()) {
            if (getDebug().messageEnabled()) {
               getDebug().message("SystemConfigUtil.update: servers=" + avPairs.get("iplanet-am-platform-server-list"));
               getDebug().message("SystemConfigUtil.update: sites=" + avPairs.get("iplanet-am-platform-site-list"));
            }

            Set<String> values = avPairs.get("iplanet-am-platform-server-list");
            if (values != null && !values.isEmpty()) {
               values.addAll(avPairs.get("iplanet-am-platform-site-list"));
            } else {
               values = avPairs.get("iplanet-am-platform-site-list");
            }

            storeServerList(values);
            storeSiteList(avPairs.get("iplanet-am-platform-site-list"));
         } else {
            serverList = Collections.emptyList();
            serverToIdTable = null;
            idToServerTable = null;
         }
      } catch (ConfigurationException ex) {
         getDebug().error("SystemConfigurationUtil.update:", ex);
      }
   }

   private static synchronized void initPlatformConfig() {
      if (!platformConfigInitialized) {
         try {
            platformConfig = ConfigurationManager.getConfigurationInstance("PLATFORM");
            platformConfig.addListener(new SystemConfigurationUtil());
         } catch (ConfigurationException cex) {
            getDebug().error("SystemConfigurationUtil.static: unable to get platform configuration.", cex);
         }

         update();
         platformConfigInitialized = true;
      }
   }
}
