/*
 * 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) 2003 Eric J. Bowersox/Silverwrist Design Studios.  All Rights Reserved.
 * 
 * Contributor(s): 
 */
package com.silverwrist.venice.community;

import java.security.Principal;
import java.security.acl.AclNotFoundException;
import java.util.*;
import com.silverwrist.dynamo.except.*;
import com.silverwrist.dynamo.iface.*;
import com.silverwrist.venice.CommunityVisibility;
import com.silverwrist.venice.except.*;
import com.silverwrist.venice.iface.*;

/**
 * A "proxy object" for communities, which is returned by property deserialization.
 *
 * @author Eric J. Bowersox &lt;erbo@silcom.com&gt;
 * @version X
 */
abstract class CommunityProxy implements VeniceCommunity, DynamicWrapper
{
  /*--------------------------------------------------------------------------------
   * Attributes
   *--------------------------------------------------------------------------------
   */

  /**
   * The ID of the community that this object is a proxy for.
   */
  protected int m_id;

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

  /**
   * Constructs a new <CODE>CommunityProxy</CODE> object.
   *
   * @param cid ID of the community that this object is to be a proxy for.
   */
  CommunityProxy(int cid)
  {
    m_id = cid;

  } // end constructor

  /*--------------------------------------------------------------------------------
   * Abstract operations
   *--------------------------------------------------------------------------------
   */

  /**
   * Returns a reference to the "real" {@link com.silverwrist.venice.iface.VeniceCommunity VeniceCommunity} object
   * underlying this proxy.
   *
   * @return A reference to the "real" community object.
   */
  protected abstract VeniceCommunity getRealCommunity();

  /*--------------------------------------------------------------------------------
   * Overrides from class Object
   *--------------------------------------------------------------------------------
   */

  /**
   * Indicates whether some other object is "equal to" this one.
   *
   * @param o The reference object with which to compare.
   * @return <CODE>true</CODE> if this object is the same as the <CODE>o</CODE> argument; <CODE>false</CODE> otherwise.
   */
  public boolean equals(Object o)
  {
    if (o==null)
      return false;
    if (o instanceof VeniceCommunity)
      return (((VeniceCommunity)o).getCID()==m_id);
    return false;

  } // end equals

  /**
   * Returns a hash code value for the object. This method is supported for the benefit of hashtables such as those
   * provided by {@link java.util.Hashtable Hashtable}.
   *
   * @return A hash code value for this object.
   */
  public int hashCode()
  {
    return m_id;

  } // end hashCode

  /**
   * Returns a string representation of the object. In general, the <CODE>toString</CODE> method returns a string
   * that "textually represents" this object. 
   *
   * @return A string representation of the object.
   */
  public String toString()
  {
    return "Community #" + m_id;

  } // end toString

  /*--------------------------------------------------------------------------------
   * Implementations from interface NamedObject
   *--------------------------------------------------------------------------------
   */

  /**
   * Returns the name of this community.
   *
   * @return The name of this community.
   */
  public String getName()
  {
    return getRealCommunity().getName();

  } // end getName

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

  /**
   * Retrieves an object from the community's properties.
   *
   * @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 Object getObject(String namespace, String name)
  {
    return getRealCommunity().getObject(namespace,name);

  } // end getObject

  /*--------------------------------------------------------------------------------
   * Implementations from interface SecureObjectStore
   *--------------------------------------------------------------------------------
   */

  /**
   * Sets an object into the community's properties.
   *
   * @param caller The user performing the operation.
   * @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 community's properties.
   * @return The previous object that was set into the community's properties under this namespace and name, or
   *         <CODE>null</CODE> if there was no such object.
   * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error setting the object value.
   * @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to
   *            set this object value into this community's properties.
   */
  public Object setObject(DynamoUser caller, String namespace, String name, Object value)
      throws DatabaseException, DynamoSecurityException
  {
    return getRealCommunity().setObject(caller,namespace,name,value);

  } // end setObject

  /**
   * Removes an object from this community's properties.
   *
   * @param caller The user performing the operation.
   * @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 community's properties under this namespace and name, or
   *         <CODE>null</CODE> if there was no such object.
   * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error removing the object value.
   * @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to
   *            remove this object value from this community's properties.
   */
  public Object removeObject(DynamoUser caller, String namespace, String name)
      throws DatabaseException, DynamoSecurityException
  {
    return getRealCommunity().removeObject(caller,namespace,name);

  } // end removeObject

  /**
   * Returns a collection of all object namespaces that have been set into this community's properties.
   *
   * @return A {@link java.util.Collection Collection} containing {@link java.lang.String String} objects specifying
   *         all the object namespaces.
   * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error getting the namespace list.
   */
  public Collection getNamespaces() throws DatabaseException
  {
    return getRealCommunity().getNamespaces();

  } // end getNamespaces

