/*****************************************************************************************
 * Copyright © 2004 VHA. All rights reserved
 ****************************************************************************************/
package gov.va.med.esr.common.model.security;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang.Validate;
import org.apache.commons.lang.builder.ToStringBuilder;

import gov.va.med.fw.util.DateUtils;
import gov.va.med.fw.model.RolePrincipalImpl;
import gov.va.med.fw.security.UserPrincipal;

import gov.va.med.esr.common.model.lookup.Capability;

/**
 * Implementation of RolePrincipal.
 * 
 * @author Ghazenfer Mansoor
 */
public class ESRRolePrincipalImpl extends RolePrincipalImpl 
   implements ESRRolePrincipal, Comparable {

   /**
    * An instance of serialVersionUID
    */
   private static final long serialVersionUID = 7324046791893823968L;

   private Date activeDate = null;

   private Date inactiveDate = null;

   private Boolean assigned = Boolean.FALSE;

   private Set internalCapabilitySets = null;

   private Set internalCapabilities = null;

   /**
    * Default Constructor
    */
   public ESRRolePrincipalImpl() {
      super();
   }

   /**
    * Construct using role name.
    * 
    * @param name
    */
   public ESRRolePrincipalImpl(String name) {
      super(name);
   }

   public Date getActiveDate() {
      return activeDate;
   }

   public void setActiveDate(Date activeDate) {
      this.activeDate = activeDate;
   }

   public Date getInactiveDate() {
      return inactiveDate;
   }

   public void setInactiveDate(Date inactiveDate) {
      this.inactiveDate = inactiveDate;
   }

   public Boolean getAssigned() {
      return assigned == null ? Boolean.FALSE : assigned;
   }

   public void setAssigned(Boolean assigned) {
      this.assigned = assigned;
   }

   public boolean isActive() {
       return AbstractPermission.isActive(activeDate,inactiveDate);
   }

   public boolean isAssignable() {
       return AbstractPermission.isAssignable(activeDate,inactiveDate);
   }

   public boolean isCapabilityAssigned(Capability capability) {
      return getCapabilities().contains(capability) ? true : false;
   }

   public boolean isCapabilitySetAssigned(CapabilitySet capabilitySet) {
      return getCapabilitySets().contains(capabilitySet) ? true : false;
   }

   public Set getCapabilities() {
      Set capabilities = new HashSet();
      for( Iterator i = getInternalCapabilities().iterator(); i.hasNext(); ) {
         capabilities.add(( (RoleCapability)i.next() ).getCapability());
      }
      return capabilities;
   }

   public List getActiveCapabilities() {
      List capabilities = new ArrayList();
      // check whether the role is active or not

      // Check Active data validity
      if( isActive() ) {
         // add all the capablities from the role
         capabilities.addAll(getCapabilities());

         // Add the capabilities from the active capability sets
         for( Iterator i = getCapabilitySets().iterator(); i.hasNext(); ) {
            capabilities.addAll(( (CapabilitySet)i.next() ).getActiveCapabilities());
         }
      }
      return capabilities;
   }

   public Set getCapabilitySets() {
      Set capabilitySets = new HashSet();

      // Add Capabilities from Sets
      for( Iterator i = getInternalCapabilitySets().iterator(); i.hasNext(); ) {
         capabilitySets.add(( (RoleCapabilitySet)i.next() ).getCapabilitySet());
      }
      return capabilitySets;
   }

   public Set getRoleCapabilities() {
      return Collections.unmodifiableSet(getInternalCapabilities());
   }

   public void addCapability(Capability capability) {
      if( findRoleCapability(capability) == null ) {
         RoleCapability roleCapability = new RoleCapability(this, capability);
         getInternalCapabilities().add(roleCapability);
      }
   }

   public void removeCapability(RoleCapability roleCapability) {
      getInternalCapabilities().remove(roleCapability);
   }

   public void removeCapability(Capability capability) {
      RoleCapability roleCapability = findRoleCapability(capability);
      if( roleCapability != null ) {
         getInternalCapabilities().remove(roleCapability);
      }
   }

   public Set getRoleCapabilitySets() {
      return Collections.unmodifiableSet(getInternalCapabilitySets());
   }

   public void addCapabilitySet(CapabilitySet capabilitySet) {
      if( findRoleCapabilitySet(capabilitySet) == null ) {
         RoleCapabilitySet roleCapabilitySet = new RoleCapabilitySet(this, capabilitySet);
         getInternalCapabilitySets().add(roleCapabilitySet);
      }
   }

   public void removeCapabilitySet(CapabilitySet capabilitySet) {
      RoleCapabilitySet roleCapabilitySet = findRoleCapabilitySet(capabilitySet);
      if( roleCapabilitySet != null ) {
         getInternalCapabilitySets().remove(roleCapabilitySet);
      }
   }

   public RoleCapability findRoleCapability(Capability capability) {
      for( Iterator iter = getInternalCapabilities().iterator(); iter.hasNext(); ) {
         RoleCapability roleCapability = (RoleCapability)iter.next();
         if( capability.equals(roleCapability.getCapability()) ) {
            return roleCapability;
         }
      }
      return null;
   }

   public int compareTo(Object o) {
      if( o != null && o instanceof ESRRolePrincipalImpl )
         return getName().compareTo(( (ESRRolePrincipalImpl)o ).getName());
      else
         return 1;
   }

   private RoleCapabilitySet findRoleCapabilitySet(CapabilitySet capabilitySet) {
      for( Iterator iter = getInternalCapabilitySets().iterator(); iter.hasNext(); ) {
         RoleCapabilitySet roleCapabilitySet = (RoleCapabilitySet)iter.next();

         // compare only ids
         if( capabilitySet.getEntityKey().getKeyValueAsString().equals(
               roleCapabilitySet.getCapabilitySet().getEntityKey().getKeyValueAsString()) ) {
            return roleCapabilitySet;
         }
      }
      return null;
   }

   /*
    * (non-Javadoc)
    * 
    * @see com.vha.fw.model.AbstractEntity#buildToString()
    */
   protected void buildToString(ToStringBuilder builder) {
      super.buildToString(builder);
   }

   private Set getInternalCapabilities() {
      if( internalCapabilities == null )
         internalCapabilities = new HashSet();
      return internalCapabilities;
   }

   private void setInternalCapabilities(Set internalCapabilities) {
      this.internalCapabilities = internalCapabilities;
   }

   private Set getInternalCapabilitySets() {
      if( internalCapabilitySets == null )
         internalCapabilitySets = new HashSet();
      return internalCapabilitySets;
   }

   private void setInternalCapabilitySets(Set internalCapabilitySets) {
      this.internalCapabilitySets = internalCapabilitySets;
   }

   // ///////////////////the following methods may be removed////////////////
   // //////////////////////////////////////////////////////////////////////
   private Set getInternalRoleUsers() {
      /*
       * if (internalRoleUsers == null) { this.internalRoleUsers = new HashSet(); } return
       * internalRoleUsers;
       */
      return null;
   }

   private void setInternalRoleUsers(Set internalRoleUsers) {
      // this.internalRoleUsers = internalRoleUsers;
   }

   /*
    * (non-Javadoc)
    * 
    * @see gov.va.med.fw.security.RolePrincipal#getRoleUsers()
    */
   public Set getRoleUsers() {
      Set users = new HashSet();
      Set set = getInternalRoleUsers();
      if (set != null && set.size() > 0) {
	      for( Iterator iter = set.iterator(); iter.hasNext(); ) {
	         UserRole userRole = (UserRole)iter.next();
	         UserPrincipal userPrincipal = userRole.getUserPrincipal();
	         if( userPrincipal != null ) {
	            users.add(userPrincipal);
	         }
	      }
      }
      return Collections.unmodifiableSet(users);
   }

   /**
    * Helper method to add a given UserPrincipal to this role.
    * 
    * @param user -
    *           a UserPrincipal
    */
   public void addRoleUser(UserPrincipal userPrincipal) {
      Validate.notNull(userPrincipal, "Can not add null UserPrincipal");
      Set set = getInternalRoleUsers();
      if (set != null) {
	      if(findUserRole(userPrincipal) == null ) {
	         UserRole userRole = new UserRole(userPrincipal, this);
	         set.add(userRole);
	      }
      }
   }

   /**
    * Helper method to remove UserPrincipal.
    * 
    * @param rolePrincipal
    */
   public void removeRoleUser(UserPrincipal userPrincipal) {
      Validate.notNull(userPrincipal, "Can not remove null UserPrincipal");
      UserRole userRoleToDelete = findUserRole(userPrincipal);
      Set set = getInternalRoleUsers();
      if( set != null && set.size() > 0 && userRoleToDelete != null ) {
         set.remove(userRoleToDelete);
      }
   }

   /**
    * Find a UserRole from a collection that have given UserPrincipal.
    * 
    * @param userPrincipal
    * @return UserRole
    */
   private UserRole findUserRole(UserPrincipal userPrincipal) {
	  Set set = getInternalRoleUsers();
	  
	  if (set != null && set.size() > 0) {
	      for( Iterator iter = set.iterator(); iter.hasNext(); ) {
	         UserRole userRole = (UserRole)iter.next();
	         if( userPrincipal.equals(userRole.getUserPrincipal()) ) {
	            return userRole;
	         }
	      }
	  }
      return null;
   }

   protected void finalize() throws Throwable {
      super.finalize();
      setInternalCapabilities( null );
      setInternalCapabilitySets( null );
      setInternalRoleUsers( null );
   }
}