/*
 * The contents of this file are subject to the Mozilla Public License Version 1.1
 * (the "License"); you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
 * 
 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
 * language governing rights and limitations under the License.
 * 
 * The Original Code is the Venice Web Communities System.
 * 
 * The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
 * for Silverwrist Design Studios.  Portions created by Eric J. Bowersox are
 * Copyright (C) 2002-03 Eric J. Bowersox/Silverwrist Design Studios.  All Rights Reserved.
 * 
 * Contributor(s): 
 */
package com.silverwrist.dynamo.util;

import java.util.*;
import com.silverwrist.dynamo.except.*;
import com.silverwrist.dynamo.iface.*;

/**
 * A simple in-memory implementation of {@link com.silverwrist.dynamo.iface.ObjectStore ObjectStore}.  This
 * is used, for instance, as part of the standard {@link com.silverwrist.dynamo.iface.Request Request} and
 * {@link com.silverwrist.dynamo.iface.SessionInfo SessionInfo} objects.
 *
 * @author Eric J. Bowersox &lt;erbo@silcom.com&gt;
 * @version X
 */
public class MemoryObjectStore implements ObjectStore
{
  /*--------------------------------------------------------------------------------
   * Attributes
   *--------------------------------------------------------------------------------
   */

  private HashMap m_data;      // where the data is
  private String m_context;    // context, to be used for error messages

  /*--------------------------------------------------------------------------------
   * Constructor
   *--------------------------------------------------------------------------------
   */

  /**
   * Creates a new, empty <CODE>MemoryObjectStore</CODE>.
   *
   * @param context The context of this store, to be used in generating error messages.
   */
  public MemoryObjectStore(String context)
  {
    m_data = new HashMap();
    m_context = context;

  } // end constructor

  /**
   * Creates a new <CODE>MemoryObjectStore</CODE>, and optionally copies the contents of another
   * {@link com.silverwrist.dynamo.iface.ObjectStore ObjectStore} into it.
   *
   * @param context The context of this store, to be used in generating error messages.
   * @param copy_from If not <CODE>null</CODE>, designates an <CODE>ObjectStore</CODE> whose contents will
   *                  be copied into this one.
   */
  public MemoryObjectStore(String context, ObjectStore copy_from)
  {
    m_data = new HashMap();
    m_context = context;
    if (copy_from!=null)
    { // copy the contents of the ObjectStore
      Collection nsc = copy_from.getNamespaces();
      Iterator it1 = nsc.iterator();
      while (it1.hasNext())
      { // get all namespaces and get their contents
	String ns = (String)(it1.next());
	HashMap ns_map = new HashMap();
	Collection namec = copy_from.getNamesForNamespace(ns);
	Iterator it2 = namec.iterator();
	while (it2.hasNext())
	{ // copy contents of the object store
	  String name = (String)(it2.next());
	  ns_map.put(name,copy_from.getObject(ns,name));

	} // end while

	m_data.put(ns,ns_map);

      } // end while

    } // end if

  } // end constructor

  /*--------------------------------------------------------------------------------
   * Implementations from interface ObjectProvider
   *--------------------------------------------------------------------------------
   */

  /**
   * Retrieves an object from this <CODE>ObjectProvider</CODE>.
   *
   * @param namespace The namespace to interpret the name relative to.
   * @param name The name of the object to be retrieved.
   * @return The object reference specified.
   */
  public synchronized Object getObject(String namespace, String name)
  {
    Object rc = null;
    HashMap ns_map = (HashMap)(m_data.get(namespace));
    if (ns_map!=null)
      rc = ns_map.get(name);
    if (rc==null)
      throw new NoSuchObjectException(m_context,namespace,name);
    return rc;

  } // end getObject

  /*--------------------------------------------------------------------------------
   * Implementations from interface ObjectStore
   *--------------------------------------------------------------------------------
   */

