/***********************************************************************
 * 
 *  Copyright (C) 2006 Novell, Inc. All Rights Reserved.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; version 2.1
 *  of the License.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, Novell, Inc.
 * 
 *  To contact Novell about this file by physical or electronic mail, 
 *  you may find current contact information at www.novell.com.
 * 
 *  Author: Juan Carlos Luciani <jluciani@novell.com>
 *  
 ***********************************************************************/

package com.novell.casa.authtoksvc;

import java.util.*;

import org.xml.sax.SAXException;

/**
 * Settings file SAXHandler Class.
 * <p>
 * This class provides a SAXHandler for parsing .settings files.
 * 
 */
public final class SettingsFileSAXHandler extends org.xml.sax.helpers.DefaultHandler
{
   private final static int AWAITING_ROOT_ELEMENT_START = 0;
   private final static int AWAITING_SETTING_ELEMENT_START = 1;
   private final static int AWAITING_SETTING_ELEMENT_DATA = 2;
   private final static int AWAITING_SETTING_ELEMENT_END = 3;
   private final static int DONE_PARSING = 4;

   private final static String m_rootElementName = "settings";

   private final Map<String,String>    m_keyMap;
   private int    m_state;
   private String m_currentKey;

   /**
    * Constructor.
    *
    * @param keyMap  Key/Value map.
    */
   public SettingsFileSAXHandler(Map<String,String> keyMap)
   {
      super();

      // Initialize our members
      m_keyMap = keyMap;
      m_state = AWAITING_ROOT_ELEMENT_START;
   }

   /**
    * endDocument() implementation.
    *
    * @throws SAXException
    */
   public final void endDocument () throws SAXException
   {
      // Verify that we are not in an invalid state
      if (m_state != DONE_PARSING)
      {
         System.err.println("SettingsFileSAXHandler.endDocument()- Invalid state" + m_state);
         throw new SAXException("Invalid state at endDocument");
      }
   }

   /**
    * startElement() implementation.
    *
    * @param uri     Uri.
    * @param name    Local name.
    * @param qName   Qualified name.
    * @param atts    Attributes.
    * @throws SAXException
    */
   public final void startElement (String uri, String name, String qName, org.xml.sax.Attributes atts) throws SAXException
   {
      // Proceed based on our state
      switch (m_state)
      {
         case AWAITING_ROOT_ELEMENT_START:
            // Verify that we are processing the expected tag
            if (m_rootElementName.equalsIgnoreCase(qName))
            {
               // Advance to the next state
               m_state = AWAITING_SETTING_ELEMENT_START;
            }
            else
            {
               System.err.println("SettingsFileSAXHandler.startElement()- Un-expected element");
               throw new SAXException("Un-expected element");
            }
            break;

         case AWAITING_SETTING_ELEMENT_START:
            // Keep track of the key name
            m_currentKey = qName;

            // Advance to the next state
            m_state = AWAITING_SETTING_ELEMENT_DATA;
            break;

         default:
            System.err.println("SettingsFileSAXHandler.startElement()- Invalid state " + m_state);
            throw new SAXException("Invalid state at startElement");
      }
   }

   /**
    * endElement() implementation.
    *
    * @param uri     Uri.
    * @param name    Local name.
    * @param qName   Qualified name.
    * @throws SAXException
    */
   public final void endElement (String uri, String name, String qName) throws SAXException
   {
      // Proceed based on our state
      switch (m_state)
      {
         case AWAITING_SETTING_ELEMENT_DATA:
         case AWAITING_SETTING_ELEMENT_END:
            // Advance to the next state
            m_state = AWAITING_SETTING_ELEMENT_START;
            break;

         case AWAITING_SETTING_ELEMENT_START:
            // Verify that we are processing the expected tag
            if (m_rootElementName.equalsIgnoreCase(qName))
            {
               // Advance to the next state
               m_state = DONE_PARSING;
            }
            else
            {
               System.err.println("SettingsFileSAXHandler.endElement()- Un-expected element");
               throw new SAXException("Un-expected element");
            }
            break;

         default:
            System.err.println("SettingsFileSAXHandler.endElement()- Invalid state " + m_state);
            throw new SAXException("Invalid state at endElement");
      }
   }

   /**
    * character() implementation.
    *
    * @param ch      Characters with element data.
    * @param start   Start position in the character array.
    * @param length  Number of characters to use in the array.
    * @throws SAXException
    */
   public final void characters (char ch[], int start, int length) throws SAXException
   {
      // Consume the data if in the right state
      if (m_state == AWAITING_SETTING_ELEMENT_DATA)
      {
         // Consume the data and add the key to map
         m_keyMap.put(m_currentKey, new String(ch, start, length));

         // Advance to the next state
         m_state = AWAITING_SETTING_ELEMENT_END;
      }
      else if (m_state == AWAITING_SETTING_ELEMENT_END)
      {
         // Concat this data to the setting data that we have already consumed
         String settingData = m_keyMap.remove(m_currentKey);
         if (settingData != null)
         {
            // Consume the data and add the key to map
            m_keyMap.put(m_currentKey, settingData.concat(new String(ch, start, length)));
         }
         else
         {
            System.err.println("SettingsFileSAXHandler.characters()- Settings data not found");
            throw new SAXException("Settings data not found");
         }
      }
   }
}
