/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.security.auth.login;

import java.util.HashMap;
import javax.security.auth.login.AppConfigurationEntry;

import org.jboss.xml.binding.ObjectModelFactory;
import org.jboss.xml.binding.ContentNavigator;
import org.jboss.util.StringPropertyReplacer;
import org.xml.sax.Attributes;

/** A JBossXB object factory for parsing the login-config.xml object model. 
 * 
 * @author Scott.Stark@jboss.org
 * @version $Revision: 1.1.2.2 $
 */
public class LoginConfigObjectModelFactory implements ObjectModelFactory
{
   public Object newRoot(Object root, ContentNavigator navigator, 
      String namespaceURI, String localName, Attributes attrs)
   {
      if (!localName.equals("policy"))
      {
         throw new IllegalStateException("Unexpected root element: was expecting 'policy' but got '" + localName + "'");
      }
      return new PolicyConfig();
   }

   
   public Object newChild(PolicyConfig config, ContentNavigator navigator,
      String namespaceUri, String localName, Attributes attrs)
   {
      Object child = null;
      if("application-policy".equals(localName))
      {
         String name = attrs.getValue("name");
         child = new AuthenticationInfo(name);
      }
      return child;
   }
   public Object newChild(AuthenticationInfo info, ContentNavigator navigator,
      String namespaceUri, String localName, Attributes attrs)
   {
      Object child = null;
      if("login-module".equals(localName))
      {
         String code = attrs.getValue("code");
         code = StringPropertyReplacer.replaceProperties(code.trim());
         String flag = attrs.getValue("flag");
         flag = StringPropertyReplacer.replaceProperties(flag.trim());
         AppConfigurationEntryHolder holder = new AppConfigurationEntryHolder(code, flag);
         child = holder;
      }

      return child;
   }
   public Object newChild(AppConfigurationEntryHolder entry, ContentNavigator navigator,
      String namespaceUri, String localName, Attributes attrs)
   {
      Object child = null;
      if("module-option".equals(localName))
      {
         String name = attrs.getValue("name");         
         child = new ModuleOption(name);
      }

      return child;
   }

   public void setValue(ModuleOption option, ContentNavigator navigator,
      String namespaceUri, String localName, String value)
   {
      if("module-option".equals(localName))
      {
         String valueWithReplacement = StringPropertyReplacer.replaceProperties(value.trim());
         option.setValue(valueWithReplacement);
      }
   }

   public void addChild(PolicyConfig config, AuthenticationInfo authInfo,
      ContentNavigator navigator, String namespaceURI, String localName)
   {
      config.add(authInfo);
   }
   public void addChild(AuthenticationInfo authInfo, AppConfigurationEntryHolder entryInfo,
      ContentNavigator navigator, String namespaceURI, String localName)
   {
      AppConfigurationEntry entry = entryInfo.getEntry();
      authInfo.addAppConfigurationEntry(entry);
   }
   public void addChild(AppConfigurationEntryHolder entryInfo, ModuleOption option,
      ContentNavigator navigator, String namespaceURI, String localName)
   {
      entryInfo.addOption(option);
   }
   public void addChild(ModuleOption option, Object value,
      ContentNavigator navigator, String namespaceURI, String localName)
   {
      option.setValue(value);
   }

   private static class AppConfigurationEntryHolder
   {
      String code;
      AppConfigurationEntry.LoginModuleControlFlag controlFlag;
      HashMap options = new HashMap();
      AppConfigurationEntryHolder(String code, String flag)
      {
         this.code = code;
         controlFlag = AppConfigurationEntry.LoginModuleControlFlag.REQUIRED;
         if (flag != null)
         {
            // Lower case is what is used by the jdk1.4.1 implementation
            flag = flag.toLowerCase();
            if (AppConfigurationEntry.LoginModuleControlFlag.REQUIRED.toString().indexOf(flag) > 0)
               controlFlag = AppConfigurationEntry.LoginModuleControlFlag.REQUIRED;
            else if (AppConfigurationEntry.LoginModuleControlFlag.REQUISITE.toString().indexOf(flag) > 0)
               controlFlag = AppConfigurationEntry.LoginModuleControlFlag.REQUISITE;
            else if (AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT.toString().indexOf(flag) > 0)
               controlFlag = AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT;
            else if (AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL.toString().indexOf(flag) > 0)
               controlFlag = AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL;
         }
      }

      public AppConfigurationEntry getEntry()
      {
         AppConfigurationEntry entry = new AppConfigurationEntry(code, controlFlag, options);
         return entry;
      }

      public void addOption(ModuleOption option)
      {
         options.put(option.name, option.value);
      }
   }
   private static class ModuleOption
   {
      String name;
      Object value = "";
      ModuleOption(String name)
      {
         this.name = name;
      }
      void setValue(Object value)
      {
         this.value = value;
      }
   }
}