  /**
   * Sets an object into this <CODE>ObjectStore</CODE>.
   *
   * @param namespace The namespace to interpret the name relative to.
   * @param name The name of the object to be set.
   * @param value The object to set into the <CODE>ObjectStore</CODE>.
   * @return The previous object that was set into the <CODE>ObjectStore</CODE> under this namespace and name, or
   *         <CODE>null</CODE> if there was no such object.
   */
  public synchronized Object setObject(String namespace, String name, Object value)
  {
    HashMap ns_map = (HashMap)(m_data.get(namespace));
    if (ns_map==null)
    { // create new map for this namespace
      ns_map = new HashMap();
      m_data.put(namespace,ns_map);

    } // end if

    return ns_map.put(name,value);

  } // end setObject

  /**
   * Removes an object from this <CODE>ObjectStore</CODE>.
   *
   * @param namespace The namespace to interpret the name relative to.
   * @param name The name of the object to be removed.
   * @return The previous object that was set into the <CODE>ObjectStore</CODE> under this namespace and name, or
   *         <CODE>null</CODE> if there was no such object.
   */
  public synchronized Object removeObject(String namespace, String name)
  {
    Object rc = null;
    HashMap ns_map = (HashMap)(m_data.get(namespace));
    if (ns_map!=null)
      rc = ns_map.remove(name);
    return rc;

  } // end removeObject

  /**
   * Returns a collection of all object namespaces that have been set into this <CODE>ObjectStore</CODE>.
   *
   * @return A <CODE>java.util.Collection</CODE> containing <CODE>String</CODE> objects specifying all the
   *         object namespaces.
   */
  public synchronized Collection getNamespaces()
  {
    if (m_data.isEmpty())
      return Collections.EMPTY_LIST;
    ArrayList rc = new ArrayList(m_data.size());
    rc.addAll(m_data.keySet());
    return Collections.unmodifiableList(rc);

  } // end getNamespaces

  /**
   * Returns a collection of all object names that have been set into this <CODE>ObjectStore</CODE> under a given
   * namespace.
   *
   * @param namespace The namespace to look for names under.
   * @return A <CODE>java.util.Collection</CODE> containing <CODE>String</CODE> objects specifying all the
   *         object names for this namespace.
   */
  public synchronized Collection getNamesForNamespace(String namespace)
  {
    HashMap ns_map = (HashMap)(m_data.get(namespace));
    if ((ns_map==null) || (ns_map.isEmpty()))
      return Collections.EMPTY_LIST;
    ArrayList rc = new ArrayList(ns_map.size());
    rc.addAll(ns_map.keySet());
    return Collections.unmodifiableList(rc);

  } // end getNamesforNamespace

  /*--------------------------------------------------------------------------------
   * External operations
   *--------------------------------------------------------------------------------
   */

  /**
   * Visits each object in this store with the specified
   * {@link com.silverwrist.dynamo.util.ObjectVisitor ObjectVisitor}.
   *
   * @param visitor The <CODE>ObjectVisitor</CODE> that will visit all objects in the store.
   */
  public synchronized void visitAllContents(ObjectVisitor visitor)
  {
    Iterator it1 = m_data.entrySet().iterator();
    while (it1.hasNext())
    { // get namespace and name contents
      Map.Entry ntry1 = (Map.Entry)(it1.next());
      String namespace = (String)(ntry1.getKey());
      Iterator it2 = ((Map)(ntry1.getValue())).entrySet().iterator();
      while (it2.hasNext())
      { // get names for each namespace and visit them
	Map.Entry ntry2 = (Map.Entry)(it2.next());
	visitor.visit(namespace,(String)(ntry2.getKey()),ntry2.getValue());

      } // end while

    } // end while

  } // end visitAllContents

  /**
   * Erases the contents of this store.
   */
  public synchronized void clear()
  {
    Iterator it = m_data.values().iterator();
    while (it.hasNext())
    { // clear all submaps
      Map map = (Map)(it.next());
      map.clear();

    } // end while

    m_data.clear();  // and clear this map

  } // end clear

} // end class MemoryObjectStore
