/*****************************************************************************************
 * Copyright © 2004 VHA. All rights reserved
 ****************************************************************************************/
package gov.va.med.esr.service.impl;

// Library classes
import org.aopalliance.intercept.MethodInvocation;

// Framework classes
import gov.va.med.fw.cache.AbstractEntityCacheAdvice;

// ESR classes
import gov.va.med.esr.service.PersonIdentityTraits;
import gov.va.med.esr.common.model.person.id.VPIDEntityKey;

/**
 * PSDelegateServiceAdvice created on Oct 17, 2006
 * 
 * @author DNS   LEV
 */
public class PSDelegateServiceAdvice extends AbstractEntityCacheAdvice {

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

   /**
    * A default constructor
    */
   public PSDelegateServiceAdvice() {
      super();
   }

   /** Processes a method invocation. This method checks if a return
    * value should be cloned.  A default implementation is to clone
    * a result value.  To change a default behavior, set an isResultCloned
    * flag to false. The return value is cached in thread-bound storage
    * in an EntityCacheManager class.
    * 
    * @param invocation Information needed to invoke a method
    * @return A result object either cloned or uncloned.
    * @throws Throwable In case of errors in a method invocation
    */
   protected Object processInvocation( MethodInvocation invocation ) throws Throwable {
      
      // Invoke a getIdentityTraits method first. if a return value
      // is of type PersonIdentityTraits, proceed with the cache. 
      // This step is neccessary because there are 3 different getIdentittyTraits()
      // and one of which takes a collection and returns a map. That call is ignored.
      
      Object result = invocation.proceed();
      Object cached = null;
      if( result instanceof PersonIdentityTraits ) {
         cached = cache( clone( result ), invocation );
         result = this.isReturnCachedItem() ? cached : result;
      }
      return result;
   }
   
   /**
    * @see gov.va.med.fw.cache.AbstractEntityCacheAdvice#getCachedKey(java.lang.Object, org.aopalliance.intercept.MethodInvocation)
    */
   protected Object getCachedKey(Object result, MethodInvocation invocation) {
      
      // During the Z07 process, the first call to get identity traits by dfn
      // and station number while all subsequent calls to get identity traits
      // are by VPIDEntityKey.  Since any call to PSIM is espensive, cach the
      // first call to get identity traits by dfn and station number by VPIDEntityKey
      // so that all subsequence calls by VPIDEntityKey will benefit from the cache.
      Object key = super.getCachedKey(result, invocation);
      
      // Check if this is a case of getIdentityTraits( dfn, station# )
      if( key instanceof String && result instanceof PersonIdentityTraits ) {
         key = ((PersonIdentityTraits)result).getVpid();
      }
      return key;
   }

   /**
    * @see gov.va.med.fw.cache.AbstractEntityCacheAdvice#isCached(org.aopalliance.intercept.MethodInvocation)
    */
   protected boolean isCached( MethodInvocation invocation ) {
      boolean isCached = false;
      Object[] arguments = invocation.getArguments();
      if( arguments != null ) {
         
         // Check for getIdentityTraits(VPIDEntityKey)
         if( arguments.length == 1 ) {
            VPIDEntityKey id = (arguments[0] instanceof VPIDEntityKey) ? (VPIDEntityKey)arguments[0] : null;
            isCached = (id != null) ? this.isCached( id ) : false;
         }
         // Check for getIdentityTraits(String dfn, String station)
         else if( arguments.length == 2 ) {
            String dfn = (arguments[0] instanceof String) ? (String)arguments[0] : null;
            String station = (arguments[1] instanceof String) ? (String)arguments[1] : null;
            isCached = (dfn != null && station != null) ? (getCacheManager().getItem( dfn + station ) != null) : false;
         }
      }
      return isCached;
   }

   /**
    * @see gov.va.med.fw.cache.AbstractEntityCacheAdvice#getCachedItem(org.aopalliance.intercept.MethodInvocation)
    */
   protected Object getCachedItem( MethodInvocation invocation ) {
      Object entity = null;
      Object[] arguments = invocation.getArguments();
      if( arguments != null ) {
         // Check for getIdentityTraits(VPIDEntityKey)
         if( arguments.length == 1 ) {
            VPIDEntityKey id = (arguments[0] instanceof VPIDEntityKey) ? (VPIDEntityKey)arguments[0] : null;
            entity = (id != null) ? this.getCachedItem( id ) : null;
         }
         // Check for getIdentityTraits(String dfn, String station)
         else if( arguments.length == 2 ) {
            String dfn = (arguments[0] instanceof String) ? (String)arguments[0] : null;
            String station = (arguments[1] instanceof String) ? (String)arguments[1] : null;
            entity = (dfn != null && station != null) ? getCacheManager().getItem( dfn + station ) : null;
         }
      }
      return entity;
   }
}