  /**
   * Returns a collection of all object names that have been set into this community's properties under
   * a given namespace.
   *
   * @param namespace The namespace to look for names under.
   * @return A {@link java.util.Collection Collection} containing {@link java.lang.String String} objects
   *         specifying all the object names for this namespace.
   * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error getting the object name list.
   */
  public Collection getNamesForNamespace(String namespace) throws DatabaseException
  {
    return getRealCommunity().getNamesForNamespace(namespace);

  } // end getNamesForNamespace

  /*--------------------------------------------------------------------------------
   * Implementations from interface VeniceCommunity
   *--------------------------------------------------------------------------------
   */

  /**
   * Returns the community ID of this community.  The community ID is set when the community is created and may
   * not be altered.
   *
   * @return The community ID of this community.
   */
  public int getCID()
  {
    return m_id;

  } // end getCID

  /**
   * Returns the GID of the <EM>member group</EM> of this community.  The member group specifies all
   * members of the community.
   *
   * @return The GID of the member group for this community.
   */
  public int getMemberGID()
  {
    return getRealCommunity().getMemberGID();

  } // end getMemberGID

  /**
   * Returns a reference to the <EM>member group</EM> of this community.  The member group specifies all
   * members of the community.
   *
   * @return A reference to the member group of this community.
   * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error getting the member group.
   */
  public DynamoGroup getMemberGroup() throws DatabaseException
  {
    return getRealCommunity().getMemberGroup();

  } // end getMemberGroup

  /**
   * Returns the GID of the <EM>host group</EM> of this community.  The host group specifies all
   * hosts of the community, who generally have power to change most attributes of a community.
   *
   * @return The GID of the host group for this community.
   */
  public int getHostGID()
  {
    return getRealCommunity().getHostGID();

  } // end getHostGID

  /**
   * Returns a reference to the <EM>host group</EM> of this community.  The host group specifies all
   * hosts of the community, who generally have power to change most attributes of a community.
   *
   * @return A reference to the host group of this community.
   * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error getting the host group.
   */
  public DynamoGroup getHostGroup() throws DatabaseException
  {
    return getRealCommunity().getHostGroup();

  } // end getHostGroup

  /**
   * Returns the UID of the <EM>host user</EM> of this community.  The host user is the primary host of the
   * community, who is the only one who has power to add or remove additional hosts.
   *
   * @return The UID of the host user of the community.
   */
  public int getHostUID()
  {
    return getRealCommunity().getHostUID();

  } // end getHostUID

  /**
   * Returns a reference to the <EM>host user</EM> of this community.  The host user is the primary host of the
   * community, who is the only one who has power to add or remove additional hosts.
   *
   * @return A reference to the host user of the community.
   * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error getting the host user.
   */
  public DynamoUser getHostUser() throws DatabaseException
  {
    return getRealCommunity().getHostUser();

  } // end getHostUser

  /**
   * Returns a reference to the community's access control list.
   *
   * @return A reference to the community's access control list.
   * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error getting the ACL.
   * @exception java.security.acl.AclNotFoundException If the community ACL could not be found.
   */
  public DynamoAcl getAcl() throws DatabaseException, AclNotFoundException
  {
    return getRealCommunity().getAcl();

  } // end getAcl
 
  /**
   * Returns the category ID of the community, specifying its location in the community directory.
   *
   * @return The category ID of the community.
   */
  public int getCategoryID()
  {
    return getRealCommunity().getCategoryID();

  } // end getCategoryID

  /**
   * Returns the category of the community, specifying its location in the community directory.
   *
   * @return The category of the community.
   * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error getting the category object.
   */
  public VeniceCategory getCategory() throws DatabaseException
  {
    return getRealCommunity().getCategory();

  } // end getCategory

  /**
   * Changes the category ID of the community, specifying its location in the community directory.
   *
   * @param caller The user attempting to change the category ID.
   * @param catid The new category ID for the community.
   * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error resetting the category.
   * @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to
   *            change the category ID.
   */
  public synchronized void setCategoryID(DynamoUser caller, int catid)
      throws DatabaseException, DynamoSecurityException
  {
    getRealCommunity().setCategoryID(caller,catid);

  } // end setCategoryID

  /**
   * Changes the category of the community, specifying its location in the community directory.
   *
   * @param caller The user attempting to change the category.
   * @param catid The new category for the community.
   * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error resetting the category.
   * @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to
   *            change the category.
   */
  public void setCategory(DynamoUser caller, VeniceCategory cat) throws DatabaseException, DynamoSecurityException
  {
    this.setCategoryID(caller,cat.getCategoryID());

  } // end setCategory

