/*
 * 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.util;

import java.security.Principal;
import java.security.acl.*;
import java.util.*;
import org.apache.log4j.Logger;
import com.silverwrist.dynamo.Namespaces;
import com.silverwrist.dynamo.except.*;
import com.silverwrist.dynamo.iface.*;
import com.silverwrist.dynamo.security.SecurityReferenceMonitor;

public class AclEditHelper
{
  /*--------------------------------------------------------------------------------
   * Attributes
   *--------------------------------------------------------------------------------
   */

  private SecurityReferenceMonitor m_srm;

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

  public AclEditHelper(ServiceProvider services, String srm_name)
  {
    ObjectProvider op = (ObjectProvider)(services.queryService(ObjectProvider.class));
    Object tmp = op.getObject(Namespaces.DYNAMO_OBJECT_NAMESPACE,srm_name);
    if (tmp instanceof SecurityReferenceMonitor)
      m_srm = (SecurityReferenceMonitor)tmp;
    else if (tmp instanceof ServiceProvider)
      m_srm = (SecurityReferenceMonitor)(((ServiceProvider)tmp).queryService(SecurityReferenceMonitor.class));

  } // end AclEditHelper

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

  public SecurityReferenceMonitor getSRM()
  {
    return m_srm;

  } // end getSRM

  public void insertAce(DynamoUser caller, DynamoAcl acl, DynamoAce ace) throws DatabaseException, NotOwnerException
  {
    // Locate the place to insert this ACE into the ACL.
    int acecount = acl.getAceCount();
    int ipoint = 0;
    if (ace.isNegative())
    { // negative ACEs get inserted before positive ACEs
      if (ace.isGroupAce())
      { // skip all user ACEs, insert before group ACEs (or before positive ACEs)
	DynamoAce tmp = acl.getAce(caller,ipoint);
	while ((ipoint<acecount) && tmp.isNegative() && !(tmp.isGroupAce()))
	  tmp = acl.getAce(caller,++ipoint);

      } // end if
      // else this ACE gets inserted at the front anyway

    } // end if
    else
    { // a positive ACE - skip over the negative ACEs and insert 
      DynamoAce tmp = acl.getAce(caller,ipoint);
      while ((ipoint<acecount) && (tmp.isNegative()))
	tmp = acl.getAce(caller,++ipoint);
      if ((ipoint<acecount) && ace.isGroupAce())
      { // skip all user ACEs, insert before group ACEs
	while ((ipoint<acecount) && !(tmp.isGroupAce()))
	  tmp = acl.getAce(caller,++ipoint);

      } // end if
      // else it's a positive user ACE - we're there

    } // end else

    // Perform the insert!
    acl.insertEntry(caller,ace,ipoint);

  } // end insertAce

  public void addPermission(DynamoUser caller, DynamoAcl acl, Principal subject, boolean negative, String namespace,
			    String name) throws DatabaseException, NotOwnerException
  {
    DynamoAce ace = acl.getMatchingAce(caller,subject,negative);
    if (ace==null)
    { // Create a new ACE.
      ace = m_srm.createAce();
      ace.setPrincipal(subject);
      if (negative)
	ace.setNegativePermissions();

      // insert the ACE into the ACL
      this.insertAce(caller,acl,ace);

    } // end if

    // Now add the permission to the ACE.
    ace.addPermission(namespace,name);

  } // end addPermission

  public void removePermission(DynamoUser caller, DynamoAcl acl, Principal subject, boolean negative, String namespace,
			       String name) throws DatabaseException, NotOwnerException
  {
    DynamoAce ace = acl.getMatchingAce(caller,subject,negative);
    if (ace!=null)
    { // remove the permission
      ace.removePermission(namespace,name);
      if (ace.getNumPermissions()==0)
	acl.removeEntry(caller,ace);  // ACE is now empty - remove it

    } // end if

  } // end removePermission

  public void stripPermission(DynamoUser caller, DynamoAcl acl, String namespace, String name)
      throws DatabaseException, NotOwnerException
  {
    int acecount = acl.getAceCount();
    LinkedList null_aces = new LinkedList();
    for (int i=0; i<acecount; i++)
    { // remove permission from each ACE in the ACL
      DynamoAce ace = acl.getAce(caller,i);
      ace.removePermission(namespace,name);
      if (ace.getNumPermissions()==0)
	null_aces.addLast(ace);

    } // end for

    while (null_aces.size()>0)
    { // zap the ACEs that are now empty
      DynamoAce ace = (DynamoAce)(null_aces.removeFirst());
      acl.removeEntry(caller,ace);

    } // end while

  } // end stripPermission

} // end class AclEditHelper