  /**
   * Returns the current {@link com.silverwrist.venice.CommunityVisibility visibility} of the community.
   *
   * @return The current visibility of the community.
   */
  public CommunityVisibility getVisibility()
  {
    return getRealCommunity().getVisibility();

  } // end getVisibility

  /**
   * Sets the current {@link com.silverwrist.venice.CommunityVisibility visibility} of the community.
   *
   * @param caller The user attempting to change the community's visibility.
   * @param vis The new visibility for the community.
   * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error resetting the visibility.
   * @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to
   *            change the community visibility.
   */
  public synchronized void setVisibility(DynamoUser caller, CommunityVisibility vis)
      throws DatabaseException, DynamoSecurityException
  {
    getRealCommunity().setVisibility(caller,vis);

  } // end setVisibility

  /**
   * Sets the name of the community.
   *
   * @param caller The user attempting to change the community's name.
   * @param name The new name for the community.
   * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error resetting the name.
   * @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to
   *            change the community name.
   */
  public synchronized void setName(DynamoUser caller, String name) throws DatabaseException, DynamoSecurityException
  {
    getRealCommunity().setName(caller,name);

  } // end setName

  /**
   * Returns the <EM>alias</EM> of the community.  The alias is a unique identifier for the community that must
   * conform to the rules for Dynamo identifiers.
   *
   * @return The alias for the community.
   */
  public String getAlias()
  {
    return getRealCommunity().getAlias();

  } // end getAlias

  /**
   * Sets the <EM>alias</EM> of the community.  The alias is a unique identifier for the community that must
   * conform to the rules for Dynamo identifiers.
   *
   * @param caller The user attempting to change the community's alias.
   * @param alias The new alias for the community.
   * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error resetting the alias.
   * @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to
   *            change the community alias.
   */
  public synchronized void setAlias(DynamoUser caller, String alias) throws DatabaseException, DynamoSecurityException
  {
    getRealCommunity().setAlias(caller,alias);

  } // end setAlias

  /**
   * Returns the date and time at which this community was created.
   *
   * @return The creation date and time for this community.
   */
  public java.util.Date getCreationDate()
  {
    return getRealCommunity().getCreationDate();

  } // end getCreationDate

  /**
   * Returns the date and time at which this community was last accessed.
   *
   * @return The last access date and time for this community.
   */
  public java.util.Date getLastAccessDate()
  {
    return getRealCommunity().getLastAccessDate();

  } // end getLastAccessDate

  /**
   * Sets the date and time at which this community was last accessed.
   *
   * @param caller The user attempting to change the community's access date/time.
   * @param date The new access date/time for the community.
   * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error resetting the access date/time.
   * @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to
   *            change the community access date/time.
   */
  public synchronized void setLastAccessDate(DynamoUser caller, java.util.Date date)
      throws DatabaseException, DynamoSecurityException
  {
    getRealCommunity().setLastAccessDate(caller,date);

  } // end setLastAccessedDate

  /**
   * Returns the date and time at which this community was last updated.
   *
   * @return The last update date and time for this community.
   */
  public java.util.Date getLastUpdateDate()
  {
    return getRealCommunity().getLastUpdateDate();

  } // end getLastUpdateDate

  /**
   * Sets the date and time at which this community was last updated.
   *
   * @param caller The user attempting to change the community's update date/time.
   * @param date The new update date/time for the community.
   * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error resetting the update date/time.
   * @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to
   *            change the community update date/time.
   */
  public synchronized void setLastUpdateDate(DynamoUser caller, java.util.Date date)
      throws DatabaseException, DynamoSecurityException
  {
    getRealCommunity().setLastUpdateDate(caller,date);

  } // end setLastUpdateDate

  /**
   * Grants permission to join the community to a specific user or group.  This permission may be contingent upon
   * the user authenticating with the community in some fashion, and it may also be single-use, meaning the permission
   * is automatically revoked whenever a user uses it to join the community.
   *
   * @param caller The person attempting to grant access to the community.
   * @param subject The {@link com.silverwrist.dynamo.iface.DynamoUser user} or
   *                {@link com.silverwrist.dynamo.iface.DynamoGroup group} that we want to grant access to.
   * @param auth_namespace The namespace of the authenticator to use to grant access.  If both this parameter and
   *                       <EM>auth_name</EM> are <CODE>null</CODE>, no authentication is required.
   * @param auth_name The name of the authenticator to use to grant access.  If both this parameter and
   *                  <EM>auth_namespace</EM> are <CODE>null</CODE>, no authentication is required.
   * @param source_info The source information for the authenticator.  If <EM>auth_namespace</EM> and
   *                    <EM>auth_name</EM> are <CODE>null</CODE>, this parameter is ignored.
   * @param auth_info The authentication information (such as a password) for the authenticator.  If
   *                  <EM>auth_namespace</EM> and <EM>auth_name</EM> are <CODE>null</CODE>, this parameter is ignored.
   * @param single_use If this parameter is <CODE>true</CODE>, the permission will automatically be revoked after the
   *                   first time it is successfully used by a user to join the community.
   * @exception com.silverwrist.dynamo.except.AuthenticationException If the named authenticator is not a valid one.
   * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error registering the access grant.
   * @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to grant
   *            access to this community.
   */
  public void grantAccess(DynamoUser caller, Principal subject, String auth_namespace, String auth_name,
			  String source_info, String auth_info, boolean single_use)
      throws AuthenticationException, DatabaseException, DynamoSecurityException
  {
    getRealCommunity().grantAccess(caller,subject,auth_namespace,auth_name,source_info,auth_info,single_use);

  } // end grantAccess

  /**
   * Revokes permission to join the community from a specific user or group.  This does not affect any user who
   * has already joined the community.
   *
   * @param caller The person attempting to revoke access to the community.
   * @param subject The {@link com.silverwrist.dynamo.iface.DynamoUser user} or
   *                {@link com.silverwrist.dynamo.iface.DynamoGroup group} that we want to revoke access from.
   * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error registering the access revoke.
   * @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to revoke
   *            access to this community.
   */
  public void revokeAccess(DynamoUser caller, Principal subject) throws DatabaseException, DynamoSecurityException
  {
    getRealCommunity().revokeAccess(caller,subject);

  } // end revokeAccess

  /**
   * Tests to see what requirements must be fulfilled by a user to join this community.  Returns values as follows:
   * <UL>
   *   <LI>If the user is not permitted to join the community under any circumstances, this method returns
   *     <CODE>null</CODE>.</LI>
   *   <LI>If the user is already a member of the community, this method returns <CODE>Boolean.FALSE</CODE>.</LI>
   *   <LI>If the user may join the community without any authentication, this method returns
   *     <CODE>Boolean.TRUE</CODE>.</LI>
   *   <LI>Otherwise, the method returns a {@link java.util.Set Set} of
   *     {@link com.silverwrist.dynamo.util.QualifiedNameKey QualifiedNameKey} objects, each of which specifies the
   *     namespace and name of an authenticator which can be used to authenticate the user in order to join this
   *     community.</LI>
   * </UL>
   *
   * @param joiner The user to test atainst the current community.
   * @return See above.
   * @exception com.silverwrist.dynamo.except.DatabaseException If there was an error getting the authenticator
   *            information for this user.
   */
  public Object getJoinRequirement(DynamoUser joiner) throws DatabaseException
  {
    return getRealCommunity().getJoinRequirement(joiner);

  } // end getJoinRequirement

  public boolean join(DynamoUser joiner, String auth_namespace, String auth_name, String source_info,
		      String auth_info) throws DatabaseException, DynamoSecurityException
  {
    return getRealCommunity().join(joiner,auth_namespace,auth_name,source_info,auth_info);

  } // end join

  public boolean join(DynamoUser joiner) throws DatabaseException, DynamoSecurityException
  {
    return this.join(joiner,null,null,null,null);

  } // end join

  public void unjoin(DynamoUser unjoiner) throws DatabaseException, DynamoSecurityException
  {
    getRealCommunity().unjoin(unjoiner);

  } // end unjoin

  public boolean isAdministrator(DynamoUser user)
  {
    return getRealCommunity().isAdministrator(user);

  } // end isAdministrator

  public List getServices() throws DatabaseException
  {
    return getRealCommunity().getServices();

  } // end getServices

  public boolean isUsingService(String namespace, String name) throws DatabaseException
  {
    return getRealCommunity().isUsingService(namespace,name);

  } // end isUsingService

  public void addService(DynamoUser caller, Request req, String namespace, String name)
      throws DatabaseException, DynamoSecurityException, CommunityServiceException
  {
    getRealCommunity().addService(caller,req,namespace,name);

  } // end addService

  public void removeService(DynamoUser caller, Request req, String namespace, String name)
      throws DatabaseException, DynamoSecurityException, CommunityServiceException
  {
    getRealCommunity().removeService(caller,req,namespace,name);

  } // end removeService

  public void setMenuVariables(MenuRenderObject menu) throws DatabaseException
  {
    getRealCommunity().setMenuVariables(menu);

  } // end setMenuVariables

  /*--------------------------------------------------------------------------------
   * Implementations from interface DynamicWrapper
   *--------------------------------------------------------------------------------
   */

  /**
   * Returns a reference to the "real" {@link com.silverwrist.venice.iface.VeniceCommunity VeniceCommunity} object
   * underlying this proxy.
   *
   * @return A reference to the "real" community object.
   */
  public Object unwrap()
  {
    return getRealCommunity();

  } // end unwrap

} // end class CommunityProxy
